This is an automated email from the ASF dual-hosted git repository.
paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sedona-db.git
The following commit(s) were added to refs/heads/main by this push:
new 8c837de9 feat(python/sedonadb): Handle crs-like objects in
parameterized queries (#660)
8c837de9 is described below
commit 8c837de94ac551b536768c1588c0e8ea57241c17
Author: Dewey Dunnington <[email protected]>
AuthorDate: Thu Feb 26 08:49:56 2026 -0600
feat(python/sedonadb): Handle crs-like objects in parameterized queries
(#660)
---
python/sedonadb/python/sedonadb/expr/literal.py | 10 +++++++++-
python/sedonadb/tests/expr/test_literal.py | 21 +++++++++++++++++++++
2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/python/sedonadb/python/sedonadb/expr/literal.py
b/python/sedonadb/python/sedonadb/expr/literal.py
index cbde54d8..b65960a1 100644
--- a/python/sedonadb/python/sedonadb/expr/literal.py
+++ b/python/sedonadb/python/sedonadb/expr/literal.py
@@ -71,7 +71,8 @@ def lit(value: Any) -> Literal:
- SedonaDB DataFrame objects that evaluate to a single column and
row become a scalar value according to the single represented
value.
-
+ - pyproj CRS objects become PROJJSON strings (e.g., so they may be used
+ in `ST_SetCRS()`, `ST_Point()`, or `ST_GeomFromWKT()`).
"""
if isinstance(value, Literal):
return value
@@ -155,11 +156,17 @@ def _lit_from_wkb_and_crs(wkb, crs):
return type.wrap_array(storage)
+def _lit_from_crs(crs):
+ return _resolve_arrow_lit(crs.to_json())
+
+
def _qualified_type_name(obj):
return f"{type(obj).__module__}.{type(obj).__name__}"
SPECIAL_CASED_LITERALS = {
+ "geoarrow.types.crs.ProjJsonCrs": _lit_from_crs,
+ "geoarrow.types.crs.StringCrs": _lit_from_crs,
"geopandas.geodataframe.GeoDataFrame": _lit_from_dataframe,
"geopandas.geoseries.GeoSeries": _lit_from_series,
# pandas < 3.0
@@ -168,6 +175,7 @@ SPECIAL_CASED_LITERALS = {
# pandas >= 3.0
"pandas.DataFrame": _lit_from_dataframe,
"pandas.Series": _lit_from_series,
+ "pyproj.crs.crs.CRS": _lit_from_crs,
"sedonadb.dataframe.DataFrame": _lit_from_sedonadb,
"shapely.geometry.point.Point": _lit_from_shapely,
"shapely.geometry.linestring.LineString": _lit_from_shapely,
diff --git a/python/sedonadb/tests/expr/test_literal.py
b/python/sedonadb/tests/expr/test_literal.py
index b1941131..51f0957f 100644
--- a/python/sedonadb/tests/expr/test_literal.py
+++ b/python/sedonadb/tests/expr/test_literal.py
@@ -149,3 +149,24 @@ def test_sedonadb_literal(con):
with pytest.raises(ValueError, match="size != 1 row"):
df = con.sql("SELECT 1 as one WHERE false")
pa.array(lit(df))
+
+
+def test_crs_literal():
+ import pyproj
+
+ crs = pyproj.CRS("EPSG:26920")
+ assert pa.array(lit(crs)) == pa.array([crs.to_json()])
+
+ # Ensure this is also the case for whatever GeoSeries.crs returns
+ geoseries = geopandas.GeoSeries.from_wkt(["POINT (0 1)"], crs="EPSG:26920")
+ assert pa.array(lit(geoseries.crs)) == pa.array([crs.to_json()])
+
+ # Make sure geoarrow.pyarrow CRSes also work here
+
+ # A ProjjsonCrs
+ ga_crs = ga.wkb().with_crs(crs).crs
+ assert pa.array(lit(ga_crs)) == pa.array([crs.to_json()])
+
+ # A StringCrs
+ ga_crs = ga.wkb().with_crs("EPSG:26920").crs
+ assert pa.array(lit(ga_crs)) == pa.array([crs.to_json()])