Skip to content

Commit

Permalink
python: improved error handling (#370)
Browse files Browse the repository at this point in the history
removing lots of unwraps!
  • Loading branch information
kylebarron authored Jan 1, 2024
1 parent 62fef84 commit 615c70e
Show file tree
Hide file tree
Showing 22 changed files with 287 additions and 244 deletions.
25 changes: 11 additions & 14 deletions python/core/src/algorithm/geo/area.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use crate::ffi::from_python::import_arrow_c_array;
use geoarrow::algorithm::geo::Area;
use geoarrow::array::from_arrow_array;
use pyo3::prelude::*;

#[pyfunction]
pub fn area(ob: &PyAny) -> PyResult<Float64Array> {
pub fn area(ob: &PyAny) -> PyGeoArrowResult<Float64Array> {
let (array, field) = import_arrow_c_array(ob)?;
// TODO: need to improve crate's error handling
let array = from_arrow_array(&array, &field).unwrap();
// TODO: fix error handling
Ok(array.as_ref().unsigned_area().unwrap().into())
let array = from_arrow_array(&array, &field)?;
Ok(array.as_ref().unsigned_area()?.into())
}

#[pyfunction]
pub fn signed_area(ob: &PyAny) -> PyResult<Float64Array> {
pub fn signed_area(ob: &PyAny) -> PyGeoArrowResult<Float64Array> {
let (array, field) = import_arrow_c_array(ob)?;
// TODO: need to improve crate's error handling
let array = from_arrow_array(&array, &field).unwrap();
// TODO: fix error handling
Ok(array.as_ref().signed_area().unwrap().into())
let array = from_arrow_array(&array, &field)?;
Ok(array.as_ref().signed_area()?.into())
}

macro_rules! impl_area {
Expand Down Expand Up @@ -56,15 +53,15 @@ macro_rules! impl_chunked {
#[pymethods]
impl $struct_name {
/// Unsigned planar area of a geometry.
pub fn area(&self) -> ChunkedFloat64Array {
pub fn area(&self) -> PyGeoArrowResult<ChunkedFloat64Array> {
use geoarrow::algorithm::geo::Area;
Area::unsigned_area(&self.0).unwrap().into()
Ok(Area::unsigned_area(&self.0)?.into())
}

/// Signed planar area of a geometry.
pub fn signed_area(&self) -> ChunkedFloat64Array {
pub fn signed_area(&self) -> PyGeoArrowResult<ChunkedFloat64Array> {
use geoarrow::algorithm::geo::Area;
Area::signed_area(&self.0).unwrap().into()
Ok(Area::signed_area(&self.0)?.into())
}
}
};
Expand Down
7 changes: 3 additions & 4 deletions python/core/src/algorithm/geo/bounding_rect.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use pyo3::prelude::*;

macro_rules! impl_bounding_rect {
Expand Down Expand Up @@ -29,11 +30,9 @@ macro_rules! impl_vector {
#[pymethods]
impl $struct_name {
/// Return the bounding rectangle of a geometry
pub fn bounding_rect(&self) -> PyResult<ChunkedRectArray> {
pub fn bounding_rect(&self) -> PyGeoArrowResult<ChunkedRectArray> {
use geoarrow::algorithm::geo::BoundingRect;
Ok(ChunkedRectArray(
BoundingRect::bounding_rect(&self.0).unwrap(),
))
Ok(ChunkedRectArray(BoundingRect::bounding_rect(&self.0)?))
}
}
};
Expand Down
13 changes: 6 additions & 7 deletions python/core/src/algorithm/geo/center.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use crate::ffi::from_python::import_arrow_c_array;
use geoarrow::algorithm::geo::Center;
use geoarrow::array::from_arrow_array;
use pyo3::prelude::*;

#[pyfunction]
pub fn center(ob: &PyAny) -> PyResult<PointArray> {
pub fn center(ob: &PyAny) -> PyGeoArrowResult<PointArray> {
let (array, field) = import_arrow_c_array(ob)?;
// TODO: need to improve crate's error handling
let array = from_arrow_array(&array, &field).unwrap();
// TODO: fix error handling
Ok(array.as_ref().center().unwrap().into())
let array = from_arrow_array(&array, &field)?;
Ok(array.as_ref().center()?.into())
}

macro_rules! impl_center {
Expand Down Expand Up @@ -47,9 +46,9 @@ macro_rules! impl_chunked {
///
/// This first computes the axis-aligned bounding rectangle, then takes the center of
/// that box
pub fn center(&self) -> ChunkedPointArray {
pub fn center(&self) -> PyGeoArrowResult<ChunkedPointArray> {
use geoarrow::algorithm::geo::Center;
ChunkedPointArray(Center::center(&self.0).unwrap())
Ok(ChunkedPointArray(Center::center(&self.0)?))
}
}
};
Expand Down
13 changes: 6 additions & 7 deletions python/core/src/algorithm/geo/centroid.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use crate::ffi::from_python::import_arrow_c_array;
use geoarrow::algorithm::geo::Centroid;
use geoarrow::array::from_arrow_array;
use pyo3::prelude::*;

#[pyfunction]
pub fn centroid(ob: &PyAny) -> PyResult<PointArray> {
pub fn centroid(ob: &PyAny) -> PyGeoArrowResult<PointArray> {
let (array, field) = import_arrow_c_array(ob)?;
// TODO: need to improve crate's error handling
let array = from_arrow_array(&array, &field).unwrap();
// TODO: fix error handling
Ok(array.as_ref().centroid().unwrap().into())
let array = from_arrow_array(&array, &field)?;
Ok(array.as_ref().centroid()?.into())
}

macro_rules! impl_centroid {
Expand Down Expand Up @@ -55,9 +54,9 @@ macro_rules! impl_chunked {
///
/// The geometric centroid of a convex object always lies in the object.
/// A non-convex object might have a centroid that _is outside the object itself_.
pub fn centroid(&self) -> ChunkedPointArray {
pub fn centroid(&self) -> PyGeoArrowResult<ChunkedPointArray> {
use geoarrow::algorithm::geo::Centroid;
ChunkedPointArray(Centroid::centroid(&self.0).unwrap())
Ok(ChunkedPointArray(Centroid::centroid(&self.0)?))
}
}
};
Expand Down
17 changes: 9 additions & 8 deletions python/core/src/algorithm/geo/chamberlain_duquette_area.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use pyo3::prelude::*;

macro_rules! impl_alg {
Expand Down Expand Up @@ -35,19 +36,19 @@ macro_rules! impl_chunked {
#[pymethods]
impl $struct_name {
/// Calculate the unsigned approximate geodesic area of a `Geometry`.
pub fn chamberlain_duquette_unsigned_area(&self) -> ChunkedFloat64Array {
pub fn chamberlain_duquette_unsigned_area(
&self,
) -> PyGeoArrowResult<ChunkedFloat64Array> {
use geoarrow::algorithm::geo::ChamberlainDuquetteArea;
ChamberlainDuquetteArea::chamberlain_duquette_unsigned_area(&self.0)
.unwrap()
.into()
Ok(ChamberlainDuquetteArea::chamberlain_duquette_unsigned_area(&self.0)?.into())
}

/// Calculate the signed approximate geodesic area of a `Geometry`.
pub fn chamberlain_duquette_signed_area(&self) -> ChunkedFloat64Array {
pub fn chamberlain_duquette_signed_area(
&self,
) -> PyGeoArrowResult<ChunkedFloat64Array> {
use geoarrow::algorithm::geo::ChamberlainDuquetteArea;
ChamberlainDuquetteArea::chamberlain_duquette_signed_area(&self.0)
.unwrap()
.into()
Ok(ChamberlainDuquetteArea::chamberlain_duquette_signed_area(&self.0)?.into())
}
}
};
Expand Down
13 changes: 6 additions & 7 deletions python/core/src/algorithm/geo/convex_hull.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use crate::ffi::from_python::import_arrow_c_array;
use geoarrow::algorithm::geo::ConvexHull;
use geoarrow::array::from_arrow_array;
use pyo3::prelude::*;

#[pyfunction]
pub fn convex_hull(ob: &PyAny) -> PyResult<PolygonArray> {
pub fn convex_hull(ob: &PyAny) -> PyGeoArrowResult<PolygonArray> {
let (array, field) = import_arrow_c_array(ob)?;
// TODO: need to improve crate's error handling
let array = from_arrow_array(&array, &field).unwrap();
// TODO: fix error handling
Ok(array.as_ref().convex_hull().unwrap().into())
let array = from_arrow_array(&array, &field)?;
Ok(array.as_ref().convex_hull()?.into())
}

macro_rules! impl_alg {
Expand Down Expand Up @@ -53,9 +52,9 @@ macro_rules! impl_chunked {
/// Dobkin, David P.; Huhdanpaa, Hannu (1 December
/// 1996)](https://dx.doi.org/10.1145%2F235815.235821) Original paper here:
/// <http://www.cs.princeton.edu/~dpd/Papers/BarberDobkinHuhdanpaa.pdf>
pub fn convex_hull(&self) -> ChunkedPolygonArray {
pub fn convex_hull(&self) -> PyGeoArrowResult<ChunkedPolygonArray> {
use geoarrow::algorithm::geo::ConvexHull;
ChunkedPolygonArray(ConvexHull::convex_hull(&self.0).unwrap())
Ok(ChunkedPolygonArray(ConvexHull::convex_hull(&self.0)?))
}
}
};
Expand Down
5 changes: 3 additions & 2 deletions python/core/src/algorithm/geo/dimensions.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use pyo3::prelude::*;

macro_rules! impl_alg {
Expand Down Expand Up @@ -37,9 +38,9 @@ macro_rules! impl_chunked {
///
/// Types like `Point`, which have at least one coordinate by construction, can never
/// be considered empty.
pub fn is_empty(&self) -> ChunkedBooleanArray {
pub fn is_empty(&self) -> PyGeoArrowResult<ChunkedBooleanArray> {
use geoarrow::algorithm::geo::HasDimensions;
HasDimensions::is_empty(&self.0).unwrap().into()
Ok(HasDimensions::is_empty(&self.0)?.into())
}
}
};
Expand Down
5 changes: 3 additions & 2 deletions python/core/src/algorithm/geo/euclidean_length.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use pyo3::prelude::*;

macro_rules! impl_euclidean_length {
Expand All @@ -25,9 +26,9 @@ macro_rules! impl_chunked {
#[pymethods]
impl $struct_name {
/// (Euclidean) Calculation of the length of a Line
pub fn length(&self) -> ChunkedFloat64Array {
pub fn length(&self) -> PyGeoArrowResult<ChunkedFloat64Array> {
use geoarrow::algorithm::geo::EuclideanLength;
EuclideanLength::euclidean_length(&self.0).unwrap().into()
Ok(EuclideanLength::euclidean_length(&self.0)?.into())
}
}
};
Expand Down
15 changes: 7 additions & 8 deletions python/core/src/algorithm/geo/geodesic_area.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use pyo3::prelude::*;

macro_rules! impl_geodesic_area {
Expand Down Expand Up @@ -110,9 +111,9 @@ macro_rules! impl_chunked {
/// 2. The polygon is larger than half the planet. In this case, the returned area of the polygon is not correct. If you expect to be dealing with very large polygons, please use the `unsigned` methods.
///
/// [Karney (2013)]: https://arxiv.org/pdf/1109.4448.pdf
pub fn geodesic_area_signed(&self) -> ChunkedFloat64Array {
pub fn geodesic_area_signed(&self) -> PyGeoArrowResult<ChunkedFloat64Array> {
use geoarrow::algorithm::geo::GeodesicArea;
GeodesicArea::geodesic_area_signed(&self.0).unwrap().into()
Ok(GeodesicArea::geodesic_area_signed(&self.0)?.into())
}

/// Determine the area of a geometry on an ellipsoidal model of the earth. Supports very large geometries that cover a significant portion of the earth.
Expand All @@ -130,11 +131,9 @@ macro_rules! impl_chunked {
/// - return value: meter²
///
/// [Karney (2013)]: https://arxiv.org/pdf/1109.4448.pdf
pub fn geodesic_area_unsigned(&self) -> ChunkedFloat64Array {
pub fn geodesic_area_unsigned(&self) -> PyGeoArrowResult<ChunkedFloat64Array> {
use geoarrow::algorithm::geo::GeodesicArea;
GeodesicArea::geodesic_area_unsigned(&self.0)
.unwrap()
.into()
Ok(GeodesicArea::geodesic_area_unsigned(&self.0)?.into())
}

/// Determine the perimeter of a geometry on an ellipsoidal model of the earth.
Expand All @@ -149,9 +148,9 @@ macro_rules! impl_chunked {
/// - return value: meter
///
/// [Karney (2013)]: https://arxiv.org/pdf/1109.4448.pdf
pub fn geodesic_perimeter(&self) -> ChunkedFloat64Array {
pub fn geodesic_perimeter(&self) -> PyGeoArrowResult<ChunkedFloat64Array> {
use geoarrow::algorithm::geo::GeodesicArea;
GeodesicArea::geodesic_perimeter(&self.0).unwrap().into()
Ok(GeodesicArea::geodesic_perimeter(&self.0)?.into())
}
}
};
Expand Down
6 changes: 3 additions & 3 deletions python/core/src/algorithm/geo/vincenty_length.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::array::*;
use crate::error::PyGeoArrowResult;
use pyo3::prelude::*;

macro_rules! impl_vincenty_length {
Expand All @@ -8,10 +9,9 @@ macro_rules! impl_vincenty_length {
/// Determine the length of a geometry using [Vincenty’s formulae].
///
/// [Vincenty’s formulae]: https://en.wikipedia.org/wiki/Vincenty%27s_formulae
pub fn vincenty_length(&self) -> PyResult<Float64Array> {
pub fn vincenty_length(&self) -> PyGeoArrowResult<Float64Array> {
use geoarrow::algorithm::geo::VincentyLength;
let result = VincentyLength::vincenty_length(&self.0).unwrap();
Ok(result.into())
Ok(VincentyLength::vincenty_length(&self.0)?.into())
}
}
};
Expand Down
5 changes: 3 additions & 2 deletions python/core/src/algorithm/native/concatenate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::array::*;
use crate::chunked_array::*;
use crate::error::PyGeoArrowResult;
use geoarrow::algorithm::native::Concatenate;
use pyo3::prelude::*;

Expand All @@ -8,8 +9,8 @@ macro_rules! impl_len {
#[pymethods]
impl $struct_name {
/// Concatenate a chunked array into a contiguous array.
pub fn concatenate(&self) -> $return_type {
self.0.concatenate().unwrap().into()
pub fn concatenate(&self) -> PyGeoArrowResult<$return_type> {
Ok(self.0.concatenate()?.into())
}
}
};
Expand Down
25 changes: 13 additions & 12 deletions python/core/src/array/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod primitive;

use crate::error::PyGeoArrowResult;
pub use primitive::{
BooleanArray, Float16Array, Float32Array, Float64Array, Int16Array, Int32Array, Int64Array,
Int8Array, LargeStringArray, StringArray, UInt16Array, UInt32Array, UInt64Array, UInt8Array,
Expand Down Expand Up @@ -74,27 +75,27 @@ impl_array! {

#[pymethods]
impl WKBArray {
fn to_point_array(&self) -> Result<PointArray, PyErr> {
Ok(PointArray(self.0.clone().try_into().unwrap()))
fn to_point_array(&self) -> PyGeoArrowResult<PointArray> {
Ok(PointArray(self.0.clone().try_into()?))
}

fn to_line_string_array(&self) -> Result<LineStringArray, PyErr> {
Ok(LineStringArray(self.0.clone().try_into().unwrap()))
fn to_line_string_array(&self) -> PyGeoArrowResult<LineStringArray> {
Ok(LineStringArray(self.0.clone().try_into()?))
}

fn to_polygon_array(&self) -> Result<PolygonArray, PyErr> {
Ok(PolygonArray(self.0.clone().try_into().unwrap()))
fn to_polygon_array(&self) -> PyGeoArrowResult<PolygonArray> {
Ok(PolygonArray(self.0.clone().try_into()?))
}

fn to_multi_point_array(&self) -> Result<MultiPointArray, PyErr> {
Ok(MultiPointArray(self.0.clone().try_into().unwrap()))
fn to_multi_point_array(&self) -> PyGeoArrowResult<MultiPointArray> {
Ok(MultiPointArray(self.0.clone().try_into()?))
}

fn to_multi_line_string_array(&self) -> Result<MultiLineStringArray, PyErr> {
Ok(MultiLineStringArray(self.0.clone().try_into().unwrap()))
fn to_multi_line_string_array(&self) -> PyGeoArrowResult<MultiLineStringArray> {
Ok(MultiLineStringArray(self.0.clone().try_into()?))
}

fn to_multi_polygon_array(&self) -> Result<MultiPolygonArray, PyErr> {
Ok(MultiPolygonArray(self.0.clone().try_into().unwrap()))
fn to_multi_polygon_array(&self) -> PyGeoArrowResult<MultiPolygonArray> {
Ok(MultiPolygonArray(self.0.clone().try_into()?))
}
}
Loading

0 comments on commit 615c70e

Please sign in to comment.