[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