Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ jobs:

- name: Install wheel and test dependencies
shell: bash
run: pip install --find-links target/wheels/ ggsql[test]
run: |
WHEEL=$(ls target/wheels/ggsql-*.whl)
pip install "${WHEEL}[test]"

- name: Run tests
shell: bash
Expand Down
4 changes: 3 additions & 1 deletion ggsql-python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ dependencies = [
]

[project.optional-dependencies]
test = ["pytest>=7.0"]
test = ["pytest>=7.0", "duckdb>=1.0", "pyarrow>=14.0"]
dev = ["maturin>=1.4"]

[tool.maturin]
Expand All @@ -31,6 +31,8 @@ module-name = "ggsql._ggsql"

[dependency-groups]
dev = [
"duckdb>=1.0",
"maturin>=1.11.5",
"pyarrow>=14.0",
"pytest>=9.0.2",
]
48 changes: 31 additions & 17 deletions ggsql-python/tests/test_ggsql.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import json

import duckdb
import pytest
import polars as pl
import altair
Expand Down Expand Up @@ -399,8 +400,16 @@ def test_simple_custom_reader(self):
"""Custom reader with execute_sql() method works."""

class SimpleReader:
def __init__(self):
self.conn = duckdb.connect()
self.conn.execute(
"CREATE TABLE data AS SELECT * FROM ("
"VALUES (1, 10), (2, 20), (3, 30)"
") AS t(x, y)"
)

def execute_sql(self, sql: str) -> pl.DataFrame:
return pl.DataFrame({"x": [1, 2, 3], "y": [10, 20, 30]})
return self.conn.execute(sql).pl()

reader = SimpleReader()
spec = ggsql.execute("SELECT * FROM data VISUALISE x, y DRAW point", reader)
Expand All @@ -411,19 +420,16 @@ def test_custom_reader_with_register(self):

class RegisterReader:
def __init__(self):
self.tables = {}
self.conn = duckdb.connect()

def execute_sql(self, sql: str) -> pl.DataFrame:
# Simple: just return the first registered table
if self.tables:
return next(iter(self.tables.values()))
return pl.DataFrame({"x": [1], "y": [2]})
return self.conn.execute(sql).pl()

def supports_register(self) -> bool:
return True

def register(self, name: str, df: pl.DataFrame) -> None:
self.tables[name] = df
self.conn.register(name, df)

reader = RegisterReader()
spec = ggsql.execute("SELECT 1 AS x, 2 AS y VISUALISE x, y DRAW point", reader)
Expand Down Expand Up @@ -460,17 +466,20 @@ def test_native_reader_fast_path(self):
def test_custom_reader_can_render(self):
"""Custom reader result can be rendered to Vega-Lite."""

class StaticReader:
def execute_sql(self, sql: str) -> pl.DataFrame:
return pl.DataFrame(
{
"x": [1, 2, 3, 4, 5],
"y": [10, 40, 20, 50, 30],
"category": ["A", "B", "A", "B", "A"],
}
class DuckDBBackedReader:
def __init__(self):
self.conn = duckdb.connect()
self.conn.execute(
"CREATE TABLE data AS SELECT * FROM ("
"VALUES (1, 10, 'A'), (2, 40, 'B'), (3, 20, 'A'), "
"(4, 50, 'B'), (5, 30, 'A')"
") AS t(x, y, category)"
)

reader = StaticReader()
def execute_sql(self, sql: str) -> pl.DataFrame:
return self.conn.execute(sql).pl()

reader = DuckDBBackedReader()
spec = ggsql.execute(
"SELECT * FROM data VISUALISE x, y, category AS color DRAW point",
reader,
Expand All @@ -488,11 +497,16 @@ def test_custom_reader_execute_sql_called(self):

class RecordingReader:
def __init__(self):
self.conn = duckdb.connect()
self.conn.execute(
"CREATE TABLE data AS SELECT * FROM ("
"VALUES (1, 2)) AS t(x, y)"
)
self.execute_calls = []

def execute_sql(self, sql: str) -> pl.DataFrame:
self.execute_calls.append(sql)
return pl.DataFrame({"x": [1], "y": [2]})
return self.conn.execute(sql).pl()

reader = RecordingReader()
ggsql.execute(
Expand Down