From f67885de7f10fd2e1ebf8824cc0a734ef837ade5 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 9 Jun 2025 17:41:43 -0400 Subject: [PATCH] feat(Python): Implement `__geo_interface__` for GeoArrowArray --- Cargo.lock | 1 + rust/pyo3-geoarrow/Cargo.toml | 4 +++ rust/pyo3-geoarrow/src/array.rs | 54 +++++++++++++++++++++------------ 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7faa3e0b7..aeefbf576 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2852,6 +2852,7 @@ dependencies = [ "geoarrow-array", "geoarrow-cast", "geoarrow-schema", + "geozero", "pyo3", "pyo3-arrow", "serde_json", diff --git a/rust/pyo3-geoarrow/Cargo.toml b/rust/pyo3-geoarrow/Cargo.toml index 4e921ef25..9a2c19d1b 100644 --- a/rust/pyo3-geoarrow/Cargo.toml +++ b/rust/pyo3-geoarrow/Cargo.toml @@ -11,6 +11,9 @@ keywords = ["python", "arrow"] categories = [] rust-version = { workspace = true } +[features] +geozero = ["dep:geozero", "geoarrow-array/geozero"] + [dependencies] arrow-array = { workspace = true } arrow-cast = { workspace = true } @@ -19,6 +22,7 @@ arrow-schema = { workspace = true } geoarrow-array = { workspace = true } geoarrow-cast = { workspace = true } geoarrow-schema = { workspace = true } +geozero = { workspace = true, optional = true } pyo3 = { workspace = true, features = ["chrono", "indexmap"] } pyo3-arrow = { workspace = true } serde_json = { workspace = true } diff --git a/rust/pyo3-geoarrow/src/array.rs b/rust/pyo3-geoarrow/src/array.rs index e277d8b4c..bbc05cda6 100644 --- a/rust/pyo3-geoarrow/src/array.rs +++ b/rust/pyo3-geoarrow/src/array.rs @@ -1,18 +1,13 @@ use std::sync::Arc; -// use geoarrow::ArrayBase; -// use geoarrow::NativeArray; -// use geoarrow::error::GeoArrowError; -// use geoarrow::scalar::GeometryScalar; -// use geoarrow::trait_::NativeArrayRef; use geoarrow_array::GeoArrowArray; use geoarrow_array::array::from_arrow_array; use geoarrow_cast::downcast::NativeType; +use geoarrow_schema::GeoArrowType; use geoarrow_schema::{ BoxType, GeometryCollectionType, LineStringType, MultiLineStringType, MultiPointType, MultiPolygonType, PointType, PolygonType, }; -// use geozero::ProcessToJson; use pyo3::intern; use pyo3::prelude::*; use pyo3::types::{PyCapsule, PyTuple, PyType}; @@ -91,23 +86,42 @@ impl PyGeoArrowArray { } } - // #[getter] - // fn __geo_interface__<'py>(&'py self, py: Python<'py>) -> PyGeoArrowResult> { - // // Note: We create a Table out of this array so that each row can be its own Feature in a - // // FeatureCollection + #[cfg(feature = "geozero")] + #[getter] + fn __geo_interface__<'py>(&'py self, py: Python<'py>) -> PyGeoArrowResult> { + // Note: We create a Table out of this array so that each row can be its own Feature in a + // FeatureCollection + + // use + + use GeoArrowType::*; + use geoarrow_array::cast::AsGeoArrowArray; + match self.0.data_type() { + GeoArrowType::Point(_) => { + use geoarrow_array::GeoArrowArrayAccessor; + + let x = self.0.as_point(); + for geom in x.iter_values() { + use geozero::ToJson; + + let geom = geom.unwrap(); + let json = geom.to_json().unwrap(); + } + } + } - // let field = self.0.extension_field(); - // let geometry = self.0.to_array_ref(); - // let schema = Arc::new(Schema::new(vec![field])); - // let batch = RecordBatch::try_new(schema.clone(), vec![geometry])?; + let field = self.0.extension_field(); + let geometry = self.0.to_array_ref(); + let schema = Arc::new(Schema::new(vec![field])); + let batch = RecordBatch::try_new(schema.clone(), vec![geometry])?; - // let mut table = geoarrow::table::Table::try_new(vec![batch], schema)?; - // let json_string = table.to_json().map_err(GeoArrowError::GeozeroError)?; + let mut table = geoarrow::table::Table::try_new(vec![batch], schema)?; + let json_string = table.to_json().map_err(GeoArrowError::GeozeroError)?; - // let json_mod = py.import(intern!(py, "json"))?; - // let args = (json_string,); - // Ok(json_mod.call_method1(intern!(py, "loads"), args)?) - // } + let json_mod = py.import(intern!(py, "json"))?; + let args = (json_string,); + Ok(json_mod.call_method1(intern!(py, "loads"), args)?) + } // fn __getitem__(&self, i: isize) -> PyGeoArrowResult> { // // Handle negative indexes from the end