Fixed #25873 -- Made GEOSGeometry handle the srid parameter more predictably.

This commit is contained in:
Sergey Fedoseev 2017-03-30 18:38:26 +05:00 committed by Tim Graham
parent 068d75688f
commit 6ecccad711
4 changed files with 41 additions and 8 deletions

View File

@ -35,7 +35,7 @@ class BaseGeometryWidget(Widget):
def deserialize(self, value):
try:
return GEOSGeometry(value, self.map_srid)
return GEOSGeometry(value)
except (GEOSException, ValueError) as err:
logger.error("Error creating geometry from value '%s' (%s)", value, err)
return None
@ -48,7 +48,7 @@ class BaseGeometryWidget(Widget):
if value:
# Check that srid of value and map match
if value.srid != self.map_srid:
if value.srid and value.srid != self.map_srid:
try:
ogr = value.ogr
ogr.transform(self.map_srid)

View File

@ -46,6 +46,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
The `srid` keyword is used to specify the Source Reference Identifier
(SRID) number for this Geometry. If not set, the SRID will be None.
"""
input_srid = None
if isinstance(geo_input, bytes):
geo_input = force_text(geo_input)
if isinstance(geo_input, str):
@ -53,7 +54,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
if wkt_m:
# Handling WKT input.
if wkt_m.group('srid'):
srid = int(wkt_m.group('srid'))
input_srid = int(wkt_m.group('srid'))
g = wkt_r().read(force_bytes(wkt_m.group('wkt')))
elif hex_regex.match(geo_input):
# Handling HEXEWKB input.
@ -75,14 +76,17 @@ class GEOSGeometry(GEOSBase, ListMixin):
# Invalid geometry type.
raise TypeError('Improper geometry input type: %s' % type(geo_input))
if g:
# Setting the pointer object with a valid pointer.
self.ptr = g
else:
if not g:
raise GEOSException('Could not initialize GEOS Geometry with given input.')
input_srid = input_srid or capi.geos_get_srid(g) or None
if input_srid and srid and input_srid != srid:
raise ValueError('Input geometry already has SRID: %d.' % input_srid)
# Setting the pointer object with a valid pointer.
self.ptr = g
# Post-initialization setup.
self._post_init(srid)
self._post_init(input_srid or srid)
def _post_init(self, srid):
"Perform post-initialization setup."

View File

@ -194,6 +194,27 @@ This is the base class for all GEOS geometry objects. It initializes on the
given ``geo_input`` argument, and then assumes the proper geometry subclass
(e.g., ``GEOSGeometry('POINT(1 1)')`` will create a :class:`Point` object).
The ``srid`` parameter, if given, is set as the SRID of the created geometry if
``geo_input`` doesn't have an SRID. If different SRIDs are provided through the
``geo_input`` and ``srid`` parameters, ``ValueError`` is raised::
>>> from django.contrib.gis.geos import GEOSGeometry
>>> GEOSGeometry('POINT EMPTY', srid=4326).ewkt
'SRID=4326;POINT EMPTY'
>>> GEOSGeometry('SRID=4326;POINT EMPTY', srid=4326).ewkt
'SRID=4326;POINT EMPTY'
>>> GEOSGeometry('SRID=1;POINT EMPTY', srid=4326)
Traceback (most recent call last):
...
ValueError: Input geometry already has SRID: 1.
.. versionchanged:: 2.0
In older versions, the ``srid`` parameter is handled differently for WKT
and WKB input. For WKT, ``srid`` is used only if the input geometry doesn't
have an SRID. For WKB, ``srid`` (if given) replaces the SRID of the input
geometry.
The following input formats, along with their corresponding Python types,
are accepted:

View File

@ -708,6 +708,14 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
pnt_wo_srid = Point(1, 1)
pnt_wo_srid.srid = pnt_wo_srid.srid
# Input geometries that have an SRID.
self.assertEqual(GEOSGeometry(pnt.ewkt, srid=pnt.srid).srid, pnt.srid)
self.assertEqual(GEOSGeometry(pnt.ewkb, srid=pnt.srid).srid, pnt.srid)
with self.assertRaisesMessage(ValueError, 'Input geometry already has SRID: %d.' % pnt.srid):
GEOSGeometry(pnt.ewkt, srid=1)
with self.assertRaisesMessage(ValueError, 'Input geometry already has SRID: %d.' % pnt.srid):
GEOSGeometry(pnt.ewkb, srid=1)
@skipUnless(HAS_GDAL, "GDAL is required.")
def test_custom_srid(self):
"""Test with a null srid and a srid unknown to GDAL."""