[python-shapely] 03/14: Imported Upstream version 1.5.14
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Mon Mar 28 11:57:00 UTC 2016
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository python-shapely.
commit 6a71eda8077b03244a9327c73ece5336b1ef9c50
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Mon Mar 28 11:37:18 2016 +0200
Imported Upstream version 1.5.14
---
CHANGES.txt | 17 +++++++++
CREDITS.txt | 74 ++++++++++++++++++++------------------
shapely/__init__.py | 2 +-
shapely/ctypes_declarations.py | 3 ++
shapely/geometry/base.py | 4 +--
shapely/geometry/multipolygon.py | 37 +++++++++++--------
shapely/geometry/polygon.py | 5 +++
shapely/geos.py | 76 ++++++++++++++--------------------------
shapely/strtree.py | 2 ++
tests/test_empty_polygons.py | 22 ++++++++++++
tests/test_linestring.py | 22 ++++++++++++
tests/test_polygon.py | 15 ++++++++
tests/test_strtree.py | 29 ++++++++++++++-
tests/test_wkt.py | 34 ++++++++++++++++++
14 files changed, 239 insertions(+), 103 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index e353755..274267f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,23 @@
Changes
=======
+1.5.14 (2016-03-27)
+-------------------
+- Bug fix: use ``type()`` instead of ``isinstance()`` when evaluating geometry
+ equality, preventing instances of base and derived classes from
+ being mistaken for equals (#317).
+- Bug fix: ensure that empty geometries are created when constructors have no
+ args (#332, #333).
+- Bug fix: support app "freezing" better on Windows by not relying on the
+ ``__file__`` attribute (#342, #377).
+- Bug fix: ensure that empty polygons evaluate to be ``==`` (#355).
+- Bug fix: use uintptr_t to store pointers instead of long in _geos.pxi,
+ preventing an overflow error (#372, #373).
+- Bug fix: filter out empty geometries that can cause segfaults when creating
+ and loading STRtrees (#345, #348).
+- Bug fix: no longer attempt to reuse GEOS DLLs already loaded by Rasterio
+ or Fiona on OS X (#374, #375).
+
1.5.13 (2015-10-09)
-------------------
- Restore setup and runtime discovery and loading of GEOS shared library to
diff --git a/CREDITS.txt b/CREDITS.txt
index b328cf5..853c953 100644
--- a/CREDITS.txt
+++ b/CREDITS.txt
@@ -3,40 +3,46 @@ Credits
Shapely is written by:
-* Sean Gillies
-* Aron Bierbaum
-* Kai Lautaportti
-* Oliver Tonnhofer
-
-Patches contributed by:
-
-* Allan Adair (https://github.com/allanadair)
-* Joshua Arnott (https://github.com/snorfalorpagus)
-* David Baumgold (https://github.com/singingwolfboy)
-* Howard Butler
-* Gabi Davar (https://github.com/mindw)
-* Phil Elson (https://github.com/pelson)
-* Johan Euphrosine (https://github.com/proppy)
-* Bertrand Gervais (https://github.com/BertrandGervais)
-* Marc Jansen (https://github.com/marcjansen)
-* Kelsey Jordahl (https://github.com/kjordahl)
-* Frédéric Junod
-* Thomas Kluyver (https://github.com/takluyver)
-* William Kyngesburye (https://github.com/kyngchaos)
-* Eric Lemoine
-* Naveen Michaud-Agrawal (https://github.com/nmichaud)
-* om-henners (https://github.com/om-henners)
-* psagers https://github.com/psagers
-* Jeethu Rao (https://github.com/jeethu)
-* Benjamin Root (https://github.com/WeatherGod)
-* Jason Sanford (https://github.com/JasonSanford)
-* Johannes Schönberger (https://github.com/ahojnnes)
-* Jonathan Tartley
-* Kristian Thy
-* Mike Toews (https://github.com/mwtoews)
-* Maarten Vermeyen (https://github.com/maarten-vermeyen)
-* Jacob Wasserman (https://github.com/jwass)
-* Brandon Wood (https://github.com/woodb)
+* Sean Gillies <sean.gillies at gmail.com>
+* Oliver Tonnhofer <olt at bogosoft.com>
+* Mike Toews <mwtoews at gmail.com>
+* Joshua Arnott <josh at snorfalorpagus.net>
+* Jacob Wasserman <jwasserman at gmail.com>
+* Aron Bierbaum <aronbierbaum at gmail.com>
+* Johannes Schönberger <jschoenberger at demuc.de>
+* Phil Elson <pelson.pub at gmail.com>
+* Howard Butler <hobu.inc at gmail.com>
+* dokai <dokai at b426a367-1105-0410-b9ff-cdf4ab011145>
+* Gabi Davar <grizzly.nyo at gmail.com>
+* Kelsey Jordahl <kjordahl at enthought.com>
+* Dave Collins <dave at hopest.net>
+* Jinkun Wang <mejkunw at gmail.com>
+* Marc Jansen <jansen at terrestris.de>
+* Henry Walshaw <henry.walshaw at gmail.com>
+* David Baumgold <david at davidbaumgold.com>
+* Sampo Syrjanen <sampo.syrjanen at here.com>
+* Steve M. Kim <steve at climate.com>
+* Thomas Kluyver <takowl at gmail.com>
+* Brad Hards <bradh at frogmouth.net>
+* Allan Adair <allan.m.adair at gmail.com>
+* fredj <frederic.junod at camptocamp.com>
+* Naveen Michaud-Agrawal <naveen.michaudagrawal at gmail.com>
+* Peter Sagerson <psagers.github at ignorare.net>
+* BertrandGervais <bertrand.gervais.pro at gmail.com>
+* Jeethu Rao <jeethu at jeethurao.com>
+* Jason Sanford <jason.sanford at mapmyfitness.com>
+* Brandon Wood <btwood at geometeor.com>
+* Stephan Hügel <urschrei at gmail.com>
+* Johan Euphrosine <proppy at aminche.com>
+* mindw <grizzly.nyo at gmail.com>
+* James Spencer <james.s.spencer at gmail.com>
+* Benjamin Root <ben.v.root at gmail.com>
+* Leandro Lima <leandro at limaesilva.com.br>
+* Maarten Vermeyen <maarten.vermeyen at rwo.vlaanderen.be>
+* Tobias Sauerwein <tobias.sauerwein at camptocamp.com>
+* James Douglass <jamesdouglassusa at gmail.com>
+* Morris Tweed <tweed.morris at gmail.com>]
+* WANG Aiyong <gepcelway at gmail.com>
See also: https://github.com/Toblerity/Shapely/graphs/contributors.
diff --git a/shapely/__init__.py b/shapely/__init__.py
index 1d51ed9..0240f96 100644
--- a/shapely/__init__.py
+++ b/shapely/__init__.py
@@ -1 +1 @@
-__version__ = "1.5.13"
+__version__ = "1.5.14"
diff --git a/shapely/ctypes_declarations.py b/shapely/ctypes_declarations.py
index ac38fc5..4716212 100644
--- a/shapely/ctypes_declarations.py
+++ b/shapely/ctypes_declarations.py
@@ -159,6 +159,9 @@ def prototype(lgeos, geos_version):
lgeos.GEOSGeom_createCollection.restype = c_void_p
lgeos.GEOSGeom_createCollection.argtypes = [c_int, c_void_p, c_uint]
+ lgeos.GEOSGeom_createEmptyCollection.restype = c_void_p
+ lgeos.GEOSGeom_createEmptyCollection.argtypes = [c_int]
+
lgeos.GEOSGeom_clone.restype = c_void_p
lgeos.GEOSGeom_clone.argtypes = [c_void_p]
diff --git a/shapely/geometry/base.py b/shapely/geometry/base.py
index 42d821f..2696a3b 100644
--- a/shapely/geometry/base.py
+++ b/shapely/geometry/base.py
@@ -263,7 +263,7 @@ class BaseGeometry(object):
def __eq__(self, other):
return (
- isinstance(other, self.__class__) and
+ type(other) == type(self) and
tuple(self.coords) == tuple(other.coords)
)
@@ -765,7 +765,7 @@ class BaseMultipartGeometry(BaseGeometry):
def __eq__(self, other):
return (
- isinstance(other, self.__class__) and
+ type(other) == type(self) and
len(self) == len(other) and
all(x == y for x, y in zip(self, other))
)
diff --git a/shapely/geometry/multipolygon.py b/shapely/geometry/multipolygon.py
index eedd410..55e69ee 100644
--- a/shapely/geometry/multipolygon.py
+++ b/shapely/geometry/multipolygon.py
@@ -146,19 +146,24 @@ def geos_multipolygon_from_py(ob):
return (lgeos.GEOSGeom_createCollection(6, subs, L), N)
-def geos_multipolygon_from_polygons(ob):
+def geos_multipolygon_from_polygons(arg):
"""
ob must be either a MultiPolygon, sequence or array of sequences
or arrays.
"""
- if isinstance(ob, MultiPolygon):
- return geos_geom_from_py(ob)
+ if isinstance(arg, MultiPolygon):
+ return geos_geom_from_py(arg)
- obs = getattr(ob, 'geoms', None) or ob
+ obs = getattr(arg, 'geoms', arg)
+ obs = [ob for ob in obs
+ if ob and not (isinstance(ob, polygon.Polygon) and ob.is_empty)]
L = len(obs)
- assert L >= 1
-
+
+ # Bail immediately if we have no input points.
+ if L <= 0:
+ return (lgeos.GEOSGeom_createEmptyCollection(6), 3)
+
exemplar = obs[0]
try:
N = len(exemplar[0][0])
@@ -168,16 +173,18 @@ def geos_multipolygon_from_polygons(ob):
assert N == 2 or N == 3
subs = (c_void_p * L)()
- for l in range(L):
- shell = getattr(obs[l], 'exterior', None)
- if shell is None:
- shell = obs[l][0]
- holes = getattr(obs[l], 'interiors', None)
- if holes is None:
- holes = obs[l][1]
+
+ for i, ob in enumerate(obs):
+ if isinstance(ob, polygon.Polygon):
+ shell = ob.exterior
+ holes = ob.interiors
+ else:
+ shell = ob[0]
+ holes = ob[1]
+
geom, ndims = polygon.geos_polygon_from_py(shell, holes)
- subs[l] = cast(geom, c_void_p)
-
+ subs[i] = cast(geom, c_void_p)
+
return (lgeos.GEOSGeom_createCollection(6, subs, L), N)
# Test runner
diff --git a/shapely/geometry/polygon.py b/shapely/geometry/polygon.py
index 945a108..91f33fc 100644
--- a/shapely/geometry/polygon.py
+++ b/shapely/geometry/polygon.py
@@ -251,6 +251,11 @@ class Polygon(BaseGeometry):
def __eq__(self, other):
if not isinstance(other, Polygon):
return False
+ check_empty = (self.is_empty, other.is_empty)
+ if all(check_empty):
+ return True
+ elif any(check_empty):
+ return False
my_coords = [
tuple(self.exterior.coords),
[tuple(interior.coords) for interior in self.interiors]
diff --git a/shapely/geos.py b/shapely/geos.py
index 976173b..f4b7cf9 100644
--- a/shapely/geos.py
+++ b/shapely/geos.py
@@ -69,59 +69,31 @@ if sys.platform.startswith('linux'):
free.restype = None
elif sys.platform == 'darwin':
- # First: have we already loaded GEOS through a Fiona or Rasterio?
- # If so, let's obtain a handle to it instead of loading this module's
- # copy to side step the mysterious issue described at
- # https://github.com/Toblerity/Shapely/issues/324.
- geos_mod = sys.modules.get('fiona') or sys.modules.get('rasterio')
- if geos_mod:
- dll_path = os.path.join(
- os.path.dirname(geos_mod.__file__), '.dylibs',
- 'libgeos_c.1.dylib')
- try:
- _lgeos = CDLL(dll_path, mode=(DEFAULT_MODE | 16))
- except OSError:
- LOG.debug("GEOS DLL in fiona or rasterio .dylibs not found.")
+ # Test to see if we have a delocated wheel with a GEOS dylib.
+ geos_whl_dylib = os.path.abspath(os.path.join(os.path.dirname(
+ __file__), '.dylibs/libgeos_c.1.dylib'))
+ if os.path.exists(geos_whl_dylib):
+ _lgeos = CDLL(geos_whl_dylib)
+ LOG.debug("Found GEOS DLL: %r, using it.", _lgeos)
+
+ else:
+ if hasattr(sys, 'frozen'):
+ try:
+ # .app file from py2app
+ alt_paths = [os.path.join(os.environ['RESOURCEPATH'],
+ '..', 'Frameworks', 'libgeos_c.dylib')]
+ except KeyError:
+ # binary from pyinstaller
+ alt_paths = [
+ os.path.join(sys.executable, 'libgeos_c.dylib')]
+ else:
alt_paths = [
# The Framework build from Kyng Chaos
"/Library/Frameworks/GEOS.framework/Versions/Current/GEOS",
# macports
'/opt/local/lib/libgeos_c.dylib',
]
- _lgeos = load_dll('geos_c', fallbacks=alt_paths,
- mode=(DEFAULT_MODE | 16))
- if _lgeos:
- LOG.debug("Found %r already loaded, using it.", _lgeos)
-
- # If neither fiona nor rasterio have been imported, or if the block
- # above failed to assign _lgeos, we will locate and load the GEOS
- # DLL.
- if not _lgeos:
- # Test to see if we have a delocated wheel with a GEOS dylib.
- geos_whl_dylib = os.path.abspath(os.path.join(os.path.dirname(
- __file__), '.dylibs/libgeos_c.1.dylib'))
- if os.path.exists(geos_whl_dylib):
- _lgeos = CDLL(geos_whl_dylib)
- LOG.debug("Found GEOS DLL: %r, using it.", _lgeos)
-
- else:
- if hasattr(sys, 'frozen'):
- try:
- # .app file from py2app
- alt_paths = [os.path.join(os.environ['RESOURCEPATH'],
- '..', 'Frameworks', 'libgeos_c.dylib')]
- except KeyError:
- # binary from pyinstaller
- alt_paths = [
- os.path.join(sys.executable, 'libgeos_c.dylib')]
- else:
- alt_paths = [
- # The Framework build from Kyng Chaos
- "/Library/Frameworks/GEOS.framework/Versions/Current/GEOS",
- # macports
- '/opt/local/lib/libgeos_c.dylib',
- ]
- _lgeos = load_dll('geos_c', fallbacks=alt_paths)
+ _lgeos = load_dll('geos_c', fallbacks=alt_paths)
free = load_dll('c').free
free.argtypes = [c_void_p]
@@ -129,9 +101,13 @@ elif sys.platform == 'darwin':
elif sys.platform == 'win32':
try:
- egg_dlls = os.path.abspath(os.path.join(os.path.dirname(__file__),
- "DLLs"))
- wininst_dlls = os.path.abspath(os.__file__ + "../../../DLLs")
+ egg_dlls = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), 'DLLs'))
+ if hasattr(sys, "frozen"):
+ wininst_dlls = os.path.normpath(
+ os.path.abspath(sys.executable+'../../DLLS'))
+ else:
+ wininst_dlls = os.path.abspath(os.__file__ + "../../../DLLs")
original_path = os.environ['PATH']
os.environ['PATH'] = "%s;%s;%s" % \
(egg_dlls, wininst_dlls, original_path)
diff --git a/shapely/strtree.py b/shapely/strtree.py
index 3c0235e..7abe685 100644
--- a/shapely/strtree.py
+++ b/shapely/strtree.py
@@ -31,6 +31,8 @@ class STRtree:
"""
def __init__(self, geoms):
+ # filter empty geometries out of the input
+ geoms = [geom for geom in geoms if not geom.is_empty]
self._n_geoms = len(geoms)
# GEOS STRtree capacity has to be > 1
self._tree_handle = lgeos.GEOSSTRtree_create(max(2, len(geoms)))
diff --git a/tests/test_empty_polygons.py b/tests/test_empty_polygons.py
new file mode 100644
index 0000000..89f42e7
--- /dev/null
+++ b/tests/test_empty_polygons.py
@@ -0,0 +1,22 @@
+from shapely.geometry import MultiPolygon, Point, Polygon
+
+
+def test_empty_polygon():
+ """No constructor arg makes an empty polygon geometry."""
+ assert Polygon().is_empty
+
+
+def test_empty_multipolygon():
+ """No constructor arg makes an empty multipolygon geometry."""
+ assert MultiPolygon().is_empty
+
+
+def test_multipolygon_empty_polygon():
+ """An empty polygon passed to MultiPolygon() makes an empty
+ multipolygon geometry."""
+ assert MultiPolygon([Polygon()]).is_empty
+
+
+def test_multipolygon_empty_among_polygon():
+ """An empty polygon passed to MultiPolygon() is ignored."""
+ assert len(MultiPolygon([Point(0,0).buffer(1.0), Polygon()])) == 1
diff --git a/tests/test_linestring.py b/tests/test_linestring.py
index d7c7d4e..2c50a5b 100644
--- a/tests/test_linestring.py
+++ b/tests/test_linestring.py
@@ -57,6 +57,28 @@ class LineStringTestCase(unittest.TestCase):
l_null.coords = [(0, 0), (1, 1)]
self.assertAlmostEqual(l_null.length, 1.4142135623730951)
+ def test_equals_argument_order(self):
+ """
+ Test equals predicate functions correctly regardless of the order
+ of the inputs. See issue #317.
+ """
+ coords = ((0, 0), (1, 0), (1, 1), (0, 0))
+ ls = LineString(coords)
+ lr = LinearRing(coords)
+
+ self.assertFalse(ls.__eq__(lr)) # previously incorrectly returned True
+ self.assertFalse(lr.__eq__(ls))
+ self.assertFalse(ls == lr)
+ self.assertFalse(lr == ls)
+
+ ls_clone = LineString(coords)
+ lr_clone = LinearRing(coords)
+
+ self.assertTrue(ls.__eq__(ls_clone))
+ self.assertTrue(lr.__eq__(lr_clone))
+ self.assertTrue(ls == ls_clone)
+ self.assertTrue(lr == lr_clone)
+
def test_from_linestring(self):
line = LineString(((1.0, 2.0), (3.0, 4.0)))
diff --git a/tests/test_polygon.py b/tests/test_polygon.py
index 2d07a3a..84532b1 100644
--- a/tests/test_polygon.py
+++ b/tests/test_polygon.py
@@ -210,6 +210,21 @@ class PolygonTestCase(unittest.TestCase):
ec = list(p.buffer(1).boundary.coords)
self.assertIsInstance(ec, list) # TODO: this is a poor test
+ def test_empty_equality(self):
+ # Test equals operator, including empty geometries
+ # see issue #338
+
+ point1 = Point(0, 0)
+ polygon1 = Polygon(((0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)))
+ polygon2 = Polygon(((0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)))
+ polygon_empty1 = Polygon()
+ polygon_empty2 = Polygon()
+
+ self.assertNotEqual(point1, polygon1)
+ self.assertEqual(polygon_empty1, polygon_empty2)
+ self.assertNotEqual(polygon1, polygon_empty1)
+ self.assertEqual(polygon1, polygon2)
+ self.assertNotEqual(None, polygon_empty1)
def test_suite():
return unittest.TestLoader().loadTestsFromTestCase(PolygonTestCase)
diff --git a/tests/test_strtree.py b/tests/test_strtree.py
index 7de3921..372a987 100644
--- a/tests/test_strtree.py
+++ b/tests/test_strtree.py
@@ -1,7 +1,7 @@
from . import unittest
from shapely.strtree import STRtree
-from shapely.geometry import Point
+from shapely.geometry import Point, Polygon
from shapely.geos import geos_version
@@ -15,6 +15,33 @@ class STRTestCase(unittest.TestCase):
results = tree.query(Point(2,2).buffer(1.0))
self.assertEqual(len(results), 3)
+ def test_insert_empty_geometry(self):
+ """
+ Passing nothing but empty geometries results in an empty strtree.
+ The query segfaults if the empty geometry was actually inserted.
+ """
+ empty = Polygon()
+ geoms = [empty]
+ tree = STRtree(geoms)
+ assert(tree._n_geoms == 0)
+ query = Polygon([(0,0),(1,1),(2,0),(0,0)])
+ results = tree.query(query)
+
+ def test_query_empty_geometry(self):
+ """
+ Empty geometries should be filtered out.
+ The query segfaults if the empty geometry was actually inserted.
+ """
+ empty = Polygon()
+ point = Point(1, 0.5)
+ geoms = [empty, point]
+ tree = STRtree(geoms)
+ assert(tree._n_geoms == 1)
+ query = Polygon([(0,0),(1,1),(2,0),(0,0)])
+ results = tree.query(query)
+ self.assertEqual(len(results), 1)
+ self.assertEqual(results[0], point)
+
def test_suite():
return unittest.TestLoader().loadTestsFromTestCase(STRTestCase)
diff --git a/tests/test_wkt.py b/tests/test_wkt.py
new file mode 100644
index 0000000..945cb14
--- /dev/null
+++ b/tests/test_wkt.py
@@ -0,0 +1,34 @@
+from math import pi
+
+import pytest
+
+from shapely.geometry import LineString, Point
+from shapely.wkt import dumps
+
+
+ at pytest.fixture(scope="module")
+def pipi():
+ return Point((pi, -pi))
+
+
+ at pytest.fixture(scope="module")
+def pipi4():
+ return Point((pi*4, -pi*4))
+
+
+def test_wkt(pipi):
+ """.wkt and wkt.dumps() both do not trim by default."""
+ assert pipi.wkt == "POINT ({0:.16f} {1:.16f})".format(pi, -pi)
+
+
+def test_wkt(pipi4):
+ """.wkt and wkt.dumps() both do not trim by default."""
+ assert pipi4.wkt == "POINT ({0:.16f} {1:.16f})".format(pi*4, -pi*4)
+
+
+def test_dumps(pipi4):
+ assert dumps(pipi4) == "POINT ({0:.16f} {1:.16f})".format(pi*4, -pi*4)
+
+
+def test_dumps_precision(pipi4):
+ assert dumps(pipi4, rounding_precision=4) == "POINT ({0:.4f} {1:.4f})".format(pi*4, -pi*4)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/python-shapely.git
More information about the Pkg-grass-devel
mailing list