[python-shapely] 01/06: Imported Upstream version 1.6~b1

Bas Couwenberg sebastic at debian.org
Mon Dec 12 17:54:38 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 2f464bb56d88be7005304856db6be8b25f566534
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Mon Dec 12 18:34:38 2016 +0100

    Imported Upstream version 1.6~b1
---
 CHANGES.txt                    |  18 ++++
 README.rst                     |  78 +++++++++--------
 setup.py                       |  21 ++---
 shapely/__init__.py            |   2 +-
 shapely/coords.py              |  21 -----
 shapely/geometry/linestring.py | 154 +++++++++++----------------------
 shapely/geometry/multipoint.py |  67 +++------------
 shapely/geometry/point.py      |  74 +++++-----------
 shapely/geometry/polygon.py    | 190 +++++++++++++++--------------------------
 shapely/speedups/_speedups.pyx |  12 ++-
 tests/test_linestring.py       |   5 ++
 tests/test_ndarrays.py         |   8 +-
 tests/test_point.py            |   5 ++
 tests/test_vectorized.py       |  13 +--
 14 files changed, 250 insertions(+), 418 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 922c051..ffe9922 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,24 @@
 Changes
 =======
 
+1.6b1 (2016-12-12)
+------------------
+
+Bug fixes:
+
+- Implemented __array_interface__ for empty Points and LineStrings (#403).
+
+1.6a3 (2016-12-01)
+------------------
+
+Bug fixes:
+
+- Remove accidental hard requirement of Numpy (#431).
+
+Packaging:
+
+- Put Numpy in an optional requirement set named "vectorized" (#431).
+
 1.6a2 (2016-11-09)
 ------------------
 
diff --git a/README.rst b/README.rst
index 8bbbff9..28d8bfd 100644
--- a/README.rst
+++ b/README.rst
@@ -2,17 +2,16 @@
 Shapely
 =======
 
-Manipulation and analysis of geometric objects in the Cartesian plane.
-
 .. image:: https://travis-ci.org/Toblerity/Shapely.png?branch=master
    :target: https://travis-ci.org/Toblerity/Shapely
 
-.. image:: https://coveralls.io/repos/github/Toblerity/Shapely/badge.svg?branch=master
    :target: https://coveralls.io/github/Toblerity/Shapely?branch=master
 
-.. image:: http://farm3.staticflickr.com/2738/4511827859_b5822043b7_o_d.png
+Manipulation and analysis of geometric objects in the Cartesian plane.
+
+.. image:: https://c2.staticflickr.com/6/5560/31301790086_b3472ea4e9_c.jpg
    :width: 800
-   :height: 400
+   :height: 378
 
 Shapely is a BSD-licensed Python package for manipulation and analysis of
 planar geometric objects. It is based on the widely deployed `GEOS
@@ -28,46 +27,61 @@ but can be readily integrated with packages that are. For more details, see:
 Requirements
 ============
 
-Shapely 1.5.x requires
+Shapely 1.6.x requires
 
 * Python >=2.6 (including Python 3.x)
-* GEOS >=3.3 (Shapely 1.2.x requires only GEOS 3.1 but YMMV)
+* GEOS >=3.3 
 
-Installing Shapely
-==================
+Installing Shapely (1.6b1)
+==========================
 
-Windows users should download an executable installer from
-http://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely or PyPI (if available).
+Windows users have two good installation options: the wheels at
+http://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely and the 
+Anaconda platform's [conda-forge](https://conda-forge.github.io/)
+channel.
 
-On other systems, acquire the GEOS by any means (`brew install geos` on OS X or
-`apt-get install libgeos-dev` on Debian/Ubuntu), make sure that it is on the
-system library path, and install Shapely from the Python package index.
+OS X users can get Shapely wheels with GEOS included from the 
+Python Package Index with a recent version of pip (8+):
 
 .. code-block:: console
 
-    $ pip install shapely
+    $ pip install shapely==1.6b1
 
-If you've installed GEOS to a non-standard location, the geos-config program
-will be used to get compiler and linker options. If it is not on the PATH,
-it can be specified with a GEOS_CONFIG environment variable, e.g.:
+A few extra speedups that require Numpy can be had by running
 
 .. code-block:: console
 
-    $ GEOS_CONFIG=/path/to/geos-config pip install shapely
+    $ pip install shapely[vectorized]==1.6b1
 
-If your system's GEOS version is < 3.3.0 you cannot use Shapely 1.3+ and must
-stick to 1.2.x as shown below.
+If you want to build Shapely from source for compatibility with
+other modules that depend on GEOS (such as cartopy or osgeo.ogr)
+you may ignore the binary wheels.
 
 .. code-block:: console
 
-    $ pip install shapely<1.3
+    $ pip install shapely --no-binary shapely
 
-Or, if you're using pip 6+
+Binary wheels are also available for Linux. To get them, use `pip shapely
+shapely==1.6b1`. To avoid them, use `pip install shapely --no-binary
+shapely==1.6b1`.
+
+In other situations, install `geos_c` libs and headers by any means 
+(for example, `brew install geos` on OS X or
+`apt-get install libgeos-dev` on Debian/Ubuntu) and install Shapely
+from the Python package index.
 
 .. code-block:: console
 
-    $ pip install shapely~=1.2
+    $ pip install shapely
+
+If you've installed GEOS to a standard location, the geos-config program
+will be used to get compiler and linker options. If geos-config is not on
+your executable, it can be specified with a GEOS_CONFIG environment
+variable, e.g.:
+
+.. code-block:: console
 
+    $ GEOS_CONFIG=/path/to/geos-config pip install shapely
 Shapely is also provided by popular Python distributions like Canopy (Enthought)
 and Anaconda (Continuum Analytics).
 
@@ -133,21 +147,13 @@ We use py.test to run Shapely's suite of unittests and doctests.
 
 .. code-block:: console
 
-    (env)$ py.test tests
-
-Roadmap and Maintenance
-=======================
-
-Shapely 1.2.x is a maintenance-only branch which supports Python 2.4-2.6, but
-not Python 3+. There will be no new features in Shapely 1.2.x and only fixes
-for major bugs.
-
-Shapely 1.4.x is a maintenance-only branch supporting Pythons 2.7 and 3.3+.
+    (env)$ python -m pytest
 
 Support
 =======
 
-Please discuss Shapely with us at
-http://lists.gispython.org/mailman/listinfo/community.
+Questions about using Shapely may be asked on the `GIS StackExchange 
+<http://gis.stackexchange.com/questions/tagged/shapely>`__ using the "shapely"
+tag.
 
 Bugs may be reported at https://github.com/Toblerity/Shapely/issues.
diff --git a/setup.py b/setup.py
index 814c22b..7418d5a 100755
--- a/setup.py
+++ b/setup.py
@@ -178,8 +178,9 @@ with open('CHANGES.txt', 'r', **open_kwds) as fp:
 long_description = readme + '\n\n' + credits + '\n\n' + changes
 
 extra_reqs = {
-    'test': ['pytest', 'pytest-cov', 'numpy>=1.4.1', 'packaging']
-}
+    'test': ['pytest', 'pytest-cov', 'packaging'],
+    'vectorized': ['numpy']}
+
 extra_reqs['all'] = list(it.chain.from_iterable(extra_reqs.values()))
 
 # Make a dict of setup arguments. Some items will be updated as
@@ -302,8 +303,8 @@ def construct_build_ext(build_ext):
                 build_ext.build_extension(self, ext)
             except ext_errors as x:
                 raise BuildFailed(x)
-    return WrappedBuildExt
 
+    return WrappedBuildExt
 
 if (hasattr(platform, 'python_implementation')
         and platform.python_implementation() == 'PyPy'):
@@ -311,7 +312,6 @@ if (hasattr(platform, 'python_implementation')
     ext_modules = []
     libraries = []
 
-
 if os.path.exists("MANIFEST.in"):
     pyx_file = "shapely/speedups/_speedups.pyx"
     c_file = "shapely/speedups/_speedups.c"
@@ -333,15 +333,9 @@ if os.path.exists("MANIFEST.in"):
         log.warn("speedup extension not found")
 
 ext_modules = [
-    Extension(
-        "shapely.speedups._speedups",
-        ["shapely/speedups/_speedups.c"],
-        include_dirs=include_dirs,
-        library_dirs=library_dirs,
-        libraries=libraries,
-        extra_link_args=extra_link_args,
-    ),
-]
+    Extension("shapely.speedups._speedups", ["shapely/speedups/_speedups.c"],
+        include_dirs=include_dirs, library_dirs=library_dirs,
+        libraries=libraries, extra_link_args=extra_link_args)]
 
 cmd_classes = setup_args.setdefault('cmdclass', {})
 
@@ -370,7 +364,6 @@ except ImportError:
     log.info("Numpy or Cython not available, shapely.vectorized submodule "
              "not being built.")
 
-
 try:
     # try building with speedups
     existing_build_ext = setup_args['cmdclass'].\
diff --git a/shapely/__init__.py b/shapely/__init__.py
index 909cbfd..8f4c864 100644
--- a/shapely/__init__.py
+++ b/shapely/__init__.py
@@ -1 +1 @@
-__version__ = "1.6a2"
+__version__ = "1.6b1"
diff --git a/shapely/coords.py b/shapely/coords.py
index bfac400..427d171 100644
--- a/shapely/coords.py
+++ b/shapely/coords.py
@@ -11,27 +11,6 @@ from shapely.topology import Validating
 if sys.version_info[0] < 3:
     range = xrange
 
-try:
-    import numpy
-    has_numpy = True
-except ImportError:
-    has_numpy = False
-
-def required(ob):
-    """Return an object that meets Shapely requirements for self-owned
-    C-continguous data, copying if necessary, or just return the original
-    object."""
-    if hasattr(ob, '__array_interface__'):
-        if ob.__array_interface__.get('strides') and not has_numpy:
-            # raise an error if strided. See issue #52.
-            raise ValueError("C-contiguous data is required")
-        else:
-            # numpy.require will just return (ob) if it is already
-            # float64 and well-behaved.
-            return numpy.require(ob, numpy.float64, ["C", "OWNDATA"])
-    else:
-        return ob
-
 
 class CoordinateSequence(object):
     """
diff --git a/shapely/geometry/linestring.py b/shapely/geometry/linestring.py
index 8be43bb..9bba6cf 100644
--- a/shapely/geometry/linestring.py
+++ b/shapely/geometry/linestring.py
@@ -8,7 +8,6 @@ if sys.version_info[0] < 3:
 
 from ctypes import c_double, cast, POINTER
 
-from shapely.coords import required
 from shapely.geos import lgeos, TopologicalError
 from shapely.geometry.base import (
     BaseGeometry, geom_factory, JOIN_STYLE, geos_geom_from_py
@@ -84,7 +83,11 @@ class LineString(BaseGeometry):
 
     def array_interface(self):
         """Provide the Numpy array protocol."""
-        return self.coords.array_interface()
+        if self.is_empty:
+            ai = {'version': 3, 'typestr': '<f8', 'shape': (0,), 'data': (c_double * 0)()}
+        else:
+            ai = self.coords.array_interface()
+        return ai
 
     __array_interface__ = property(array_interface)
 
@@ -187,112 +190,62 @@ def asLineString(context):
 
 def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
     # If a LineString is passed in, clone it and return
-    # If a LinearRing is passed in, clone the coord seq and return a LineString
+    # If a LinearRing is passed in, clone the coord seq and return a
+    # LineString.
+    #
+    # NB: access to coordinates using the array protocol has been moved
+    # entirely to the speedups module.
+
     if isinstance(ob, LineString):
         if type(ob) == LineString:
             return geos_geom_from_py(ob)
         else:
             return geos_geom_from_py(ob, lgeos.GEOSGeom_createLineString)
 
-    # If numpy is present, we use numpy.require to ensure that we have a
-    # C-continguous array that owns its data. View data will be copied.
-    ob = required(ob)
     try:
-        # From array protocol
-        array = ob.__array_interface__
-        assert len(array['shape']) == 2
-        m = array['shape'][0]
-        if m < 2:
-            raise ValueError(
-                "LineStrings must have at least 2 coordinate tuples")
-        try:
-            n = array['shape'][1]
-        except IndexError:
-            raise ValueError(
-                "Input %s is the wrong shape for a LineString" % str(ob))
-        assert n == 2 or n == 3
+        m = len(ob)
+    except TypeError:  # Iterators, e.g. Python 3 zip
+        ob = list(ob)
+        m = len(ob)
 
-        # Make pointer to the coordinate array
-        if isinstance(array['data'], tuple):
-            # numpy tuple (addr, read-only)
-            cp = cast(array['data'][0], POINTER(c_double))
-        else:
-            cp = array['data']
-
-        # Create a coordinate sequence
-        if update_geom is not None:
-            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
-            if n != update_ndim:
-                raise ValueError(
-                    "Wrong coordinate dimensions; this geometry has "
-                    "dimensions: %d" % update_ndim)
-        else:
-            cs = lgeos.GEOSCoordSeq_create(m, n)
-
-        # add to coordinate sequence
-        for i in range(m):
-            dx = c_double(cp[n*i])
-            dy = c_double(cp[n*i+1])
-            dz = None
-            if n == 3:
-                try:
-                    dz = c_double(cp[n*i+2])
-                except IndexError:
-                    raise ValueError("Inconsistent coordinate dimensionality")
-
-            # Because of a bug in the GEOS C API,
-            # always set X before Y
-            lgeos.GEOSCoordSeq_setX(cs, i, dx)
-            lgeos.GEOSCoordSeq_setY(cs, i, dy)
-            if n == 3:
-                lgeos.GEOSCoordSeq_setZ(cs, i, dz)
-
-    except AttributeError:
-        # Fall back on list
-        try:
-            m = len(ob)
-        except TypeError:  # Iterators, e.g. Python 3 zip
-            ob = list(ob)
-            m = len(ob)
+    if m == 0:
+        return None
 
-        if m == 0:
-            return None
+    def _coords(o):
+        if isinstance(o, Point):
+            return o.coords[0]
+        else:
+            return o
 
-        def _coords(o):
-            if isinstance(o, Point):
-                return o.coords[0]
-            else:
-                return o
+    try:
+        n = len(_coords(ob[0]))
+    except TypeError:
+        raise ValueError(
+            "Input %s is the wrong shape for a LineString" % str(ob))
+    assert n == 2 or n == 3
 
-        try:
-            n = len(_coords(ob[0]))
-        except TypeError:
+    # Create a coordinate sequence
+    if update_geom is not None:
+        cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
+        if n != update_ndim:
             raise ValueError(
-                "Input %s is the wrong shape for a LineString" % str(ob))
-        assert n == 2 or n == 3
-
-        # Create a coordinate sequence
-        if update_geom is not None:
-            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
-            if n != update_ndim:
-                raise ValueError(
-                    "Wrong coordinate dimensions; this geometry has "
-                    "dimensions: %d" % update_ndim)
-        else:
-            cs = lgeos.GEOSCoordSeq_create(m, n)
-
-        # add to coordinate sequence
-        for i in range(m):
-            coords = _coords(ob[i])
-            # Because of a bug in the GEOS C API,
-            # always set X before Y
-            lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
-            lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
-            if n == 3:
-                try:
-                    lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
-                except IndexError:
-                    raise ValueError("Inconsistent coordinate dimensionality")
+                "Wrong coordinate dimensions; this geometry has "
+                "dimensions: %d" % update_ndim)
+    else:
+        cs = lgeos.GEOSCoordSeq_create(m, n)
+
+    # add to coordinate sequence
+    for i in range(m):
+        coords = _coords(ob[i])
+        # Because of a bug in the GEOS C API,
+        # always set X before Y
+        lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
+        lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
+        if n == 3:
+            try:
+                lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
+            except IndexError:
+                raise ValueError("Inconsistent coordinate dimensionality")
 
     if update_geom is not None:
         return None
@@ -302,12 +255,3 @@ def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
 
 def update_linestring_from_py(geom, ob):
     geos_linestring_from_py(ob, geom._geom, geom._ndim)
-
-
-# Test runner
-def _test():
-    import doctest
-    doctest.testmod()
-
-if __name__ == "__main__":
-    _test()
diff --git a/shapely/geometry/multipoint.py b/shapely/geometry/multipoint.py
index d9f8908..55c5d65 100644
--- a/shapely/geometry/multipoint.py
+++ b/shapely/geometry/multipoint.py
@@ -9,11 +9,9 @@ if sys.version_info[0] < 3:
 from ctypes import byref, c_double, c_void_p, cast, POINTER
 from ctypes import ArgumentError
 
-from shapely.coords import required
 from shapely.geos import lgeos
 from shapely.geometry.base import (
-    BaseMultipartGeometry, exceptNull, geos_geom_from_py
-)
+    BaseMultipartGeometry, exceptNull, geos_geom_from_py)
 from shapely.geometry import point
 from shapely.geometry.proxy import CachingGeometryProxy
 
@@ -98,7 +96,7 @@ class MultiPoint(BaseMultipartGeometry):
             array_type = c_double * (m * n)
             data = array_type()
             for i in range(m):
-                g = self.geoms[i]._geom    
+                g = self.geoms[i]._geom
                 cs = lgeos.GEOSGeom_getCoordSeq(g)
                 lgeos.GEOSCoordSeq_getX(cs, 0, byref(temp))
                 data[n*i] = temp.value
@@ -158,57 +156,20 @@ def geos_multipoint_from_py(ob):
     if isinstance(ob, MultiPoint):
         return geos_geom_from_py(ob)
 
-    # If numpy is present, we use numpy.require to ensure that we have a
-    # C-continguous array that owns its data. View data will be copied.
-    ob = required(ob)
+    m = len(ob)
     try:
-        # From array protocol
-        array = ob.__array_interface__
-        assert len(array['shape']) == 2
-        m = array['shape'][0]
-        n = array['shape'][1]
-        assert m >= 1
-        assert n == 2 or n == 3
-
-        # Make pointer to the coordinate array
-        if isinstance(array['data'], tuple):
-            # numpy tuple (addr, read-only)
-            cp = cast(array['data'][0], POINTER(c_double))
-        else:
-            cp = array['data']
+        n = len(ob[0])
+    except TypeError:
+        n = ob[0]._ndim
+    assert n == 2 or n == 3
 
-        # Array of pointers to sub-geometries
-        subs = (c_void_p * m)()
+    # Array of pointers to point geometries
+    subs = (c_void_p * m)()
 
-        for i in range(m):
-            geom, ndims = point.geos_point_from_py(cp[n*i:n*i+2])
-            subs[i] = cast(geom, c_void_p)
+    # add to coordinate sequence
+    for i in range(m):
+        coords = ob[i]
+        geom, ndims = point.geos_point_from_py(coords)
+        subs[i] = cast(geom, c_void_p)
 
-    except AttributeError:
-        # Fall back on list
-        m = len(ob)
-        try:
-            n = len(ob[0])
-        except TypeError:
-            n = ob[0]._ndim
-        assert n == 2 or n == 3
-
-        # Array of pointers to point geometries
-        subs = (c_void_p * m)()
-        
-        # add to coordinate sequence
-        for i in range(m):
-            coords = ob[i]
-            geom, ndims = point.geos_point_from_py(coords)
-            subs[i] = cast(geom, c_void_p)
-            
     return lgeos.GEOSGeom_createCollection(4, subs, m), n
-
-# Test runner
-def _test():
-    import doctest
-    doctest.testmod()
-
-
-if __name__ == "__main__":
-    _test()
diff --git a/shapely/geometry/point.py b/shapely/geometry/point.py
index 0b8720b..70d0eeb 100644
--- a/shapely/geometry/point.py
+++ b/shapely/geometry/point.py
@@ -4,7 +4,6 @@
 from ctypes import c_double
 from ctypes import cast, POINTER
 
-from shapely.coords import required
 from shapely.errors import DimensionError
 from shapely.geos import lgeos
 from shapely.geometry.base import BaseGeometry, geos_geom_from_py
@@ -110,8 +109,11 @@ class Point(BaseGeometry):
 
     def array_interface(self):
         """Provide the Numpy array protocol."""
-        ai = self.array_interface_base
-        ai.update({'shape': (self._ndim,)})
+        if self.is_empty:
+            ai = {'version': 3, 'typestr': '<f8', 'shape': (0,), 'data': (c_double * 0)()}
+        else:
+            ai = self.array_interface_base
+            ai.update({'shape': (self._ndim,)})
         return ai
     __array_interface__ = property(array_interface)
 
@@ -195,49 +197,20 @@ def geos_point_from_py(ob, update_geom=None, update_ndim=0):
     if isinstance(ob, Point):
         return geos_geom_from_py(ob)
 
-    # If numpy is present, we use numpy.require to ensure that we have a
-    # C-continguous array that owns its data. View data will be copied.
-    ob = required(ob)
-    try:
-        # From array protocol
-        array = ob.__array_interface__
-        assert len(array['shape']) == 1
-        n = array['shape'][0]
-        assert n == 2 or n == 3
-
-        dz = None
-        da = array['data']
-        if isinstance(da, tuple):
-            cdata = da[0]
-            # If we had numpy, we would do
-            # from numpy.ctypeslib import as_ctypes
-            # cp = as_ctypes(ob) - check that code?
-            cp = cast(cdata, POINTER(c_double))
-            dx = c_double(cp[0])
-            dy = c_double(cp[1])
-            if n == 3:
-                dz = c_double(cp[2])
-        else:
-            dx, dy = da[0:2]
-            if n == 3:
-                dz = da[2]
-
-    except AttributeError:
-        # Fall back on the case of Python sequence data
-        # Accept either (x, y) or [(x, y)]
-        if not hasattr(ob, '__getitem__'):  # Iterators, e.g. Python 3 zip
-            ob = list(ob)
-
-        if isinstance(ob[0], tuple):
-            coords = ob[0]
-        else:
-            coords = ob
-        n = len(coords)
-        dx = c_double(coords[0])
-        dy = c_double(coords[1])
-        dz = None
-        if n == 3:
-            dz = c_double(coords[2])
+    # Accept either (x, y) or [(x, y)]
+    if not hasattr(ob, '__getitem__'):  # Iterators, e.g. Python 3 zip
+        ob = list(ob)
+
+    if isinstance(ob[0], tuple):
+        coords = ob[0]
+    else:
+        coords = ob
+    n = len(coords)
+    dx = c_double(coords[0])
+    dy = c_double(coords[1])
+    dz = None
+    if n == 3:
+        dz = c_double(coords[2])
 
     if update_geom:
         cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
@@ -262,12 +235,3 @@ def geos_point_from_py(ob, update_geom=None, update_ndim=0):
 
 def update_point_from_py(geom, ob):
     geos_point_from_py(ob, geom._geom, geom._ndim)
-
-
-# Test runner
-def _test():
-    import doctest
-    doctest.testmod()
-
-if __name__ == "__main__":
-    _test()
diff --git a/shapely/geometry/polygon.py b/shapely/geometry/polygon.py
index e492fae..9602df5 100644
--- a/shapely/geometry/polygon.py
+++ b/shapely/geometry/polygon.py
@@ -11,7 +11,7 @@ from ctypes import ArgumentError
 import weakref
 
 from shapely.algorithms.cga import signed_area
-from shapely.coords import required
+#from shapely.coords import required
 from shapely.geos import lgeos
 from shapely.geometry.base import BaseGeometry, geos_geom_from_py
 from shapely.geometry.linestring import LineString, LineStringAdapter
@@ -374,6 +374,7 @@ def asPolygon(shell, holes=None):
     """Adapt objects to the Polygon interface"""
     return PolygonAdapter(shell, holes)
 
+
 def orient(polygon, sign=1.0):
     s = float(sign)
     rings = []
@@ -389,136 +390,92 @@ def orient(polygon, sign=1.0):
             rings.append(list(ring.coords)[::-1])
     return Polygon(rings[0], rings[1:])
 
+
 def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
     # If a LinearRing is passed in, clone it and return
-    # If a LineString is passed in, clone the coord seq and return a LinearRing
+    # If a LineString is passed in, clone the coord seq and return a
+    # LinearRing.
+    #
+    # NB: access to coordinates using the array protocol has been moved
+    # entirely to the speedups module.
+
     if isinstance(ob, LineString):
         if type(ob) == LinearRing:
             return geos_geom_from_py(ob)
+        elif ob.is_closed and len(ob.coords) >= 4:
+            return geos_geom_from_py(ob, lgeos.GEOSGeom_createLinearRing)
         else:
-            if ob.is_closed and len(ob.coords) >= 4:
-                return geos_geom_from_py(ob, lgeos.GEOSGeom_createLinearRing)
+            ob = list(ob.coords)
 
-    # If numpy is present, we use numpy.require to ensure that we have a
-    # C-continguous array that owns its data. View data will be copied.
-    ob = required(ob)
     try:
-        # From array protocol
-        array = ob.__array_interface__
-        assert len(array['shape']) == 2
-        m = array['shape'][0]
-        n = array['shape'][1]
-        if m < 3:
-            raise ValueError(
-                "A LinearRing must have at least 3 coordinate tuples")
-        assert n == 2 or n == 3
+        m = len(ob)
+    except TypeError:  # Iterators, e.g. Python 3 zip
+        ob = list(ob)
+        m = len(ob)
 
-        # Make pointer to the coordinate array
-        if isinstance(array['data'], tuple):
-            # numpy tuple (addr, read-only)
-            cp = cast(array['data'][0], POINTER(c_double))
-        else:
-            cp = array['data']
+    if m == 0:
+        return None
 
-        # Add closing coordinates to sequence?
-        if cp[0] != cp[m*n-n] or cp[1] != cp[m*n-n+1]:
-            M = m + 1
-        else:
-            M = m
-
-        # Create a coordinate sequence
-        if update_geom is not None:
-            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
-            if n != update_ndim:
-                raise ValueError(
-                "Wrong coordinate dimensions; this geometry has dimensions: %d" \
-                % update_ndim)
-        else:
-            cs = lgeos.GEOSCoordSeq_create(M, n)
-
-        # add to coordinate sequence
-        for i in range(m):
-            # Because of a bug in the GEOS C API,
-            # always set X before Y
-            lgeos.GEOSCoordSeq_setX(cs, i, cp[n*i])
-            lgeos.GEOSCoordSeq_setY(cs, i, cp[n*i+1])
-            if n == 3:
-                lgeos.GEOSCoordSeq_setZ(cs, i, cp[n*i+2])
-
-        # Add closing coordinates to sequence?
-        if M > m:
-            # Because of a bug in the GEOS C API,
-            # always set X before Y
-            lgeos.GEOSCoordSeq_setX(cs, M-1, cp[0])
-            lgeos.GEOSCoordSeq_setY(cs, M-1, cp[1])
-            if n == 3:
-                lgeos.GEOSCoordSeq_setZ(cs, M-1, cp[2])
-
-    except AttributeError:
-        # Fall back on list
-        try:
-            m = len(ob)
-        except TypeError:  # Iterators, e.g. Python 3 zip
-            ob = list(ob)
-            m = len(ob)
+    n = len(ob[0])
+    if m < 3:
+        raise ValueError(
+            "A LinearRing must have at least 3 coordinate tuples")
+    assert (n == 2 or n == 3)
 
-        if m == 0:
-            return None
+    # Add closing coordinates if not provided
+    if m == 3 or ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]:
+        M = m + 1
+    else:
+        M = m
 
-        n = len(ob[0])
-        if m < 3:
+    # Create a coordinate sequence
+    if update_geom is not None:
+        if n != update_ndim:
             raise ValueError(
-                "A LinearRing must have at least 3 coordinate tuples")
-        assert (n == 2 or n == 3)
-
-        # Add closing coordinates if not provided
-        if m == 3 or ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]:
-            M = m + 1
-        else:
-            M = m
-
-        # Create a coordinate sequence
-        if update_geom is not None:
-            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
-            if n != update_ndim:
-                raise ValueError(
-                "Wrong coordinate dimensions; this geometry has dimensions: %d" \
-                % update_ndim)
-        else:
-            cs = lgeos.GEOSCoordSeq_create(M, n)
-
-        # add to coordinate sequence
-        for i in range(m):
-            coords = ob[i]
-            # Because of a bug in the GEOS C API,
-            # always set X before Y
-            lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
-            lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
-            if n == 3:
-                try:
-                    lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
-                except IndexError:
-                    raise ValueError("Inconsistent coordinate dimensionality")
-
-        # Add closing coordinates to sequence?
-        if M > m:
-            coords = ob[0]
-            # Because of a bug in the GEOS C API,
-            # always set X before Y
-            lgeos.GEOSCoordSeq_setX(cs, M-1, coords[0])
-            lgeos.GEOSCoordSeq_setY(cs, M-1, coords[1])
-            if n == 3:
-                lgeos.GEOSCoordSeq_setZ(cs, M-1, coords[2])
+                "Coordinate dimensions mismatch: target geom has {} dims, "
+                "update geom has {} dims".format(n, update_ndim))
+        cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
+    else:
+        cs = lgeos.GEOSCoordSeq_create(M, n)
+
+    # add to coordinate sequence
+    for i in range(m):
+        coords = ob[i]
+        # Because of a bug in the GEOS C API,
+        # always set X before Y
+        lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
+        lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
+        if n == 3:
+            try:
+                lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
+            except IndexError:
+                raise ValueError("Inconsistent coordinate dimensionality")
+
+    # Add closing coordinates to sequence?
+    if M > m:
+        coords = ob[0]
+        # Because of a bug in the GEOS C API,
+        # always set X before Y
+        lgeos.GEOSCoordSeq_setX(cs, M-1, coords[0])
+        lgeos.GEOSCoordSeq_setY(cs, M-1, coords[1])
+        if n == 3:
+            lgeos.GEOSCoordSeq_setZ(cs, M-1, coords[2])
 
     if update_geom is not None:
         return None
     else:
         return lgeos.GEOSGeom_createLinearRing(cs), n
 
+
 def update_linearring_from_py(geom, ob):
     geos_linearring_from_py(ob, geom._geom, geom._ndim)
 
+
 def geos_polygon_from_py(shell, holes=None):
+
+    if shell is None:
+        return None
+
     if isinstance(shell, Polygon):
         return geos_geom_from_py(shell)
 
@@ -526,6 +483,7 @@ def geos_polygon_from_py(shell, holes=None):
         ret = geos_linearring_from_py(shell)
         if ret is None:
             return None
+
         geos_shell, ndim = ret
         if holes is not None and len(holes) > 0:
             ob = holes
@@ -550,19 +508,7 @@ def geos_polygon_from_py(shell, holes=None):
         else:
             geos_holes = POINTER(c_void_p)()
             L = 0
+
         return (
             lgeos.GEOSGeom_createPolygon(
-                        c_void_p(geos_shell),
-                        geos_holes,
-                        L
-                        ),
-            ndim
-            )
-
-# Test runner
-def _test():
-    import doctest
-    doctest.testmod()
-
-if __name__ == "__main__":
-    _test()
+                c_void_p(geos_shell), geos_holes, L), ndim)
diff --git a/shapely/speedups/_speedups.pyx b/shapely/speedups/_speedups.pyx
index 458b135..72da797 100644
--- a/shapely/speedups/_speedups.pyx
+++ b/shapely/speedups/_speedups.pyx
@@ -6,8 +6,8 @@
 # Transcription to cython: Copyright (c) 2011, Oliver Tonnhofer
 
 import ctypes
+import numpy
 
-from shapely.coords import required
 from shapely.geos import lgeos
 from shapely.geometry import Point, LineString, LinearRing
 from shapely.geometry.base import geom_factory
@@ -32,6 +32,16 @@ def destroy(geom):
     GEOSGeom_destroy_r(cast_handle(lgeos.geos_handle), cast_geom(geom))
 
 
+def required(ob):
+    """Return an object that meets Shapely requirements for self-owned
+    C-continguous data, copying if necessary, or just return the original
+    object."""
+    if hasattr(ob, '__array_interface__'):
+        return numpy.require(ob, numpy.float64, ["C", "OWNDATA"])
+    else:
+        return ob
+
+
 def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
     cdef double *cp
     cdef GEOSContextHandle_t handle = cast_handle(lgeos.geos_handle)
diff --git a/tests/test_linestring.py b/tests/test_linestring.py
index 2c50a5b..90c5fa8 100644
--- a/tests/test_linestring.py
+++ b/tests/test_linestring.py
@@ -154,6 +154,11 @@ class LineStringTestCase(unittest.TestCase):
         b = asarray(line)
         assert_array_equal(b, array([[0., 0.], [2., 2.], [1., 1.]]))
 
+        # Test array interface of empty linestring
+        le = LineString()
+        a = asarray(le)
+        assert(a.shape[0], 0)
+
 
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(LineStringTestCase)
diff --git a/tests/test_ndarrays.py b/tests/test_ndarrays.py
index e9b9f6d..f8db1dd 100644
--- a/tests/test_ndarrays.py
+++ b/tests/test_ndarrays.py
@@ -20,10 +20,10 @@ class TransposeTestCase(unittest.TestCase):
 
     @unittest.skipIf(not numpy, 'numpy not installed')
     def test_multipoint(self):
-        a = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
-        t = a.T
-        s = geometry.asMultiPoint(t)
-        coords = reduce(lambda x, y: x + y, [list(g.coords) for g in s])
+        arr = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]])
+        tarr = arr.T
+        shape = geometry.asMultiPoint(tarr)
+        coords = reduce(lambda x, y: x + y, [list(g.coords) for g in shape])
         self.assertEqual(
             coords,
             [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)]
diff --git a/tests/test_point.py b/tests/test_point.py
index d481a3a..452d034 100644
--- a/tests/test_point.py
+++ b/tests/test_point.py
@@ -134,6 +134,11 @@ class LineStringTestCase(unittest.TestCase):
         p = Point(*list(a))
         self.assertEqual(p.coords[:], [(1.0, 1.0, 0.0)])
 
+        # Test array interface of empty geometry
+        pe = Point()
+        a = asarray(pe)
+        self.assertEqual(a.shape[0], 0)
+
 
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(LineStringTestCase)
diff --git a/tests/test_vectorized.py b/tests/test_vectorized.py
index ea1d956..549b354 100644
--- a/tests/test_vectorized.py
+++ b/tests/test_vectorized.py
@@ -1,16 +1,18 @@
 from . import unittest, numpy
 from shapely.geometry import Point, box, MultiPolygon
-from shapely.vectorized import contains, touches
+
 
 try:
     import numpy as np
+    has_numpy = True
 except ImportError:
-    pass
+    has_numpy = False
 
 
- at unittest.skipIf(not numpy, 'numpy required')
+ at unittest.skipIf(not has_numpy, 'numpy required')
 class VectorizedContainsTestCase(unittest.TestCase):
     def assertContainsResults(self, geom, x, y):
+        from shapely.vectorized import contains
         result = contains(geom, x, y)
         x = np.asanyarray(x)
         y = np.asanyarray(y) 
@@ -85,9 +87,10 @@ class VectorizedContainsTestCase(unittest.TestCase):
         self.assertContainsResults(self.construct_torus(), *g.exterior.xy)
 
 
- at unittest.skipIf(not numpy, 'numpy required')
+ at unittest.skipIf(not has_numpy, 'numpy required')
 class VectorizedTouchesTestCase(unittest.TestCase):
     def test_touches(self):
+        from shapely.vectorized import touches
         y, x = np.mgrid[-2:3:6j, -1:3:5j]
         geom = box(0, -1, 2, 2)
         result = touches(geom, x, y)
@@ -99,8 +102,6 @@ class VectorizedTouchesTestCase(unittest.TestCase):
                              [False, False, False, False, False]], dtype=bool)
         from numpy.testing import assert_array_equal
         assert_array_equal(result, expected)
-        
-        
 
 
 def test_suite():

-- 
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