Skip to content

Commit

Permalink
Merge branch 'master' into issue1106
Browse files Browse the repository at this point in the history
  • Loading branch information
sgillies committed Jul 12, 2021
2 parents 39e7217 + 1991a72 commit 55bf523
Show file tree
Hide file tree
Showing 15 changed files with 82 additions and 44 deletions.
4 changes: 4 additions & 0 deletions CHANGES.txt
Expand Up @@ -12,6 +12,10 @@ New features:

- The STRtree nearest*() methods now take an optional argument that
specifies exclusion of the input geometry from results (#1115).
- A GeometryTypeError has been added to shapely.errors and is consistently
raised instead of TypeError or ValueError as in version 1.7. For backwards
compatibility, the new exception will derive from TypeError and Value error
until version 2.0 (#1099).
- The STRtree class constructor now takes an optional second argument, a
sequence of objects to be stored in the tree. If not provided, the sequence
indices of the geometries will be stored, as before (#1112).
Expand Down
3 changes: 2 additions & 1 deletion shapely/affinity.py
@@ -1,6 +1,7 @@
"""Affine transforms, both in general and specific, named transforms."""

from math import sin, cos, tan, pi
from shapely.errors import GeometryTypeError

__all__ = ['affine_transform', 'rotate', 'scale', 'skew', 'translate']

Expand Down Expand Up @@ -92,7 +93,7 @@ def affine_pts(pts):
return type(geom)([affine_transform(part, matrix)
for part in geom.geoms])
else:
raise ValueError('Type %r not recognized' % geom.type)
raise GeometryTypeError('Type %r not recognized' % geom.type)


def interpret_origin(geom, origin, ndim):
Expand Down
20 changes: 20 additions & 0 deletions shapely/errors.py
@@ -1,4 +1,5 @@
"""Shapely errors."""
import warnings


class ShapelyError(Exception):
Expand Down Expand Up @@ -42,3 +43,22 @@ class ShapelyDeprecationWarning(FutureWarning):

class EmptyPartError(ShapelyError):
"""An error signifying an empty part was encountered when creating a multi-part."""


class GeometryTypeError(ShapelyError, TypeError, ValueError):
"""
An error raised when the type of the geometry in question is
unrecognized or inappropriate.
"""
def __init__(self, msg):
warnings.warn("GeometryTypeError will derive from ShapelyError and not TypeError or ValueError in Shapely 2.0.", ShapelyDeprecationWarning, stacklevel=2)
super().__init__(msg)


class InvalidGeometryError(ShapelyError, TypeError, ValueError):
"""
An error raised when an operation is attempted on a null geometry
"""
def __init__(self, msg):
warnings.warn("InvalidGeometryError will derive from ShapelyError and not TypeError or ValueError in Shapely 2.0.", ShapelyDeprecationWarning, stacklevel=2)
super().__init__(msg)
8 changes: 4 additions & 4 deletions shapely/geometry/base.py
Expand Up @@ -17,7 +17,7 @@

from shapely.affinity import affine_transform
from shapely.coords import CoordinateSequence
from shapely.errors import WKBReadingError, WKTReadingError
from shapely.errors import GeometryTypeError, WKBReadingError, WKTReadingError
from shapely.errors import ShapelyDeprecationWarning
from shapely.geos import WKBWriter, WKTWriter
from shapely.geos import lgeos
Expand Down Expand Up @@ -57,7 +57,7 @@ def dump_coords(geom):
# Recursive call
return [dump_coords(part) for part in geom.geoms]
else:
raise ValueError('Unhandled geometry type: ' + repr(geom.type))
raise GeometryTypeError('Unhandled geometry type: ' + repr(geom.type))


def geometry_type_name(g):
Expand Down Expand Up @@ -653,7 +653,7 @@ def normalize(self):
"""
# self.impl['normalize'](self)
if self._geom is None:
raise ValueError("Null geometry supports no operations")
raise InvalidGeometryError("Null geometry supports no operations")
geom_cloned = lgeos.GEOSGeom_clone(self._geom)
lgeos.GEOSNormalize(geom_cloned)
return geom_factory(geom_cloned)
Expand Down Expand Up @@ -1007,7 +1007,7 @@ def __getitem__(self, key):
return self._get_geom_item(i)
elif isinstance(key, slice):
if type(self) == HeterogeneousGeometrySequence:
raise TypeError(
raise GeometryTypeError(
"Heterogenous geometry collections are not sliceable")
res = []
start, stop, stride = key.indices(m)
Expand Down
7 changes: 4 additions & 3 deletions shapely/geometry/geo.py
Expand Up @@ -3,6 +3,7 @@
"""
import warnings

from shapely.errors import GeometryTypeError
from shapely.errors import ShapelyDeprecationWarning

from .point import Point, asPoint
Expand Down Expand Up @@ -52,7 +53,7 @@ def _empty_shape_for_no_coordinates(geom_type):
elif geom_type == 'multipolygon':
return MultiPolygon()
else:
raise ValueError("Unknown geometry type: %s" % geom_type)
raise GeometryTypeError("Unknown geometry type: %s" % geom_type)


def box(minx, miny, maxx, maxy, ccw=True):
Expand Down Expand Up @@ -117,7 +118,7 @@ def shape(context):
geoms = [shape(g) for g in ob.get("geometries", [])]
return GeometryCollection(geoms)
else:
raise ValueError("Unknown geometry type: %s" % geom_type)
raise GeometryTypeError("Unknown geometry type: %s" % geom_type)


def asShape(context):
Expand Down Expand Up @@ -196,7 +197,7 @@ def asShape(context):
ShapelyDeprecationWarning, stacklevel=2)
return GeometryCollection(geoms)
else:
raise ValueError("Unknown geometry type: %s" % geom_type)
raise GeometryTypeError("Unknown geometry type: %s" % geom_type)


def mapping(ob):
Expand Down
8 changes: 4 additions & 4 deletions shapely/geos.py
Expand Up @@ -15,7 +15,7 @@
from functools import partial

from .ctypes_declarations import prototype, EXCEPTION_HANDLER_FUNCTYPE
from .errors import WKBReadingError, WKTReadingError, TopologicalError, PredicateError
from .errors import InvalidGeometryError, WKBReadingError, WKTReadingError, TopologicalError, PredicateError


# Add message handler to this module's logger
Expand Down Expand Up @@ -395,7 +395,7 @@ def __del__(self):
def write(self, geom):
"""Returns WKT string for geometry"""
if geom is None or geom._geom is None:
raise ValueError("Null geometry supports no operations")
raise InvalidGeometryError("Null geometry supports no operations")
result = self._lgeos.GEOSWKTWriter_write(self._writer, geom._geom)
text = string_at(result)
lgeos.GEOSFree(result)
Expand Down Expand Up @@ -515,7 +515,7 @@ def __del__(self):
def write(self, geom):
"""Returns WKB byte string for geometry"""
if geom is None or geom._geom is None:
raise ValueError("Null geometry supports no operations")
raise InvalidGeometryError("Null geometry supports no operations")
size = c_size_t()
result = self._lgeos.GEOSWKBWriter_write(
self._writer, geom._geom, pointer(size))
Expand All @@ -526,7 +526,7 @@ def write(self, geom):
def write_hex(self, geom):
"""Returns WKB hex string for geometry"""
if geom is None or geom._geom is None:
raise ValueError("Null geometry supports no operations")
raise InvalidGeometryError("Null geometry supports no operations")
size = c_size_t()
result = self._lgeos.GEOSWKBWriter_writeHEX(
self._writer, geom._geom, pointer(size))
Expand Down
6 changes: 3 additions & 3 deletions shapely/iterops.py
Expand Up @@ -3,7 +3,7 @@
"""
import warnings

from shapely.errors import ShapelyDeprecationWarning
from shapely.errors import InvalidGeometryError, ShapelyDeprecationWarning
from shapely.topology import Delegating


Expand All @@ -18,15 +18,15 @@ def __call__(self, context, iterator, value=True):
"Shapely 2.0".format(self._name),
ShapelyDeprecationWarning, stacklevel=2)
if context._geom is None:
raise ValueError("Null geometry supports no operations")
raise InvalidGeometryError("Null geometry supports no operations")
for item in iterator:
try:
this_geom, ob = item
except TypeError:
this_geom = item
ob = this_geom
if not this_geom._geom:
raise ValueError("Null geometry supports no operations")
raise InvalidGeometryError("Null geometry supports no operations")
try:
retval = self.fn(context._geom, this_geom._geom)
except Exception as err:
Expand Down
3 changes: 2 additions & 1 deletion shapely/linref.py
@@ -1,14 +1,15 @@
"""Linear referencing
"""

from shapely.errors import GeometryTypeError
from shapely.topology import Delegating


class LinearRefBase(Delegating):
def _validate_line(self, ob):
super()._validate(ob)
if not ob.geom_type in ['LinearRing', 'LineString', 'MultiLineString']:
raise TypeError("Only linear types support this operation")
raise GeometryTypeError("Only linear types support this operation")

class ProjectOp(LinearRefBase):
def __call__(self, this, other):
Expand Down
42 changes: 24 additions & 18 deletions shapely/ops.py
Expand Up @@ -4,7 +4,7 @@
from ctypes import byref, c_void_p, c_double
from warnings import warn

from shapely.errors import ShapelyDeprecationWarning
from shapely.errors import GeometryTypeError, ShapelyDeprecationWarning
from shapely.prepared import prep
from shapely.geos import lgeos
from shapely.geometry.base import geom_factory, BaseGeometry, BaseMultipartGeometry
Expand Down Expand Up @@ -322,7 +322,7 @@ def id_func(x, y, z=None):
elif geom.type.startswith('Multi') or geom.type == 'GeometryCollection':
return type(geom)([transform(func, part) for part in geom.geoms])
else:
raise ValueError('Type %r not recognized' % geom.type)
raise GeometryTypeError('Type %r not recognized' % geom.type)


def nearest_points(g1, g2):
Expand Down Expand Up @@ -391,9 +391,9 @@ def shared_paths(g1, g2):
The second geometry
"""
if not isinstance(g1, LineString):
raise TypeError("First geometry must be a LineString")
raise GeometryTypeError("First geometry must be a LineString")
if not isinstance(g2, LineString):
raise TypeError("Second geometry must be a LineString")
raise GeometryTypeError("Second geometry must be a LineString")
return(geom_factory(lgeos.methods['shared_paths'](g1._geom, g2._geom)))


Expand All @@ -402,9 +402,10 @@ class SplitOp:
@staticmethod
def _split_polygon_with_line(poly, splitter):
"""Split a Polygon with a LineString"""

assert(isinstance(poly, Polygon))
assert(isinstance(splitter, LineString))
if not isinstance(poly, Polygon):
raise GeometryTypeError("First argument must be a Polygon")
if not isinstance(splitter, LineString):
raise GeometryTypeError("Second argument must be a LineString")

union = poly.boundary.union(splitter)

Expand All @@ -426,8 +427,10 @@ def _split_line_with_line(line, splitter):
if splitter.type in ('Polygon', 'MultiPolygon'):
splitter = splitter.boundary

assert(isinstance(line, LineString))
assert(isinstance(splitter, LineString) or isinstance(splitter, MultiLineString))
if not isinstance(line, LineString):
raise GeometryTypeError("First argument must be a LineString")
if not isinstance(splitter, LineString) and not isinstance(splitter, MultiLineString):
raise GeometryTypeError("Second argument must be either a LineString or a MultiLineString")

# | s\l | Interior | Boundary | Exterior |
# |----------|----------|----------|----------|
Expand All @@ -448,9 +451,10 @@ def _split_line_with_line(line, splitter):
@staticmethod
def _split_line_with_point(line, splitter):
"""Split a LineString with a Point"""

assert(isinstance(line, LineString))
assert(isinstance(splitter, Point))
if not isinstance(line, LineString):
raise GeometryTypeError("First argument must be a LineString")
if not isinstance(splitter, Point):
raise GeometryTypeError("Second argument must be a Point")

# check if point is in the interior of the line
if not line.relate_pattern(splitter, '0********'):
Expand Down Expand Up @@ -494,8 +498,10 @@ def _split_line_with_point(line, splitter):
def _split_line_with_multipoint(line, splitter):
"""Split a LineString with a MultiPoint"""

assert(isinstance(line, LineString))
assert(isinstance(splitter, MultiPoint))
if not isinstance(line, LineString):
raise GeometryTypeError("First argument must be a LineString")
if not isinstance(splitter, MultiPoint):
raise GeometryTypeError("Second argument must be a MultiPoint")

chunks = [line]
for pt in splitter.geoms:
Expand Down Expand Up @@ -549,16 +555,16 @@ def split(geom, splitter):
elif splitter.type in ('MultiPoint'):
split_func = SplitOp._split_line_with_multipoint
else:
raise ValueError("Splitting a LineString with a %s is not supported" % splitter.type)
raise GeometryTypeError("Splitting a LineString with a %s is not supported" % splitter.type)

elif geom.type == 'Polygon':
if splitter.type == 'LineString':
split_func = SplitOp._split_polygon_with_line
else:
raise ValueError("Splitting a Polygon with a %s is not supported" % splitter.type)
raise GeometryTypeError("Splitting a Polygon with a %s is not supported" % splitter.type)

else:
raise ValueError("Splitting %s geometry is not supported" % geom.type)
raise GeometryTypeError("Splitting %s geometry is not supported" % geom.type)

return GeometryCollection(split_func(geom, splitter))

Expand Down Expand Up @@ -625,7 +631,7 @@ def substring(geom, start_dist, end_dist, normalized=False):
"""

if not isinstance(geom, LineString):
raise TypeError("Can only calculate a substring of LineString geometries. A %s was provided." % geom.type)
raise GeometryTypeError("Can only calculate a substring of LineString geometries. A %s was provided." % geom.type)

# Filter out cases in which to return a point
if start_dist == end_dist:
Expand Down
4 changes: 2 additions & 2 deletions shapely/speedups/_speedups.pyx
Expand Up @@ -13,7 +13,7 @@ import logging
from shapely.geos import lgeos
from shapely.geometry import Point, LineString, LinearRing
from shapely.geometry.base import geom_factory
from shapely.errors import TopologicalError
from shapely.errors import GeometryTypeError, TopologicalError


include "../_geos.pxi"
Expand Down Expand Up @@ -573,4 +573,4 @@ cpdef affine_transform(geom, matrix):
elif geom.type.startswith('Multi') or geom.type == 'GeometryCollection':
return type(geom)([affine_transform(part, matrix) for part in geom.geoms])
else:
raise ValueError('Type %r not recognized' % geom.type)
raise GeometryTypeError('Type %r not recognized' % geom.type)
3 changes: 2 additions & 1 deletion shapely/topology.py
Expand Up @@ -9,13 +9,14 @@

from ctypes import byref, c_double
from shapely.geos import TopologicalError, lgeos
from shapely.errors import InvalidGeometryError


class Validating:

def _validate(self, ob, stop_prepared=False):
if ob is None or ob._geom is None:
raise ValueError("Null geometry supports no operations")
raise InvalidGeometryError("Null geometry supports no operations")
if stop_prepared and hasattr(ob, 'prepared'):
raise ValueError("Prepared geometries cannot be operated on")

Expand Down
3 changes: 2 additions & 1 deletion tests/test_linear_referencing.py
@@ -1,4 +1,5 @@
from . import unittest
from shapely.errors import GeometryTypeError
from shapely.geometry import Point, LineString, MultiLineString


Expand Down Expand Up @@ -27,7 +28,7 @@ def test_multiline_project(self):
self.multiline.project(self.point, normalized=True), 0.125)

def test_not_supported_project(self):
with self.assertRaises(TypeError):
with self.assertRaises(GeometryTypeError):
self.point.buffer(1.0).project(self.point)

def test_not_on_line_project(self):
Expand Down
5 changes: 3 additions & 2 deletions tests/test_shared_paths.py
@@ -1,5 +1,6 @@
from . import unittest

from shapely.errors import GeometryTypeError
from shapely.geometry import Point, LineString, Polygon, MultiLineString, \
GeometryCollection
from shapely.ops import shared_paths
Expand Down Expand Up @@ -35,8 +36,8 @@ def test_wrong_type(self):
g1 = Point(0, 0)
g2 = LineString([(5, 0), (15, 0)])

with self.assertRaises(TypeError):
with self.assertRaises(GeometryTypeError):
result = shared_paths(g1, g2)

with self.assertRaises(TypeError):
with self.assertRaises(GeometryTypeError):
result = shared_paths(g2, g1)

0 comments on commit 55bf523

Please sign in to comment.