Shapely: Inconsistent behavior when passing empty Points to MultiPoint

Created on 7 Feb 2020  路  9Comments  路  Source: Toblerity/Shapely

The documentation on MultiPoint says that I can pass to it a sequence of Points. But it doesn't warn us against passing empty Points. Interestingly enough, if I pass an empty Point as the first element, it will throw an AssertionError:

>>> from shapely.geometry import Point, MultiPoint
>>> MultiPoint([Point()])
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-30-8942eaebd9a2> in <module>
----> 1 MultiPoint([Point()])

~\Miniconda3\lib\site-packages\shapely\geometry\multipoint.py in __init__(self, points)
     56             pass
     57         else:
---> 58             self._geom, self._ndim = geos_multipoint_from_py(points)
     59 
     60     def shape_factory(self, *args):

~\Miniconda3\lib\site-packages\shapely\geometry\multipoint.py in geos_multipoint_from_py(ob)
    162     except TypeError:
    163         n = ob[0]._ndim
--> 164     assert n == 2 or n == 3
    165 
    166     # Array of pointers to point geometries

AssertionError: 



md5-7f58c60ea833e3f4b523f7bc4e2c6cf6



```none
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-31-08a0b83c889a> in <module>
----> 1 MultiPoint([Point(), Point(1, 2)])

~\Miniconda3\lib\site-packages\shapely\geometry\multipoint.py in __init__(self, points)
     56             pass
     57         else:
---> 58             self._geom, self._ndim = geos_multipoint_from_py(points)
     59 
     60     def shape_factory(self, *args):

~\Miniconda3\lib\site-packages\shapely\geometry\multipoint.py in geos_multipoint_from_py(ob)
    162     except TypeError:
    163         n = ob[0]._ndim
--> 164     assert n == 2 or n == 3
    165 
    166     # Array of pointers to point geometries

AssertionError: 



md5-b0713eaf20b3dbaf812d2b96e9059121




But the resulting object will throw an exception after trying to get its wkt:



md5-6cb5bf2f7d347dc7bcb3eb576c7452e1



```none
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
<ipython-input-38-c645b8b312e6> in <module>
----> 1 MultiPoint([Point(1, 2), Point()]).wkt

~\Miniconda3\lib\site-packages\shapely\geometry\base.py in wkt(self, **kw)
    365     def wkt(self, **kw):
    366         """WKT representation of the geometry"""
--> 367         return WKTWriter(lgeos, **kw).write(self)
    368 
    369     @property

~\Miniconda3\lib\site-packages\shapely\geos.py in write(self, geom)
    361         if geom is None or geom._geom is None:
    362             raise ValueError("Null geometry supports no operations")
--> 363         result = self._lgeos.GEOSWKTWriter_write(self._writer, geom._geom)
    364         text = string_at(result)
    365         lgeos.GEOSFree(result)

OSError: exception: access violation reading 0x0000000000000000

I assume there needs to be a guard against a presence of empty points in the passed sequence, and the docs should be updated too.


Shapely version: 1.6.4.post1, installed from conda.

bug

All 9 comments

I've just discovered a similar issue with MultiLineString. MultiPolygon works fine though.

>>> from shapely.geometry import LineString, MultiLineString
>>> MultiLineString([LineString(), LineString([(0, 0), (1, 1)])])
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-55-0aca5a523169> in <module>
----> 1 MultiLineString([LineString(), LineString([(0, 0), (1, 1)])])

~\Miniconda3\lib\site-packages\shapely\geometry\multilinestring.py in __init__(self, lines)
     50             pass
     51         else:
---> 52             self._geom, self._ndim = geos_multilinestring_from_py(lines)
     53 
     54     def shape_factory(self, *args):

~\Miniconda3\lib\site-packages\shapely\geometry\multilinestring.py in geos_multilinestring_from_py(ob)
    125         N = exemplar._ndim
    126     if N not in (2, 3):
--> 127         raise ValueError("Invalid coordinate dimensionality")
    128 
    129     # Array of pointers to point geometries

ValueError: Invalid coordinate dimensionality



md5-8513a28055f286357bb8bf2e099ecb29



```none
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
<ipython-input-59-255eed31faa5> in <module>
----> 1 MultiLineString([LineString([(0, 0), (1, 1)]), LineString()]).wkt

~\Miniconda3\lib\site-packages\shapely\geometry\base.py in wkt(self, **kw)
    365     def wkt(self, **kw):
    366         """WKT representation of the geometry"""
--> 367         return WKTWriter(lgeos, **kw).write(self)
    368 
    369     @property

~\Miniconda3\lib\site-packages\shapely\geos.py in write(self, geom)
    361         if geom is None or geom._geom is None:
    362             raise ValueError("Null geometry supports no operations")
--> 363         result = self._lgeos.GEOSWKTWriter_write(self._writer, geom._geom)
    364         text = string_at(result)
    365         lgeos.GEOSFree(result)

OSError: exception: access violation reading 0x0000000000000008

Not sure if I should open another issue for this.

@LostFan123 can you check with shapely 1.7.0? We're not supporting 1.6.x any longer.

@sgillies 1.7.0 has the same problem. The only difference I'm observing is that accessing .wkt crashes Python this time instead of throwing the OSError.

@sgillies, should Shapely raise an error when the user tries to create a Multi* geometry with an empty component, since asking for the WKT of such a geometry crashes the interpreter? That seems like something we'd want to guard against at all costs. We could also remove empty parts while creating the geometry and print a warning (or not). I would appreciate your thoughts on ideal behavior.

The failing WKT might be a GEOS bug.

@jorisvandenbossche, it's a segfault so I bet it's coming from GEOS and is worth reporting back there. I still think it warrants some preventative action from Shapely, though.

I reported it in the meantime: https://github.com/libgeos/geos/issues/305

I still think it warrants some preventative action from Shapely, though.

For sure! The question might be if Shapely should raise an error upon creation, or when converting to WKT.

It's a good question, and I wasn't sure of the right fix myself. I guess stopping users from making geometries with empty parts might be a little heavy-handed, but my reasoning is that you can't use Shapely to create a multipart with an empty component using WKT, WKB, or GeoJSON (through the shape adapters) as those inputs are invalid, so this felt like closing the loop there, as it were - forcing consistency across all geometry creation interfaces.

I'd like to avoid too much validation, because it's expensive, but in this case I think filtering out empty parts and warning that this has been done is a good approach. Warn instead of log, because user code could handle the warning and change its behavior if desired.

Was this page helpful?
0 / 5 - 0 ratings