Skip to content

Commit

Permalink
Fixed #26920 -- Made GEOSGeometry equality check consider the srid
Browse files Browse the repository at this point in the history
  • Loading branch information
jackieleng authored and claudep committed Nov 23, 2016
1 parent 10d49b9 commit 50613d9
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 15 deletions.
8 changes: 5 additions & 3 deletions django/contrib/gis/geos/geometry.py
Expand Up @@ -174,12 +174,14 @@ def from_gml(cls, gml_string):
def __eq__(self, other):
"""
Equivalence testing, a Geometry may be compared with another Geometry
or a WKT representation.
or an EWKT representation.
"""
if isinstance(other, six.string_types):
return self.wkt == other
if other.startswith('SRID=0;'):
return self.ewkt == other[7:] # Test only WKT part of other
return self.ewkt == other
elif isinstance(other, GEOSGeometry):
return self.equals_exact(other)
return self.srid == other.srid and self.equals_exact(other)
else:
return False

Expand Down
10 changes: 9 additions & 1 deletion docs/ref/contrib/gis/geos.txt
Expand Up @@ -160,15 +160,23 @@ Geometries support set-like operators::
The :class:`~GEOSGeometry` equality operator uses
:meth:`~GEOSGeometry.equals_exact`, not :meth:`~GEOSGeometry.equals`, i.e.
it requires the compared geometries to have the same coordinates in the
same positions::
same positions with the same SRIDs::

>>> from django.contrib.gis.geos import LineString
>>> ls1 = LineString((0, 0), (1, 1))
>>> ls2 = LineString((1, 1), (0, 0))
>>> ls3 = LineString((1, 1), (0, 0), srid=4326)
>>> ls1.equals(ls2)
True
>>> ls1 == ls2
False
>>> ls3 == ls2 # different SRIDs
False

.. versionchanged:: 1.11

Older versions didn't check the ``srid`` when comparing
``GEOSGeometry`` objects using the equality operator.

Geometry Objects
================
Expand Down
2 changes: 2 additions & 0 deletions docs/releases/1.11.txt
Expand Up @@ -423,6 +423,8 @@ Backwards incompatible changes in 1.11
the Google Maps API and seems to be unmaintained. If you're using it, `let
us know <https://code.djangoproject.com/ticket/14284>`_.

* The ``GEOSGeometry`` equality operator now also compares SRID.

Database backend API
--------------------

Expand Down
2 changes: 1 addition & 1 deletion tests/gis_tests/geoapp/test_functions.py
Expand Up @@ -266,7 +266,7 @@ def test_make_valid(self):
State.objects.create(name='invalid', poly=invalid_geom)
invalid = State.objects.filter(name='invalid').annotate(repaired=functions.MakeValid('poly')).first()
self.assertIs(invalid.repaired.valid, True)
self.assertEqual(invalid.repaired, fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'))
self.assertEqual(invalid.repaired, fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', srid=invalid.poly.srid))

@skipUnlessDBFeature("has_MemSize_function")
def test_memsize(self):
Expand Down
11 changes: 7 additions & 4 deletions tests/gis_tests/geoapp/tests.py
Expand Up @@ -63,9 +63,9 @@ def test_proxy(self):
nullcity.point.x = 23
nullcity.point.y = 5
# Checking assignments pre & post-save.
self.assertNotEqual(Point(23, 5), City.objects.get(name='NullCity').point)
self.assertNotEqual(Point(23, 5, srid=4326), City.objects.get(name='NullCity').point)
nullcity.save()
self.assertEqual(Point(23, 5), City.objects.get(name='NullCity').point)
self.assertEqual(Point(23, 5, srid=4326), City.objects.get(name='NullCity').point)
nullcity.delete()

# Testing on a Polygon
Expand Down Expand Up @@ -479,8 +479,11 @@ def test_diff_intersection_union(self):
# SpatiaLite).
pass
else:
self.assertEqual(c.mpoly.difference(geom), c.difference)
if not spatialite:
if spatialite:
# Spatialite `difference` doesn't have an SRID
self.assertEqual(c.mpoly.difference(geom).wkt, c.difference.wkt)
else:
self.assertEqual(c.mpoly.difference(geom), c.difference)
self.assertEqual(c.mpoly.intersection(geom), c.intersection)
# Ordering might differ in collections
self.assertSetEqual(set(g.wkt for g in c.mpoly.sym_difference(geom)),
Expand Down
21 changes: 21 additions & 0 deletions tests/gis_tests/geos_tests/test_geos.py
Expand Up @@ -227,6 +227,27 @@ def test_eq(self):
self.assertNotEqual(g, {'foo': 'bar'})
self.assertNotEqual(g, False)

def test_eq_with_srid(self):
"Testing non-equivalence with different srids."
p0 = Point(5, 23)
p1 = Point(5, 23, srid=4326)
p2 = Point(5, 23, srid=32632)
# GEOS
self.assertNotEqual(p0, p1)
self.assertNotEqual(p1, p2)
# EWKT
self.assertNotEqual(p0, p1.ewkt)
self.assertNotEqual(p1, p0.ewkt)
self.assertNotEqual(p1, p2.ewkt)
# Equivalence with matching SRIDs
self.assertEqual(p2, p2)
self.assertEqual(p2, p2.ewkt)
# WKT contains no SRID so will not equal
self.assertNotEqual(p2, p2.wkt)
# SRID of 0
self.assertEqual(p0, 'SRID=0;POINT (5 23)')
self.assertNotEqual(p1, 'SRID=0;POINT (5 23)')

def test_points(self):
"Testing Point objects."
prev = fromstr('POINT(0 0)')
Expand Down
2 changes: 1 addition & 1 deletion tests/gis_tests/relatedapp/tests.py
Expand Up @@ -36,7 +36,7 @@ def test02_select_related(self):
nm, st, lon, lat = ref
self.assertEqual(nm, c.name)
self.assertEqual(st, c.state)
self.assertEqual(Point(lon, lat), c.location.point)
self.assertEqual(Point(lon, lat, srid=c.location.point.srid), c.location.point)

@skipUnlessDBFeature("has_transform_method")
def test03_transform_related(self):
Expand Down
15 changes: 10 additions & 5 deletions tests/gis_tests/test_geoforms.py
Expand Up @@ -48,12 +48,17 @@ def test_geom_type(self):
# By default, all geometry types are allowed.
fld = forms.GeometryField()
for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'):
self.assertEqual(GEOSGeometry(wkt), fld.clean(wkt))
# `to_python` uses the SRID of OpenLayersWidget if the converted
# value doesn't have an SRID itself.
self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.clean(wkt))

pnt_fld = forms.GeometryField(geom_type='POINT')
self.assertEqual(GEOSGeometry('POINT(5 23)'), pnt_fld.clean('POINT(5 23)'))
self.assertEqual(GEOSGeometry('POINT(5 23)', srid=pnt_fld.widget.map_srid), pnt_fld.clean('POINT(5 23)'))
# a WKT for any other geom_type will be properly transformed by `to_python`
self.assertEqual(GEOSGeometry('LINESTRING(0 0, 1 1)'), pnt_fld.to_python('LINESTRING(0 0, 1 1)'))
self.assertEqual(
GEOSGeometry('LINESTRING(0 0, 1 1)', srid=pnt_fld.widget.map_srid),
pnt_fld.to_python('LINESTRING(0 0, 1 1)')
)
# but rejected by `clean`
with self.assertRaises(forms.ValidationError):
pnt_fld.clean('LINESTRING(0 0, 1 1)')
Expand All @@ -66,7 +71,7 @@ def test_to_python(self):
fld = forms.GeometryField()
# to_python returns the same GEOSGeometry for a WKT
for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'):
self.assertEqual(GEOSGeometry(wkt), fld.to_python(wkt))
self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.to_python(wkt))
# but raises a ValidationError for any other string
for wkt in ('POINT(5)', 'MULTI POLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'BLAH(0 0, 1 1)'):
with self.assertRaises(forms.ValidationError):
Expand All @@ -78,7 +83,7 @@ class PointForm(forms.Form):

form = PointForm()
cleaned_pt = form.fields['pt'].clean('POINT(5 23)')
self.assertEqual(cleaned_pt, GEOSGeometry('POINT(5 23)'))
self.assertEqual(cleaned_pt, GEOSGeometry('POINT(5 23)', srid=4326))
self.assertEqual(4326, cleaned_pt.srid)

point = GEOSGeometry('SRID=4326;POINT(5 23)')
Expand Down

0 comments on commit 50613d9

Please sign in to comment.