Skip to content

API: custom classes for GEOS exceptions #991

@jorisvandenbossche

Description

@jorisvandenbossche

Moving an inline discussion to its separate dedicated issue: #983 (comment)

Currently, Shapely has a few custom error classes, such as TopologicalError. Using an example from the tests:

from shapely.geometry import Polygon
p1 = [(339, 346), (459,346), (399,311), (340, 277), (399, 173),
      (280, 242), (339, 415), (280, 381), (460, 207), (339, 346)]
p2 = [(339, 207), (280, 311), (460, 138), (399, 242), (459, 277),
      (459, 415), (399, 381), (519, 311), (520, 242), (519, 173),
      (399, 450), (339, 207)]

>>> Polygon(p1).within(Polygon(p2))
TopologyException: side location conflict at 459 346
Traceback (most recent call last):
  File "/home/joris/miniconda3/envs/DS-python-geospatial/lib/python3.8/site-packages/shapely/predicates.py", line 15, in __call__
    return self.fn(this._geom, other._geom, *args)
  File "/home/joris/miniconda3/envs/DS-python-geospatial/lib/python3.8/site-packages/shapely/geos.py", line 580, in errcheck_predicate
    raise PredicateError("Failed to evaluate %s" % repr(func))
shapely.errors.PredicateError: Failed to evaluate <_FuncPtr object at 0x7f0a641ce1c0>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/joris/miniconda3/envs/DS-python-geospatial/lib/python3.8/site-packages/shapely/geometry/base.py", line 752, in within
    return bool(self.impl['within'](self, other))
  File "/home/joris/miniconda3/envs/DS-python-geospatial/lib/python3.8/site-packages/shapely/predicates.py", line 18, in __call__
    self._check_topology(err, this, other)
  File "/home/joris/miniconda3/envs/DS-python-geospatial/lib/python3.8/site-packages/shapely/topology.py", line 35, in _check_topology
    raise TopologicalError(
shapely.errors.TopologicalError: The operation 'GEOSWithin_r' could not be performed. Likely cause is invalidity of the geometry <shapely.geometry.polygon.Polygon object at 0x7f0a6488e490>

So you can see that here a custom TopologicalError exception class is used with a general message about geometries likely being invalid, but the original GEOS error message is also still printed at the beginning of the stacktrace.

Using pygeos on the same example:

>>> import pygeos
>>> p1 = pygeos.polygons(p1)
>>> p2 = pygeos.polygons(p2)
>>> pygeos.within(p1, p2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/joris/miniconda3/envs/DS-python-geospatial/lib/python3.8/site-packages/pygeos/decorators.py", line 55, in wrapped
    return func(*args, **kwargs)
  File "/home/joris/miniconda3/envs/DS-python-geospatial/lib/python3.8/site-packages/pygeos/predicates.py", line 653, in within
    return lib.within(a, b, **kwargs)
pygeos.GEOSException: TopologyException: side location conflict at 459 346

Here, pygeos currently uses a generic GEOSException class for all exceptions raised directly by GEOS, and then adds the specific error message from GEOS.


So for Shapely 2.0 when moving in pygeos' code (started in #983), we need to decide if we are fine with the current approach in pygeos or if we want to extend it to be more like current Shapely's behaviour.

Personally, I am fine with the approach of pygeos: the error message already indicates it is a Topology related error, so I am not sure a custom exception class gives that much added value.

cc @caspervdw @sgillies @mwtoews @brendan-ward

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions