Skip to content

Commit

Permalink
ENH: Better wrap GDAL errors and pass through GDAL exceptions (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
brendan-ward authored Feb 24, 2022
1 parent 8136492 commit d0b202a
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 86 deletions.
14 changes: 14 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,26 @@
- index of GeoDataFrame created by `read_dataframe` can now optionally be set
to the FID of the features that are read, as `int64` dtype. Note that some
drivers start FID numbering at 0 whereas others start numbering at 1.
- generalize check for VSI files from `/vsizip` to `/vsi` (#29)
- add dtype for each field to `read_info` (#30)
- support writing empty GeoDataFrames (#38)

### Breaking changes

- `read` now also returns an optional FIDs ndarray in addition to meta,
geometries, and fields; this is the 2nd item in the returned tuple.

### Potentially breaking changes

- Consolided error handling to better use GDAL error messages and specific
exception classes (#39). Note that this is a breaking change only if you are
relying on specific error classes to be emitted.

### Bug fixes

- use dtype `object` instead of `numpy.object` to eliminate deprecation warnings (#34)
- raise error if layer cannot be opened (#35)

## 0.3.0

### Major enhancements
Expand Down
19 changes: 19 additions & 0 deletions docs/source/errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Error handling

Pyogrio tries to capture and wrap errors from GDAL/OGR where possible, but defers
to error messages emitted by GDAL where available. The error types below are
intended to help assist in determining the source of the error in case the
error message is a bit cryptic.

Some of the errors that may be emitted by pyogrio include:

- `ValueError` / `TypeError`: indicates that a user-provided is invalid for a particular
operation
- `DataSourceError`: indicates an error opening or using a transaction against a data source
- `DataLayerError`: indicates an error obtaining a data layer or its properties (subclassed by all of following)
- `CRSError`: indicates an error reading or writing CRS information
- `FeatureError`: indicates an error reading or writing a specific feature
- `GeometryError`: indicates an error reading or writing a geometry field of a single feature
- `FieldError`: indicates an error reading or writing a non-geometry field of a single feature

All the pyogrio specific errors are subclasses of `RuntimeError`.
1 change: 1 addition & 0 deletions docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ supported_formats
install
introduction
api
errors
known_issues
```
8 changes: 2 additions & 6 deletions docs/source/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,11 @@ If you install GeoPandas or Fiona using `pip`, you may encounter issues related
to incompatibility of the exact GDAL library pre-installed with Fiona and the
version of GDAL that gets compiled with Pyogrio (right now you do this manually).

This may show up as driver error resulting from a `NULL` pointer exception like
This may show up as an exception like
this:

```
pyogrio._err.NullPointerError: NULL pointer error
During handling of the above exception, another exception occurred:
...
pyogrio.errors.DriverError: Data source driver could not be created: GPKG
pyogrio.errors.DataSourceError: Could not obtain driver ...
```

To get around it, uninstall `fiona` then reinstall to use system GDAL:
Expand Down
3 changes: 1 addition & 2 deletions pyogrio/_err.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ cdef inline object exc_check():
return



cdef void *exc_wrap_pointer(void *ptr) except NULL:
"""Wrap a GDAL/OGR function that returns GDALDatasetH etc (void *)
Raises an exception if a non-fatal error has be set or if pointer is NULL.
Expand All @@ -191,4 +190,4 @@ cdef int exc_wrap_int(int err) except -1:
else:
# no error message from GDAL
raise CPLE_BaseError(-1, -1, "Unspecified OGR / GDAL error")
return err
return err
17 changes: 11 additions & 6 deletions pyogrio/_geometry.pyx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import warnings
from pyogrio._ogr cimport *
from pyogrio._err cimport *
from pyogrio.errors import UnsupportedGeometryTypeError
from pyogrio._err import CPLE_BaseError, NullPointerError
from pyogrio.errors import DataLayerError, GeometryError


# Mapping of OGR integer geometry types to GeoJSON type names.
Expand Down Expand Up @@ -72,14 +73,18 @@ cdef str get_geometry_type(void *ogr_layer):
cdef void *cogr_featuredef = NULL
cdef OGRwkbGeometryType ogr_type

ogr_featuredef = OGR_L_GetLayerDefn(ogr_layer)
if ogr_featuredef == NULL:
raise ValueError("Null feature definition")
try:
ogr_featuredef = exc_wrap_pointer(OGR_L_GetLayerDefn(ogr_layer))
except NullPointerError:
raise DataLayerError("Could not get layer definition")

except CPLE_BaseError as exc:
raise DataLayerError(str(exc))

ogr_type = OGR_FD_GetGeomType(ogr_featuredef)

if ogr_type not in GEOMETRY_TYPES:
raise UnsupportedGeometryTypeError(ogr_type)
raise GeometryError(f"Geometry type is not supported: {ogr_type}")

if OGR_GT_HasM(ogr_type):
original_type = GEOMETRY_TYPES[ogr_type]
Expand Down Expand Up @@ -109,6 +114,6 @@ cdef int get_geometry_type_code(str geometry_type):
geometry type code
"""
if geometry_type not in GEOMETRY_TYPE_CODES:
raise UnsupportedGeometryTypeError(geometry_type)
raise GeometryError(f"Geometry type is not supported: {geometry_type}")

return GEOMETRY_TYPE_CODES[geometry_type]
Loading

0 comments on commit d0b202a

Please sign in to comment.