Skip to content

Make base objects hashable, use it for equality check, and include srid #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions postgis/geometry.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import warnings

from .ewkb import Reader, Typed, Writer
from .geojson import GeoJSON

try:
# Do not make psycopg2 a requirement.
from psycopg2.extensions import ISQLQuote
except ImportError:
warnings.warn('psycopg2 not installed', ImportWarning)


from .ewkb import Reader, Typed, Writer
from .geojson import GeoJSON


class Geometry(object, metaclass=Typed):
Expand Down Expand Up @@ -56,9 +57,13 @@ def __repr__(self):
return '<{} {}>'.format(self.__class__.__name__, self.wkt)

def __eq__(self, other):
if isinstance(other, self.__class__):
other = other.coords
return self.coords == other
return hash(self) == hash(other)

def __hash__(self):
values = self.coords
if self.srid:
values = values + (self.srid,)
return hash(values)

@property
def name(self):
Expand Down
7 changes: 3 additions & 4 deletions postgis/geometrycollection.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
from .geometry import Geometry
from .geojson import GeoJSON
from .geometry import Geometry


class GeometryCollection(Geometry):

TYPE = 7

def __init__(self, geoms, srid=None):
def __init__(self, geoms, srid=0):
for geom in geoms:
if not isinstance(geom, Geometry):
raise ValueError('{} is not instance of Geometry'.format(geom))
self.geoms = list(geoms)
if srid:
self.srid = srid
self.srid = srid

def __iter__(self):
return self.geoms.__iter__()
Expand Down
12 changes: 6 additions & 6 deletions postgis/multi.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from .geometry import Geometry
from .point import Point


class Multi(Geometry):

__slots__ = ['geoms', 'srid']
__slots__ = ["geoms", "srid"]
SUBCLASS = None

def __init__(self, geoms, srid=None):
def __init__(self, geoms, srid=0):
self.geoms = [self.SUBCLASS(g, srid=srid) for g in geoms]
if srid:
self.srid = srid
self.srid = srid

def __iter__(self):
return iter(self.geoms)
Expand All @@ -31,8 +31,8 @@ def from_ewkb_body(cls, reader, srid=None):

@property
def wkt_coords(self):
fmt = '{}' if self.SUBCLASS == Point else '({})'
return ', '.join(fmt.format(g.wkt_coords) for g in self)
fmt = "{}" if self.SUBCLASS == Point else "({})"
return ", ".join(fmt.format(g.wkt_coords) for g in self)

def write_ewkb_body(self, writer):
writer.write_int(len(self.geoms))
Expand Down
5 changes: 2 additions & 3 deletions postgis/point.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Point(Geometry):
__slots__ = ['x', 'y', 'z', 'm', 'srid']
TYPE = 1

def __init__(self, x, y=None, z=None, m=None, srid=None):
def __init__(self, x, y=None, z=None, m=None, srid=0):
if y is None and isinstance(x, (tuple, list)):
x, y, *extra = x
if extra:
Expand All @@ -17,8 +17,7 @@ def __init__(self, x, y=None, z=None, m=None, srid=None):
self.y = float(y)
self.z = float(z) if z is not None else None
self.m = float(m) if m is not None else None
if srid is not None:
self.srid = srid
self.srid = srid

def __getitem__(self, item):
if item in (0, 'x'):
Expand Down
10 changes: 10 additions & 0 deletions tests/test_linestring.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,13 @@ def test_geom_should_compare_with_coords():
def test_linestring_get_item():
line = LineString(((30, 10), (10, 30), (40, 40)))
assert line[0] == (30, 10)


def test_linestring_is_hashable():
l1 = LineString(((1, 2), (3, 4)))
l2 = LineString(((1, 2), (3, 4)))
l3 = LineString(((3, 4), (5, 6)))
assert {l1, l2, l3} == {l1, l3}
l1 = LineString(((1, 2), (3, 4)), srid=4326)
l2 = LineString(((1, 2), (3, 4)), srid=3857)
assert len({l1, l2}) == 2
10 changes: 10 additions & 0 deletions tests/test_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,13 @@ def test_0_as_m_is_considered():
assert point.y == 2.0
assert point.z == 3
assert point.m == 0


def test_point_is_hashable():
p1 = Point(1, 1)
p2 = Point(1, 1)
p3 = Point(2, 2)
assert {p1, p2, p3} == {p1, p3}
p1 = Point(1, 1, srid=4326)
p2 = Point(1, 1, srid=3857)
assert len({p1, p2}) == 2
32 changes: 26 additions & 6 deletions tests/test_polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,38 @@


def test_geom_should_compare_with_coords():
assert (((35, 10), (45, 45), (15, 40), (10, 20), (35, 10)), ((20, 30), (35, 35), (30, 20), (20, 30))) == Polygon((((35, 10), (45, 45), (15, 40), (10, 20), (35, 10)), ((20, 30), (35, 35), (30, 20), (20, 30)))) # noqa
assert (
((35, 10), (45, 45), (15, 40), (10, 20), (35, 10)),
((20, 30), (35, 35), (30, 20), (20, 30)),
) == Polygon(
(
((35, 10), (45, 45), (15, 40), (10, 20), (35, 10)),
((20, 30), (35, 35), (30, 20), (20, 30)),
)
) # noqa


def test_polygon_geojson():
poly = Polygon((((1, 2), (3, 4), (5, 6), (1, 2)),))
assert poly.geojson == {"type": "Polygon",
"coordinates": (((1, 2), (3, 4), (5, 6), (1, 2)),)}
assert poly.geojson == {
"type": "Polygon",
"coordinates": (((1, 2), (3, 4), (5, 6), (1, 2)),),
}


def test_polygon_wkt():
poly = Polygon((((1, 2), (3, 4), (5, 6), (1, 2)),))
wkt = poly.wkt
wkt = wkt.replace('.0','')
wkt = wkt.replace(', ',',')
assert wkt == 'POLYGON((1 2,3 4,5 6,1 2))'
wkt = wkt.replace(".0", "")
wkt = wkt.replace(", ", ",")
assert wkt == "POLYGON((1 2,3 4,5 6,1 2))"


def test_polygon_is_hashable():
p1 = Polygon((((1, 2), (3, 4), (5, 6), (1, 2)),))
p2 = Polygon((((1, 2), (3, 4), (5, 6), (1, 2)),))
p3 = Polygon((((1, 2), (3, 4), (6, 7), (1, 2)),))
assert {p1, p2, p3} == {p1, p3}
p1 = Polygon((((1, 2), (3, 4), (5, 6), (1, 2)),), srid=4326)
p2 = Polygon((((1, 2), (3, 4), (5, 6), (1, 2)),), srid=3857)
assert len({p1, p2}) == 2