Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove pyarrow required dependency #64

Merged
merged 30 commits into from
Nov 15, 2024
Merged
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
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
7 changes: 2 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
[workspace]
resolver = "2"

members = [
"h3ronpy",
"crates/h3arrow"
]
members = ["h3ronpy", "crates/h3arrow"]

[workspace.dependencies]
geo = "0.28"
geo-types = "0.7"
h3o = { version = "0.6" }
rayon = "^1"
arrow = { version = "52" }
arrow = { version = "53" }

[profile.release]
lto = "thin"
7 changes: 5 additions & 2 deletions crates/h3arrow/Cargo.toml
Original file line number Diff line number Diff line change
@@ -21,10 +21,13 @@ spatial_index = ["dep:rstar"]
[dependencies]
ahash = "0.8"
arrow = { workspace = true }
geoarrow = { version = "0.3", optional = true, features = ["geozero"] }
geoarrow = { version = "0.4.0-beta.1", optional = true, features = ["geozero"] }
geo-types = { workspace = true }
geo = { workspace = true }
geozero = { version = "^0.13", default-features = false, features = ["with-geo", "with-wkb"], optional = true }
geozero = { version = "^0.14", default-features = false, features = [
"with-geo",
"with-wkb",
], optional = true }
h3o = { workspace = true, features = ["geo"] }
nom = "7"
rayon = { workspace = true, optional = true }
10 changes: 4 additions & 6 deletions crates/h3arrow/src/algorithm/string.rs
Original file line number Diff line number Diff line change
@@ -246,15 +246,13 @@ mod test {

#[test]
fn parse_utf8_array_cells_invalid_fail() {
let stringarray =
GenericStringArray::<i32>::from_iter(vec![Some("invalid".to_string())].into_iter());
let stringarray = GenericStringArray::<i32>::from_iter(vec![Some("invalid".to_string())]);
assert!(CellIndexArray::parse_genericstringarray(&stringarray, false).is_err());
}

#[test]
fn parse_utf8_array_cells_invalid_to_invalid() {
let utf8_array =
GenericStringArray::<i32>::from_iter(vec![Some("invalid".to_string())].into_iter());
let utf8_array = GenericStringArray::<i32>::from_iter(vec![Some("invalid".to_string())]);
let cell_array = CellIndexArray::parse_genericstringarray(&utf8_array, true).unwrap();
assert_eq!(1, cell_array.len());
assert!(cell_array.iter().all(|v| v.is_none()))
@@ -268,9 +266,9 @@ mod test {
let stringarray: GenericStringArray<i64> = cellindexarray.to_genericstringarray().unwrap();

assert_eq!(cellindexarray.len(), stringarray.len());
assert_eq!(stringarray.is_valid(0), true);
assert!(stringarray.is_valid(0));
assert_eq!(stringarray.value(0), "89283080ddbffff");
assert_eq!(stringarray.is_valid(1), false);
assert!(!stringarray.is_valid(1));
}

#[test]
34 changes: 7 additions & 27 deletions crates/h3arrow/src/array/from_geoarrow.rs
Original file line number Diff line number Diff line change
@@ -9,33 +9,13 @@ use crate::error::Error;
use arrow::array::OffsetSizeTrait;
use geo_types::Geometry;
use geoarrow::array::WKBArray;
use geoarrow::trait_::GeometryArrayAccessor;
use geoarrow::GeometryArrayTrait;
use geoarrow::trait_::ArrayAccessor;
use geoarrow::ArrayBase;
use h3o::CellIndex;
#[cfg(feature = "rayon")]
use rayon::prelude::{IntoParallelIterator, ParallelIterator};

macro_rules! impl_to_cells {
($array_type:ty, $offset:tt) => {
impl<$offset: OffsetSizeTrait> ToCellListArray<$offset> for $array_type {
fn to_celllistarray(
&self,
options: &ToCellsOptions,
) -> Result<H3ListArray<CellIndex, $offset>, Error> {
self.iter_geo()
.map(|v| v.map(Geometry::from))
.to_celllistarray(options)
}
}

impl<$offset: OffsetSizeTrait> ToCellIndexArray for $array_type {
fn to_cellindexarray(&self, options: &ToCellsOptions) -> Result<CellIndexArray, Error> {
self.iter_geo()
.map(|v| v.map(Geometry::from))
.to_cellindexarray(options)
}
}
};
($array_type:ty) => {
impl<O: OffsetSizeTrait> ToCellListArray<O> for $array_type {
fn to_celllistarray(
@@ -58,12 +38,12 @@ macro_rules! impl_to_cells {
};
}

impl_to_cells!(geoarrow::array::LineStringArray<O, 2>, O);
impl_to_cells!(geoarrow::array::MultiLineStringArray<O, 2>, O);
impl_to_cells!(geoarrow::array::MultiPointArray<O, 2>, O);
impl_to_cells!(geoarrow::array::MultiPolygonArray<O, 2>, O);
impl_to_cells!(geoarrow::array::LineStringArray<2>);
impl_to_cells!(geoarrow::array::MultiLineStringArray<2>);
impl_to_cells!(geoarrow::array::MultiPointArray<2>);
impl_to_cells!(geoarrow::array::MultiPolygonArray<2>);
impl_to_cells!(geoarrow::array::PointArray<2>);
impl_to_cells!(geoarrow::array::PolygonArray<O, 2>, O);
impl_to_cells!(geoarrow::array::PolygonArray<2>);

impl<O: OffsetSizeTrait> ToCellListArray<O> for WKBArray<O> {
fn to_celllistarray(
8 changes: 4 additions & 4 deletions crates/h3arrow/src/array/to_geoarrow.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ pub trait ToGeoArrowPolygons {
fn to_geoarrow_polygons<O: OffsetSizeTrait>(
&self,
use_degrees: bool,
) -> Result<PolygonArray<O, 2>, Self::Error>;
) -> Result<PolygonArray<2>, Self::Error>;
}

impl<T> ToGeoArrowPolygons for T
@@ -26,7 +26,7 @@ where
fn to_geoarrow_polygons<O: OffsetSizeTrait>(
&self,
use_degrees: bool,
) -> Result<PolygonArray<O, 2>, Self::Error> {
) -> Result<PolygonArray<2>, Self::Error> {
Ok(self.to_polygons(use_degrees)?.into())
}
}
@@ -51,7 +51,7 @@ pub trait ToGeoArrowLineStrings {
fn to_geoarrow_lines<O: OffsetSizeTrait>(
&self,
use_degrees: bool,
) -> Result<LineStringArray<O, 2>, Self::Error>;
) -> Result<LineStringArray<2>, Self::Error>;
}

impl<T> ToGeoArrowLineStrings for T
@@ -62,7 +62,7 @@ where
fn to_geoarrow_lines<O: OffsetSizeTrait>(
&self,
use_degrees: bool,
) -> Result<LineStringArray<O, 2>, Self::Error> {
) -> Result<LineStringArray<2>, Self::Error> {
Ok(self.to_linestrings(use_degrees)?.into())
}
}
1 change: 1 addition & 0 deletions crates/h3arrow/src/array/validity.rs
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ use arrow::array::UInt64Array;
/// Conversion corresponding to `From` with the difference that the validity mask
/// is set accordingly to the validity to the contained values.
pub trait FromWithValidity<T> {
#[allow(dead_code)]
fn from_with_validity(value: T) -> Self;
}

12 changes: 6 additions & 6 deletions crates/h3arrow/src/spatial_index.rs
Original file line number Diff line number Diff line change
@@ -212,13 +212,13 @@ mod tests {
assert_eq!(mask.len(), 4);

assert!(mask.is_valid(0));
assert_eq!(mask.value(0), false);
assert!(!mask.value(0));

assert!(mask.is_valid(1));
assert_eq!(mask.value(1), true);
assert!(mask.value(1));

assert!(mask.is_valid(2));
assert_eq!(mask.value(2), false);
assert!(!mask.value(2));

assert!(!mask.is_valid(3));
}
@@ -237,13 +237,13 @@ mod tests {
assert_eq!(mask.len(), 4);

assert!(mask.is_valid(0));
assert_eq!(mask.value(0), true);
assert!(mask.value(0));

assert!(mask.is_valid(1));
assert_eq!(mask.value(1), false);
assert!(!mask.value(1));

assert!(mask.is_valid(2));
assert_eq!(mask.value(2), false);
assert!(!mask.value(2));

assert!(!mask.is_valid(3));
}
10 changes: 8 additions & 2 deletions h3ronpy/Cargo.toml
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ name = "h3ronpy"
crate-type = ["cdylib"]

[dependencies]
arrow = { workspace = true, features = ["pyarrow"] }
arrow = { workspace = true }
env_logger = "^0.11"
geo-types = { workspace = true }
geo = { workspace = true }
@@ -25,6 +25,12 @@ ndarray = { version = "0.15", features = ["rayon"] }
numpy = "0.21"
ordered-float = ">=2.0.1"
py_geo_interface = { version = "0.8", features = ["f64", "wkb"] }
pyo3 = { version = "^0.21", features = ["extension-module", "abi3", "abi3-py39"] }
pyo3 = { version = "^0.21", features = [
"extension-module",
# "abi3",
# "abi3-py39",
] }
# Note(kyle) I have a bug with setting default-features = false, so we keep default-features on and turn off abi3
pyo3-arrow = { version = "0.4.0", default-features = true }
rasterh3 = { version = "^0.8", features = ["rayon"] }
rayon = { workspace = true }
31 changes: 7 additions & 24 deletions h3ronpy/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
[build-system]
requires = [
"maturin>=1.7",
]
requires = ["maturin>=1.7"]
build-backend = "maturin"

[tool.pytest.ini_options]
minversion = "6.0"
addopts = "--doctest-modules -v -s"
testpaths = [
"tests"
]
testpaths = ["tests"]

[tool.ruff]
# Never enforce `E501` (line length violations).
@@ -19,10 +15,7 @@ ignore = ["E501"]
name = "h3ronpy"
readme = "../README.rst"

dependencies = [
"numpy<2",
"pyarrow>=17.0"
]
dependencies = ["numpy<2", "arro3-core>=0.4"]
classifiers = [
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering :: GIS",
@@ -31,20 +24,10 @@ classifiers = [


[project.optional-dependencies]
polars = [
"polars>=1"
]
pandas = [
"geopandas>=1"
]
test = [
"rasterio",
"Shapely>=1.7",
"pytest>=6",
"h3>=3.7",
"pytest-benchmark"
]
polars = ["polars>=1"]
pandas = ["geopandas>=1"]
test = ["rasterio", "Shapely>=1.7", "pytest>=6", "h3>=3.7", "pytest-benchmark"]

[tool.maturin]
python-source = "python"
module-name = "h3ronpy.h3ronpyrs"
module-name = "h3ronpy.h3ronpyrs"
116 changes: 116 additions & 0 deletions h3ronpy/src/array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use std::sync::Arc;

use arrow::datatypes::{DataType, Field};
use h3arrow::array::{CellIndexArray, DirectedEdgeIndexArray, VertexIndexArray};
use pyo3::prelude::*;
use pyo3::types::{PyCapsule, PyTuple};
use pyo3_arrow::ffi::to_array_pycapsules;

use crate::arrow_interop::pyarray_to_cellindexarray;
use crate::resolution::PyResolution;

#[pyclass(name = "CellArray")]
pub struct PyCellArray(CellIndexArray);

impl PyCellArray {
pub fn into_inner(self) -> CellIndexArray {
self.0
}
}

#[pymethods]
impl PyCellArray {
fn __arrow_c_array__<'py>(
&'py self,
py: Python<'py>,
requested_schema: Option<Bound<'py, PyCapsule>>,
) -> PyResult<Bound<'py, PyTuple>> {
let array = self.0.primitive_array();
let field = Arc::new(Field::new("", DataType::UInt64, true));
Ok(to_array_pycapsules(py, field, array, requested_schema)?)
}

fn __len__(&self) -> usize {
self.0.len()
}

fn parent(&self, resolution: PyResolution) -> Self {
Self(self.0.parent(resolution.into()))
}

fn slice(&self, offset: usize, length: usize) -> Self {
Self(self.0.slice(offset, length))
}
}

impl AsRef<CellIndexArray> for PyCellArray {
fn as_ref(&self) -> &CellIndexArray {
&self.0
}
}

impl<'py> FromPyObject<'py> for PyCellArray {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
Ok(Self(pyarray_to_cellindexarray(ob)?))
}
}

#[pyclass(name = "DirectedEdgeArray")]
pub struct PyDirectedEdgeArray(DirectedEdgeIndexArray);

#[pymethods]
impl PyDirectedEdgeArray {
fn __arrow_c_array__<'py>(
&'py self,
py: Python<'py>,
requested_schema: Option<Bound<'py, PyCapsule>>,
) -> PyResult<Bound<'py, PyTuple>> {
let array = self.0.primitive_array();
let field = Arc::new(Field::new("", DataType::UInt64, true));
Ok(to_array_pycapsules(py, field, array, requested_schema)?)
}

fn __len__(&self) -> usize {
self.0.len()
}

pub fn origin(&self) -> PyCellArray {
PyCellArray(self.0.origin())
}

pub fn destination(&self) -> PyCellArray {
PyCellArray(self.0.destination())
}

fn slice(&self, offset: usize, length: usize) -> Self {
Self(self.0.slice(offset, length))
}
}

#[pyclass(name = "VertexArray")]
pub struct PyVertexArray(VertexIndexArray);

#[pymethods]
impl PyVertexArray {
fn __arrow_c_array__<'py>(
&'py self,
py: Python<'py>,
requested_schema: Option<Bound<'py, PyCapsule>>,
) -> PyResult<Bound<'py, PyTuple>> {
let array = self.0.primitive_array();
let field = Arc::new(Field::new("", DataType::UInt64, true));
Ok(to_array_pycapsules(py, field, array, requested_schema)?)
}

fn __len__(&self) -> usize {
self.0.len()
}

pub fn owner(&self) -> PyCellArray {
PyCellArray(self.0.owner())
}

fn slice(&self, offset: usize, length: usize) -> Self {
Self(self.0.slice(offset, length))
}
}
Loading