Skip to content

Commit b19a8ce

Browse files
ncclementigforsyth
authored andcommitted
feat(duckdb): add read_geo function
1 parent 65f496c commit b19a8ce

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

ibis/backends/duckdb/__init__.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,49 @@ def read_csv(
493493
con.exec_driver_sql(view)
494494
return self.table(table_name)
495495

496+
def read_geo(
497+
self,
498+
source: str,
499+
table_name: str | None = None,
500+
**kwargs: Any,
501+
) -> ir.Table:
502+
"""Register a GEO file as a table in the current database.
503+
504+
Parameters
505+
----------
506+
source
507+
The data source(s). Path to a file of geospatial files supported
508+
by duckdb.
509+
See https://duckdb.org/docs/extensions/spatial.html#st_read---read-spatial-data-from-files
510+
table_name
511+
An optional name to use for the created table. This defaults to
512+
a sequentially generated name.
513+
**kwargs
514+
Additional keyword arguments passed to DuckDB loading function.
515+
See https://duckdb.org/docs/extensions/spatial.html#st_read---read-spatial-data-from-files
516+
for more information.
517+
518+
Returns
519+
-------
520+
ir.Table
521+
The just-registered table
522+
"""
523+
524+
if not table_name:
525+
table_name = util.gen_name("read_geo")
526+
527+
# load geospatial extension
528+
self.load_extension("spatial")
529+
530+
source_expr = sa.select(sa.literal_column("*")).select_from(
531+
sa.func.st_read(util.normalize_filename(source), _format_kwargs(kwargs))
532+
)
533+
534+
view = self._compile_temp_view(table_name, source_expr)
535+
with self.begin() as con:
536+
con.exec_driver_sql(view)
537+
return self.table(table_name)
538+
496539
def read_parquet(
497540
self,
498541
source_list: str | Iterable[str],

ibis/backends/duckdb/tests/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ def con(data_dir, tmp_path_factory, worker_id):
8181
return TestConf.load_data(data_dir, tmp_path_factory, worker_id).connection
8282

8383

84+
@pytest.fixture(scope="session")
85+
def zones(con, data_dir):
86+
# pending merge https://github.com/ibis-project/testing-data/pull/5
87+
zones = con.read_geo(data_dir / "geojson" / "zones.geojson")
88+
return zones
89+
90+
8491
@pytest.fixture(scope="session")
8592
def zones_gdf(data_dir):
8693
# pending merge https://github.com/ibis-project/testing-data/pull/5

ibis/backends/duckdb/tests/test_register.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ def test_read_parquet(data_dir):
4646
assert t.count().execute()
4747

4848

49+
@pytest.mark.xfail(raises=duckdb.duckdb.CatalogException, reason="ST_AsEWKB")
50+
def test_read_geo_fail(con, data_dir):
51+
t = con.read_geo(data_dir / "geojson" / "zones.geojson")
52+
# can't convert geometry to arrow type yet
53+
assert t.head().to_pyarrow()
54+
55+
56+
def test_read_geo(con, data_dir):
57+
t = con.read_geo(data_dir / "geojson" / "zones.geojson")
58+
assert t.count().execute()
59+
60+
4961
@pytest.mark.xfail_version(
5062
duckdb=["duckdb<0.7.0"], reason="read_json_auto doesn't exist", raises=exc.IbisError
5163
)

0 commit comments

Comments
 (0)