[Git][debian-gis-team/python-shapely][upstream] New upstream version 1.8.3
Bas Couwenberg (@sebastic)
gitlab at salsa.debian.org
Wed Aug 17 04:37:25 BST 2022
Bas Couwenberg pushed to branch upstream at Debian GIS Project / python-shapely
Commits:
41878988 by Bas Couwenberg at 2022-08-17T05:18:48+02:00
New upstream version 1.8.3
- - - - -
23 changed files:
- .github/workflows/release.yml
- .github/workflows/tests.yml
- CHANGES.txt
- pyproject.toml
- shapely/__init__.py
- shapely/ctypes_declarations.py
- shapely/geometry/base.py
- shapely/geometry/collection.py
- shapely/geometry/multilinestring.py
- shapely/geometry/multipoint.py
- shapely/geometry/multipolygon.py
- shapely/geometry/polygon.py
- shapely/geometry/proxy.py
- shapely/ops.py
- shapely/strtree.py
- shapely/topology.py
- tests/test_geos_err_handler.py
- tests/test_linear_referencing.py
- tests/test_parallel_offset.py
- tests/test_shared_paths.py
- tests/test_split.py
- tests/test_strtree.py
- tests/test_substring.py
Changes:
=====================================
.github/workflows/release.yml
=====================================
@@ -30,7 +30,7 @@ jobs:
- name: Build a source tarball
env:
- GEOS_VERSION: "3.10.2"
+ GEOS_VERSION: "3.10.3"
GEOS_INSTALL: ${{ runner.temp }}/geos-$GEOS_VERSION
GEOS_CONFIG: ${{ runner.temp }}/geos-$GEOS_VERSION/bin/geos-config
LD_LIBRARY_PATH: $LD_LIBRARY_PATH:${{ runner.temp }}/geos-$GEOS_VERSION/lib
@@ -49,7 +49,7 @@ jobs:
name: Build ${{ matrix.arch }} wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
- GEOS_VERSION: "3.10.2"
+ GEOS_VERSION: "3.10.3"
CIBW_BUILD_VERBOSITY: 2
strategy:
fail-fast: false
@@ -65,13 +65,13 @@ jobs:
- os: windows-2019
arch: AMD64
msvc_arch: x64
- - os: macos-10.15
+ - os: macos-11
arch: x86_64
cmake_osx_architectures: x86_64
- - os: macos-10.15
+ - os: macos-11
arch: arm64
cmake_osx_architectures: arm64
- - os: macos-10.15
+ - os: macos-11
arch: universal2
cmake_osx_architectures: "x86_64;arm64"
=====================================
.github/workflows/tests.yml
=====================================
@@ -14,7 +14,7 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-2019]
architecture: [x64]
- geos: [3.6.5, 3.7.3, 3.8.1, 3.9.2, 3.10.2]
+ geos: [3.6.5, 3.7.5, 3.8.3, 3.9.3, 3.10.3, 3.11.0]
include:
# 2017
- python: 3.6
@@ -30,51 +30,63 @@ jobs:
speeedups: 0
# 2018
- python: 3.7
- geos: 3.7.3
+ geos: 3.7.5
numpy: 1.15.4
speedups: 1
- python: 3.7
- geos: 3.7.3
+ geos: 3.7.5
numpy: 1.15.4
speedups: 0
- python: 3.7
- geos: 3.7.3
+ geos: 3.7.5
speedups: 0
# 2019
- python: 3.8
- geos: 3.8.1
+ geos: 3.8.3
numpy: 1.17.5
speedups: 1
- python: 3.8
- geos: 3.8.1
+ geos: 3.8.3
numpy: 1.17.5
speedups: 0
- python: 3.8
- geos: 3.8.1
+ geos: 3.8.3
speedups: 0
# 2020
- python: 3.9
- geos: 3.9.2
+ geos: 3.9.3
numpy: 1.19.5
speedups: 1
- python: 3.9
- geos: 3.9.2
+ geos: 3.9.3
numpy: 1.19.5
speedups: 0
- python: 3.9
- geos: 3.9.2
+ geos: 3.9.3
speedups: 0
# 2021
- python: "3.10"
- geos: 3.10.2
+ geos: 3.10.3
numpy: 1.21.3
speedups: 1
- python: "3.10"
- geos: 3.10.2
+ geos: 3.10.3
numpy: 1.21.3
speedups: 0
- python: "3.10"
- geos: 3.10.2
+ geos: 3.10.3
+ speedups: 0
+ # 2022
+ - python: "3.10" # switch to "3.11" when released (PEP 664)
+ geos: 3.11.0
+ numpy: 1.23.0
+ speedups: 1
+ - python: "3.10"
+ geos: 3.11.0
+ numpy: 1.23.0
+ speedups: 0
+ - python: "3.10"
+ geos: 3.11.0
speedups: 0
# enable two 32-bit windows builds
- os: windows-2019
@@ -86,7 +98,7 @@ jobs:
- os: windows-2019
architecture: x86
python: 3.9
- geos: 3.10.2
+ geos: 3.10.3
numpy: 1.19.5
speeedups: 1
@@ -132,7 +144,7 @@ jobs:
- name: Install python dependencies
run: |
- pip install --disable-pip-version-check --user --upgrade pip
+ python -m pip install --disable-pip-version-check --user --upgrade pip
pip install --upgrade wheel setuptools
if [ "$SPEEDUPS" == "1" ]; then
pip install --install-option="--no-cython-compile" cython;
=====================================
CHANGES.txt
=====================================
@@ -1,6 +1,31 @@
Changes
=======
+1.8.3 (2022-08-16)
+------------------
+
+Deprecations:
+
+The STRtree class will be changed in 2.0.0 and will not be compatible with the
+class in versions 1.8.x. This change obsoletes the deprecation announcement in
+1.8a3 (below).
+
+Packaging:
+
+Wheels for 1.8.3 published on PyPI include GEOS 3.10.3.
+
+Bug fixes:
+
+- The signature for GEOSMinimumClearance has been corrected, fixing an issue
+ affecting aarch64-darwin (#1480)
+- Return and arg types have been corrected and made more strict for area,
+ length, and distance properties.
+- A new c_geom_p type has been created to replace c_void_p when calling GEOS
+ functions (#1479).
+- An incorrect polygon-line intersection (#1427) has been fixed in GEOS 3.10.3,
+ which will be included in wheels published to PyPI.
+- GEOS buffer parameters are now destroyed, fixing a memory leak (#1440)..
+
1.8.2 (2022-05-03)
------------------
@@ -23,7 +48,7 @@ install from source.
Packaging:
Wheels for 1.8.1 published on PyPI include GEOS 3.10.2. This version is the
-best version of GDAL yet. Discrepancies in behavior compared to previous
+best version of GEOS yet. Discrepancies in behavior compared to previous
versions are considered to be improvements.
For the first time, we will publish wheels for macos_arm64 (see PR #1310).
=====================================
pyproject.toml
=====================================
@@ -1,2 +1,6 @@
[build-system]
-requires = ["setuptools", "wheel", "cython>=0.29.24", "oldest-supported-numpy"]
+requires = [
+ "Cython>=0.29.24,<3",
+ "oldest-supported-numpy",
+ "setuptools<64",
+]
=====================================
shapely/__init__.py
=====================================
@@ -1 +1 @@
-__version__ = "1.8.2"
+__version__ = "1.8.3"
=====================================
shapely/ctypes_declarations.py
=====================================
@@ -3,8 +3,19 @@
See header file: geos-x.y.z/capi/geos_c.h
'''
-from ctypes import CFUNCTYPE, POINTER, c_void_p, c_char_p, \
- c_size_t, c_byte, c_uint, c_int, c_double, py_object
+from ctypes import (
+ CFUNCTYPE,
+ POINTER,
+ Structure,
+ c_void_p,
+ c_char_p,
+ c_size_t,
+ c_byte,
+ c_uint,
+ c_int,
+ c_double,
+ py_object,
+)
from .errors import UnsupportedGEOSVersionError
@@ -20,6 +31,13 @@ class allocated_c_char_p(c_char_p):
pass
+class GEOSGeom_t(Structure):
+ pass
+
+
+c_geom_p = POINTER(GEOSGeom_t)
+
+
def prototype(lgeos, geos_version):
"""Protype functions in geos_c.h for different version of GEOS
@@ -132,6 +150,9 @@ def prototype(lgeos, geos_version):
lgeos.GEOSBufferParams_create.restype = c_void_p
lgeos.GEOSBufferParams_create.argtypes = None
+ lgeos.GEOSBufferParams_destroy.restype = None
+ lgeos.GEOSBufferParams_destroy.argtypes = [c_void_p]
+
lgeos.GEOSBufferParams_setEndCapStyle.restype = c_int
lgeos.GEOSBufferParams_setEndCapStyle.argtypes = [c_void_p, c_int]
@@ -152,25 +173,25 @@ def prototype(lgeos, geos_version):
# Geometry constructors
- lgeos.GEOSGeom_createPoint.restype = c_void_p
+ lgeos.GEOSGeom_createPoint.restype = c_geom_p
lgeos.GEOSGeom_createPoint.argtypes = [c_void_p]
- lgeos.GEOSGeom_createLinearRing.restype = c_void_p
+ lgeos.GEOSGeom_createLinearRing.restype = c_geom_p
lgeos.GEOSGeom_createLinearRing.argtypes = [c_void_p]
- lgeos.GEOSGeom_createLineString.restype = c_void_p
+ lgeos.GEOSGeom_createLineString.restype = c_geom_p
lgeos.GEOSGeom_createLineString.argtypes = [c_void_p]
- lgeos.GEOSGeom_createPolygon.restype = c_void_p
- lgeos.GEOSGeom_createPolygon.argtypes = [c_void_p, c_void_p, c_uint]
+ lgeos.GEOSGeom_createPolygon.restype = c_geom_p
+ lgeos.GEOSGeom_createPolygon.argtypes = [c_geom_p, POINTER(c_geom_p), c_uint]
- lgeos.GEOSGeom_createCollection.restype = c_void_p
- lgeos.GEOSGeom_createCollection.argtypes = [c_int, c_void_p, c_uint]
+ lgeos.GEOSGeom_createCollection.restype = c_geom_p
+ lgeos.GEOSGeom_createCollection.argtypes = [c_int, POINTER(c_geom_p), c_uint]
- lgeos.GEOSGeom_createEmptyCollection.restype = c_void_p
+ lgeos.GEOSGeom_createEmptyCollection.restype = c_geom_p
lgeos.GEOSGeom_createEmptyCollection.argtypes = [c_int]
- lgeos.GEOSGeom_clone.restype = c_void_p
+ lgeos.GEOSGeom_clone.restype = c_geom_p
lgeos.GEOSGeom_clone.argtypes = [c_void_p]
# Memory management
@@ -222,9 +243,13 @@ def prototype(lgeos, geos_version):
lgeos.GEOSPolygonize.restype = c_void_p
lgeos.GEOSPolygonize.argtypes = [c_void_p, c_uint]
- lgeos.GEOSPolygonize_full.restype = c_void_p
+ lgeos.GEOSPolygonize_full.restype = c_geom_p
lgeos.GEOSPolygonize_full.argtypes = [
- c_void_p, c_void_p, c_void_p, c_void_p]
+ c_geom_p,
+ POINTER(c_geom_p),
+ POINTER(c_geom_p),
+ POINTER(c_geom_p),
+ ]
if geos_version >= (3, 4, 0):
lgeos.GEOSDelaunayTriangulation.restype = c_void_p
@@ -393,17 +418,17 @@ def prototype(lgeos, geos_version):
# Misc functions
- lgeos.GEOSArea.restype = c_double
- lgeos.GEOSArea.argtypes = [c_void_p, c_void_p]
+ lgeos.GEOSArea.restype = c_int
+ lgeos.GEOSArea.argtypes = [c_geom_p, POINTER(c_double)]
lgeos.GEOSLength.restype = c_int
- lgeos.GEOSLength.argtypes = [c_void_p, c_void_p]
+ lgeos.GEOSLength.argtypes = [c_geom_p, POINTER(c_double)]
lgeos.GEOSDistance.restype = c_int
- lgeos.GEOSDistance.argtypes = [c_void_p, c_void_p, c_void_p]
+ lgeos.GEOSDistance.argtypes = [c_geom_p, c_geom_p, POINTER(c_double)]
lgeos.GEOSHausdorffDistance.restype = c_int
- lgeos.GEOSHausdorffDistance.argtypes = [c_void_p, c_void_p, c_void_p]
+ lgeos.GEOSHausdorffDistance.argtypes = [c_geom_p, c_geom_p, POINTER(c_double)]
# Reader and Writer APIs
@@ -521,8 +546,8 @@ def prototype(lgeos, geos_version):
c_void_p, py_object, c_void_p, lgeos.GEOSDistanceCallback, py_object]
lgeos.GEOSSTRtree_nearest_generic.restype = c_void_p
- lgeos.GEOSMinimumClearance.argtypes = [c_void_p]
- lgeos.GEOSMinimumClearance.restype = c_double
+ lgeos.GEOSMinimumClearance.argtypes = [c_geom_p, POINTER(c_double)]
+ lgeos.GEOSMinimumClearance.restype = c_int
if geos_version >= (3, 8, 0):
lgeos.GEOSMakeValid.restype = c_void_p
=====================================
shapely/geometry/base.py
=====================================
@@ -7,7 +7,7 @@ different z values may intersect or be equal.
"""
from binascii import a2b_hex
-from ctypes import pointer, c_size_t, c_char_p, c_void_p
+from ctypes import cast, pointer, c_size_t, c_char_p, c_void_p
from itertools import islice
import logging
import math
@@ -18,6 +18,7 @@ import warnings
from shapely.affinity import affine_transform
from shapely.coords import CoordinateSequence
+from shapely.ctypes_declarations import c_geom_p
from shapely.errors import GeometryTypeError, WKBReadingError, WKTReadingError
from shapely.errors import ShapelyDeprecationWarning
from shapely.geos import WKBWriter, WKTWriter
@@ -107,10 +108,11 @@ def geos_geom_from_py(ob, create_func=None):
This behaviour is useful for converting between LineString and LinearRing
objects.
"""
+ geom_ptr = cast(ob._geom, c_geom_p)
if create_func is None:
- geom = lgeos.GEOSGeom_clone(ob._geom)
+ geom = lgeos.GEOSGeom_clone(geom_ptr)
else:
- cs = lgeos.GEOSGeom_getCoordSeq(ob._geom)
+ cs = lgeos.GEOSGeom_getCoordSeq(geom_ptr)
cs = lgeos.GEOSCoordSeq_clone(cs)
geom = create_func(cs)
@@ -625,12 +627,16 @@ class BaseGeometry:
if 'buffer_with_params' in self.impl:
params = self._lgeos.GEOSBufferParams_create()
- self._lgeos.GEOSBufferParams_setEndCapStyle(params, cap_style)
- self._lgeos.GEOSBufferParams_setJoinStyle(params, join_style)
- self._lgeos.GEOSBufferParams_setMitreLimit(params, mitre_limit)
- self._lgeos.GEOSBufferParams_setQuadrantSegments(params, res)
- self._lgeos.GEOSBufferParams_setSingleSided(params, single_sided)
- return geom_factory(self.impl['buffer_with_params'](self, params, distance))
+ try:
+ self._lgeos.GEOSBufferParams_setEndCapStyle(params, cap_style)
+ self._lgeos.GEOSBufferParams_setJoinStyle(params, join_style)
+ self._lgeos.GEOSBufferParams_setMitreLimit(params, mitre_limit)
+ self._lgeos.GEOSBufferParams_setQuadrantSegments(params, res)
+ self._lgeos.GEOSBufferParams_setSingleSided(params, single_sided)
+ return geom_factory(self.impl['buffer_with_params'](self, params, distance))
+ finally:
+ if params:
+ self._lgeos.GEOSBufferParams_destroy(params)
if cap_style == CAP_STYLE.round and join_style == JOIN_STYLE.round:
return geom_factory(self.impl['buffer'](self, distance, res))
=====================================
shapely/geometry/collection.py
=====================================
@@ -3,6 +3,7 @@
from ctypes import c_void_p
+from shapely.ctypes_declarations import c_geom_p
from shapely.geos import lgeos
from shapely.geometry.base import BaseGeometry
from shapely.geometry.base import BaseMultipartGeometry
@@ -63,7 +64,7 @@ def geos_geometrycollection_from_py(ob):
ob = ob.geoms
L = len(ob)
N = 2
- subs = (c_void_p * L)()
+ subs = (c_geom_p * L)()
for l in range(L):
assert(isinstance(ob[l], BaseGeometry))
if ob[l].has_z:
=====================================
shapely/geometry/multilinestring.py
=====================================
@@ -4,6 +4,7 @@
from ctypes import c_void_p, cast
import warnings
+from shapely.ctypes_declarations import c_geom_p
from shapely.errors import EmptyPartError, ShapelyDeprecationWarning
from shapely.geos import lgeos
from shapely.geometry.base import BaseMultipartGeometry, geos_geom_from_py
@@ -116,9 +117,9 @@ def asMultiLineString(context):
def geos_multilinestring_from_py(ob):
- # ob must be either a MultiLineString, a sequence, or
+ # ob must be either a MultiLineString, a sequence, or
# array of sequences or arrays
-
+
if isinstance(ob, MultiLineString):
return geos_geom_from_py(ob)
@@ -134,8 +135,8 @@ def geos_multilinestring_from_py(ob):
raise ValueError("Invalid coordinate dimensionality")
# Array of pointers to point geometries
- subs = (c_void_p * L)()
-
+ subs = (c_geom_p * L)()
+
# add to coordinate sequence
for l in range(L):
geom, ndims = linestring.geos_linestring_from_py(obs[l])
@@ -143,6 +144,6 @@ def geos_multilinestring_from_py(ob):
if lgeos.GEOSisEmpty(geom):
raise EmptyPartError("Can't create MultiLineString with empty component")
- subs[l] = cast(geom, c_void_p)
-
+ subs[l] = cast(geom, c_geom_p)
+
return (lgeos.GEOSGeom_createCollection(5, subs, L), N)
=====================================
shapely/geometry/multipoint.py
=====================================
@@ -4,6 +4,7 @@
from ctypes import byref, c_double, c_void_p, cast
import warnings
+from shapely.ctypes_declarations import c_geom_p
from shapely.errors import EmptyPartError, ShapelyDeprecationWarning
from shapely.geos import lgeos
from shapely.geometry.base import (
@@ -194,7 +195,7 @@ def geos_multipoint_from_py(ob):
assert n == 2 or n == 3
# Array of pointers to point geometries
- subs = (c_void_p * m)()
+ subs = (c_geom_p * m)()
# add to coordinate sequence
for i in range(m):
@@ -204,6 +205,6 @@ def geos_multipoint_from_py(ob):
if lgeos.GEOSisEmpty(geom):
raise EmptyPartError("Can't create MultiPoint with empty component")
- subs[i] = cast(geom, c_void_p)
+ subs[i] = cast(geom, c_geom_p)
return lgeos.GEOSGeom_createCollection(4, subs, m), n
=====================================
shapely/geometry/multipolygon.py
=====================================
@@ -4,6 +4,7 @@
from ctypes import c_void_p, cast
import warnings
+from shapely.ctypes_declarations import c_geom_p
from shapely.errors import ShapelyDeprecationWarning
from shapely.geos import lgeos
from shapely.geometry.base import BaseMultipartGeometry, geos_geom_from_py
@@ -146,10 +147,10 @@ def geos_multipolygon_from_py(ob):
N = len(ob[0][0][0])
assert N == 2 or N == 3
- subs = (c_void_p * L)()
+ subs = (c_geom_p * L)()
for l in range(L):
geom, ndims = polygon.geos_polygon_from_py(ob[l][0], ob[l][1:])
- subs[l] = cast(geom, c_void_p)
+ subs[l] = cast(geom, c_geom_p)
return (lgeos.GEOSGeom_createCollection(6, subs, L), N)
@@ -192,7 +193,7 @@ def geos_multipolygon_from_polygons(arg):
assert N == 2 or N == 3
- subs = (c_void_p * L)()
+ subs = (c_geom_p * L)()
for i, ob in enumerate(obs):
if isinstance(ob, polygon.Polygon):
@@ -203,6 +204,6 @@ def geos_multipolygon_from_polygons(arg):
holes = ob[1]
geom, ndims = polygon.geos_polygon_from_py(shell, holes)
- subs[i] = cast(geom, c_void_p)
+ subs[i] = cast(geom, c_geom_p)
return (lgeos.GEOSGeom_createCollection(6, subs, L), N)
=====================================
shapely/geometry/polygon.py
=====================================
@@ -9,6 +9,7 @@ import weakref
from shapely.algorithms.cga import signed_area
from shapely.coords import CoordinateSequence
+from shapely.ctypes_declarations import c_geom_p
from shapely.geos import lgeos
from shapely.geometry.base import BaseGeometry, geos_geom_from_py
from shapely.geometry.linestring import LineString, LineStringAdapter
@@ -555,16 +556,17 @@ def geos_polygon_from_py(shell, holes=None):
raise ValueError("insufficiant coordinate dimension")
# Array of pointers to ring geometries
- geos_holes = (c_void_p * L)()
+ geos_holes = (c_geom_p * L)()
# add to coordinate sequence
for l in range(L):
geom, ndim = geos_linearring_from_py(ob[l])
- geos_holes[l] = cast(geom, c_void_p)
+ geos_holes[l] = cast(geom, c_geom_p)
else:
- geos_holes = POINTER(c_void_p)()
+ geos_holes = POINTER(c_geom_p)()
L = 0
return (
- lgeos.GEOSGeom_createPolygon(
- c_void_p(geos_shell), geos_holes, L), ndim)
+ lgeos.GEOSGeom_createPolygon(cast(geos_shell, c_geom_p), geos_holes, L),
+ ndim,
+ )
=====================================
shapely/geometry/proxy.py
=====================================
@@ -34,14 +34,17 @@ class CachingGeometryProxy:
self.__geom__, n = self.factory(self.context)
self._gtag = gtag
return self.__geom__
-
+
def gtag(self):
return hash(repr(self.context))
def __setattr__(self, name, value):
# to override the custom one in BaseGeometry, so we don't warn
# for the proxy classes, which are already deprecated itself
- object.__setattr__(self, name, value)
+ try:
+ object.__setattr__(self, name, value)
+ except AttributeError:
+ pass
class PolygonProxy(CachingGeometryProxy):
=====================================
shapely/ops.py
=====================================
@@ -1,9 +1,10 @@
"""Support for various GEOS geometry operations
"""
-from ctypes import byref, c_void_p, c_double
+from ctypes import byref, cast, c_void_p, c_double
from warnings import warn
+from shapely.ctypes_declarations import c_geom_p
from shapely.errors import GeometryTypeError, ShapelyDeprecationWarning
from shapely.prepared import prep
from shapely.geos import lgeos
@@ -44,12 +45,16 @@ class CollectionOperator:
source = [source]
finally:
obs = [self.shapeup(l) for l in source]
- geom_array_type = c_void_p * len(obs)
+
+ geom_array_type = c_geom_p * len(obs)
geom_array = geom_array_type()
+
for i, line in enumerate(obs):
- geom_array[i] = line._geom
+ geom_array[i] = cast(line._geom, c_geom_p)
+
product = lgeos.GEOSPolygonize(byref(geom_array), len(obs))
collection = geom_factory(product)
+
for g in collection.geoms:
clone = lgeos.GEOSGeom_clone(g._geom)
g = geom_factory(clone)
@@ -78,16 +83,21 @@ class CollectionOperator:
source = [source]
finally:
obs = [self.shapeup(l) for l in source]
+
L = len(obs)
- subs = (c_void_p * L)()
+ subs = (c_geom_p * L)()
+
for i, g in enumerate(obs):
- subs[i] = g._geom
+ subs[i] = cast(g._geom, c_geom_p)
+
collection = lgeos.GEOSGeom_createCollection(5, subs, L)
- dangles = c_void_p()
- cuts = c_void_p()
- invalids = c_void_p()
+ dangles = c_geom_p()
+ cuts = c_geom_p()
+ invalids = c_geom_p()
product = lgeos.GEOSPolygonize_full(
- collection, byref(dangles), byref(cuts), byref(invalids))
+ collection, byref(dangles), byref(cuts), byref(invalids)
+ )
+
return (
geom_factory(product),
geom_factory(dangles),
@@ -135,9 +145,12 @@ class CollectionOperator:
except TypeError:
geoms = [geoms]
L = 1
- subs = (c_void_p * L)()
+
+ subs = (c_geom_p * L)()
+
for i, g in enumerate(geoms):
- subs[i] = g._geom
+ subs[i] = cast(g._geom, c_geom_p)
+
collection = lgeos.GEOSGeom_createCollection(6, subs, L)
return geom_factory(lgeos.methods['cascaded_union'](collection))
@@ -154,9 +167,12 @@ class CollectionOperator:
except TypeError:
geoms = [geoms]
L = 1
- subs = (c_void_p * L)()
+
+ subs = (c_geom_p * L)()
+
for i, g in enumerate(geoms):
- subs[i] = g._geom
+ subs[i] = cast(g._geom, c_geom_p)
+
collection = lgeos.GEOSGeom_createCollection(6, subs, L)
return geom_factory(lgeos.methods['unary_union'](collection))
=====================================
shapely/strtree.py
=====================================
@@ -22,7 +22,10 @@ import ctypes
import logging
from typing import Any, ItemsView, Iterable, Iterator, Optional, Sequence, Tuple, Union
import sys
+from warnings import warn
+from shapely.ctypes_declarations import c_geom_p
+from shapely.errors import ShapelyDeprecationWarning
from shapely.geometry.base import BaseGeometry
from shapely.geos import lgeos
@@ -97,6 +100,19 @@ class STRtree:
items: Iterable[Any] = None,
node_capacity: int = 10,
):
+ if items is not None:
+ warn(
+ "STRtree will be changed in 2.0.0 and will not be compatible with versions < 2. "
+ "Specifically: the items keyword argument will be removed.",
+ ShapelyDeprecationWarning,
+ stacklevel=2,
+ )
+ else:
+ warn(
+ "STRtree will be changed in 2.0.0 and will not be compatible with versions < 2.",
+ ShapelyDeprecationWarning,
+ stacklevel=2,
+ )
self.node_capacity = node_capacity
# Keep references to geoms
@@ -247,8 +263,11 @@ class STRtree:
if callback_userdata["exclusive"] and self._geoms[idx].equals(geom2):
dist[0] = sys.float_info.max
else:
- lgeos.GEOSDistance(self._geoms[idx]._geom, geom2._geom, dist)
-
+ lgeos.GEOSDistance(
+ ctypes.cast(self._geoms[idx]._geom, c_geom_p),
+ ctypes.cast(geom2._geom, c_geom_p),
+ dist,
+ )
return 1
except Exception:
log.exception("Caught exception")
=====================================
shapely/topology.py
=====================================
@@ -7,7 +7,9 @@ to GEOS functions via ctypes.
These methods return ctypes objects that should be recast by the caller.
"""
-from ctypes import byref, c_double
+from ctypes import byref, cast, c_double
+
+from shapely.ctypes_declarations import c_geom_p
from shapely.geos import TopologicalError, lgeos
from shapely.errors import InvalidGeometryError
@@ -47,7 +49,9 @@ class BinaryRealProperty(Delegating):
self._validate(this)
self._validate(other, stop_prepared=True)
d = c_double()
- retval = self.fn(this._geom, other._geom, byref(d))
+ retval = self.fn(
+ cast(this._geom, c_geom_p), cast(other._geom, c_geom_p), byref(d)
+ )
return d.value
@@ -56,7 +60,7 @@ class UnaryRealProperty(Delegating):
def __call__(self, this):
self._validate(this)
d = c_double()
- retval = self.fn(this._geom, byref(d))
+ retval = self.fn(cast(this._geom, c_geom_p), byref(d))
return d.value
=====================================
tests/test_geos_err_handler.py
=====================================
@@ -19,7 +19,8 @@ def test_error_handler_exception(tmpdir):
with pytest.raises(ReadingError):
loads('POINT (LOLWUT)')
- log = open(logfile).read()
+ with open(logfile) as fobj:
+ log = fobj.read()
assert "Expected number but encountered word: 'LOLWUT'" in log
@@ -33,7 +34,8 @@ def test_error_handler(tmpdir):
# has *no* conversion specifiers.
LineString([(0, 0), (2, 2)]).project(LineString([(1, 1), (1.5, 1.5)]))
- log = open(logfile).read()
+ with open(logfile) as fobj:
+ log = fobj.read()
assert "third argument of GEOSProject_r must be Point" in log
@@ -57,7 +59,8 @@ def test_info_handler(tmpdir):
g = loads('MULTIPOLYGON (((10 20, 10 120, 60 70, 30 70, 30 40, 60 40, 60 70, 90 20, 10 20)))')
assert not g.is_valid
- log = open(logfile).read()
+ with open(logfile) as fobj:
+ log = fobj.read()
assert "Ring Self-intersection at or near point 60 70" in log
@@ -71,5 +74,6 @@ def test_info_handler_quiet(tmpdir):
g = loads('MULTIPOLYGON (((10 20, 10 120, 60 70, 30 70, 30 40, 60 40, 60 70, 90 20, 10 20)))')
assert not g.is_valid
- log = open(logfile).read()
+ with open(logfile) as fobj:
+ log = fobj.read()
assert "Ring Self-intersection at or near point 60 70" not in log
=====================================
tests/test_linear_referencing.py
=====================================
@@ -1,5 +1,7 @@
+import pytest
+
from . import unittest
-from shapely.errors import GeometryTypeError
+from shapely.errors import GeometryTypeError, ShapelyDeprecationWarning
from shapely.geometry import Point, LineString, MultiLineString
@@ -28,8 +30,9 @@ class LinearReferencingTestCase(unittest.TestCase):
self.multiline.project(self.point, normalized=True), 0.125)
def test_not_supported_project(self):
- with self.assertRaises(GeometryTypeError):
- self.point.buffer(1.0).project(self.point)
+ with pytest.warns(ShapelyDeprecationWarning):
+ with self.assertRaises(GeometryTypeError):
+ self.point.buffer(1.0).project(self.point)
def test_not_on_line_project(self):
# Points that aren't on the line project to 0.
=====================================
tests/test_parallel_offset.py
=====================================
@@ -9,9 +9,11 @@ class OperationsTestCase(unittest.TestCase):
left = line1.parallel_offset(5, 'left')
self.assertEqual(left, LineString([(0, 5), (10, 5)]))
right = line1.parallel_offset(5, 'right')
- self.assertEqual(right, LineString([(10, -5), (0, -5)]))
+ # using spatial equality because the order of coordinates is not guaranteed
+ # (GEOS 3.11 changed this, see https://github.com/shapely/shapely/issues/1436)
+ assert right.equals(LineString([(10, -5), (0, -5)]))
right = line1.parallel_offset(-5, 'left')
- self.assertEqual(right, LineString([(10, -5), (0, -5)]))
+ assert right.equals(LineString([(10, -5), (0, -5)]))
left = line1.parallel_offset(-5, 'right')
self.assertEqual(left, LineString([(0, 5), (10, 5)]))
=====================================
tests/test_shared_paths.py
=====================================
@@ -1,16 +1,19 @@
+import pytest
+
from . import unittest
-from shapely.errors import GeometryTypeError
+from shapely.errors import GeometryTypeError, ShapelyDeprecationWarning
from shapely.geometry import Point, LineString, Polygon, MultiLineString, \
GeometryCollection
from shapely.ops import shared_paths
+
class SharedPaths(unittest.TestCase):
def test_shared_paths_forward(self):
g1 = LineString([(0, 0), (10, 0), (10, 5), (20, 5)])
g2 = LineString([(5, 0), (15, 0)])
result = shared_paths(g1, g2)
-
+
self.assertTrue(isinstance(result, GeometryCollection))
self.assertTrue(len(result.geoms) == 2)
a, b = result.geoms
@@ -23,7 +26,7 @@ class SharedPaths(unittest.TestCase):
g1 = LineString([(0, 0), (10, 0), (10, 5), (20, 5)])
g2 = LineString([(15, 0), (5, 0)])
result = shared_paths(g1, g2)
-
+
self.assertTrue(isinstance(result, GeometryCollection))
self.assertTrue(len(result.geoms) == 2)
a, b = result.geoms
@@ -31,13 +34,15 @@ class SharedPaths(unittest.TestCase):
self.assertTrue(len(b.geoms) == 1)
self.assertEqual(b.geoms[0].coords[:], [(5, 0), (10, 0)])
self.assertTrue(a.is_empty)
-
+
def test_wrong_type(self):
g1 = Point(0, 0)
g2 = LineString([(5, 0), (15, 0)])
-
- with self.assertRaises(GeometryTypeError):
- result = shared_paths(g1, g2)
-
- with self.assertRaises(GeometryTypeError):
- result = shared_paths(g2, g1)
+
+ with pytest.warns(ShapelyDeprecationWarning):
+ with self.assertRaises(GeometryTypeError):
+ result = shared_paths(g1, g2)
+
+ with pytest.warns(ShapelyDeprecationWarning):
+ with self.assertRaises(GeometryTypeError):
+ result = shared_paths(g2, g1)
=====================================
tests/test_split.py
=====================================
@@ -1,230 +1,247 @@
-from shapely.ops import split
+import pytest
from . import unittest
-from shapely.errors import GeometryTypeError
+from shapely.errors import GeometryTypeError, ShapelyDeprecationWarning
from shapely.geometry import Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection
-from shapely.ops import linemerge, unary_union
+from shapely.ops import linemerge, split, unary_union
class TestSplitGeometry(unittest.TestCase):
- # helper class for testing below
- def helper(self, geom, splitter, expected_chunks):
- s = split(geom, splitter)
- self.assertEqual(s.type, "GeometryCollection")
- self.assertEqual(len(s.geoms), expected_chunks)
- if expected_chunks > 1:
- # split --> expected collection that when merged is again equal to original geometry
- if s.geoms[0].type == 'LineString':
- self.assertTrue(linemerge(s).simplify(0.000001).equals(geom))
- elif s.geoms[0].type == 'Polygon':
- union = unary_union(s).simplify(0.000001)
- self.assertTrue(union.equals(geom))
- self.assertEqual(union.area, geom.area)
- else:
- raise ValueError
- elif expected_chunks == 1:
- # not split --> expected equal to line
- self.assertTrue(s.geoms[0].equals(geom))
-
- def test_split_closed_line_with_point(self):
- # point at start/end of closed ring -> return equal
- # see GH #524
- ls = LineString([(0,0), (0, 1), (1, 1), (1, 0), (0, 0)])
- splitter = Point(0, 0)
- self.helper(ls, splitter, 1)
+ # helper class for testing below
+ def helper(self, geom, splitter, expected_chunks):
+ s = split(geom, splitter)
+ self.assertEqual(s.type, "GeometryCollection")
+ self.assertEqual(len(s.geoms), expected_chunks)
+ if expected_chunks > 1:
+ # split --> expected collection that when merged is again equal to original geometry
+ if s.geoms[0].type == "LineString":
+ self.assertTrue(linemerge(s).simplify(0.000001).equals(geom))
+ elif s.geoms[0].type == "Polygon":
+ union = unary_union(s).simplify(0.000001)
+ self.assertTrue(union.equals(geom))
+ self.assertEqual(union.area, geom.area)
+ else:
+ raise ValueError
+ elif expected_chunks == 1:
+ # not split --> expected equal to line
+ self.assertTrue(s.geoms[0].equals(geom))
+
+ def test_split_closed_line_with_point(self):
+ # point at start/end of closed ring -> return equal
+ # see GH #524
+ ls = LineString([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
+ splitter = Point(0, 0)
+ self.helper(ls, splitter, 1)
class TestSplitPolygon(TestSplitGeometry):
- poly_simple = Polygon([(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)])
- poly_hole = Polygon([(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)], [[(0.5, 0.5), (0.5, 1.5), (1.5, 1.5), (1.5, 0.5), (0.5, 0.5)]])
-
- def test_split_poly_with_line(self):
- # crossing at 2 points --> return 2 segments
- splitter = LineString([(1, 3), (1, -3)])
- self.helper(self.poly_simple, splitter, 2)
- self.helper(self.poly_hole, splitter, 2)
-
- # touching the boundary--> return equal
- splitter = LineString([(0, 2), (5, 2)])
- self.helper(self.poly_simple, splitter, 1)
- self.helper(self.poly_hole, splitter, 1)
-
- # inside the polygon --> return equal
- splitter = LineString([(0.2, 0.2), (1.7, 1.7), (3, 2)])
- self.helper(self.poly_simple, splitter, 1)
- self.helper(self.poly_hole, splitter, 1)
-
- # outside the polygon --> return equal
- splitter = LineString([(0, 3), (3, 3) , (3, 0)])
- self.helper(self.poly_simple, splitter, 1)
- self.helper(self.poly_hole, splitter, 1)
-
- def test_split_poly_with_other(self):
- with self.assertRaises(GeometryTypeError):
- split(self.poly_simple, Point(1, 1))
- with self.assertRaises(GeometryTypeError):
- split(self.poly_simple, MultiPoint([(1, 1), (3, 4)]))
- with self.assertRaises(GeometryTypeError):
- split(self.poly_simple, self.poly_hole)
+ poly_simple = Polygon([(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)])
+ poly_hole = Polygon(
+ [(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)],
+ [[(0.5, 0.5), (0.5, 1.5), (1.5, 1.5), (1.5, 0.5), (0.5, 0.5)]],
+ )
+
+ def test_split_poly_with_line(self):
+ # crossing at 2 points --> return 2 segments
+ splitter = LineString([(1, 3), (1, -3)])
+ self.helper(self.poly_simple, splitter, 2)
+ self.helper(self.poly_hole, splitter, 2)
+
+ # touching the boundary--> return equal
+ splitter = LineString([(0, 2), (5, 2)])
+ self.helper(self.poly_simple, splitter, 1)
+ self.helper(self.poly_hole, splitter, 1)
+
+ # inside the polygon --> return equal
+ splitter = LineString([(0.2, 0.2), (1.7, 1.7), (3, 2)])
+ self.helper(self.poly_simple, splitter, 1)
+ self.helper(self.poly_hole, splitter, 1)
+
+ # outside the polygon --> return equal
+ splitter = LineString([(0, 3), (3, 3), (3, 0)])
+ self.helper(self.poly_simple, splitter, 1)
+ self.helper(self.poly_hole, splitter, 1)
+
+ def test_split_poly_with_point(self):
+ with pytest.warns(ShapelyDeprecationWarning):
+ with self.assertRaises(GeometryTypeError):
+ split(self.poly_simple, Point(1, 1))
+
+ def test_split_poly_with_multipoint(self):
+ with pytest.warns(ShapelyDeprecationWarning):
+ with self.assertRaises(GeometryTypeError):
+ split(self.poly_simple, MultiPoint([(1, 1), (3, 4)]))
+
+ def test_split_poly_with_poly(self):
+ with pytest.warns(ShapelyDeprecationWarning):
+ with self.assertRaises(GeometryTypeError):
+ split(self.poly_simple, self.poly_hole)
class TestSplitLine(TestSplitGeometry):
- ls = LineString([(0, 0), (1.5, 1.5), (3.0, 4.0)])
-
- def test_split_line_with_point(self):
- # point on line interior --> return 2 segments
- splitter = Point(1, 1)
- self.helper(self.ls, splitter, 2)
-
- # point on line point --> return 2 segments
- splitter = Point(1.5, 1.5)
- self.helper(self.ls, splitter, 2)
-
- # point on boundary --> return equal
- splitter = Point(3, 4)
- self.helper(self.ls, splitter, 1)
-
- # point on exterior of line --> return equal
- splitter = Point(2, 2)
- self.helper(self.ls, splitter, 1)
-
- def test_split_line_with_multipoint(self):
- # points on line interior --> return 4 segments
- splitter = MultiPoint([(1,1), (1.5, 1.5), (0.5, 0.5)])
- self.helper(self.ls, splitter, 4)
-
- # points on line interior and boundary -> return 2 segments
- splitter = MultiPoint([(1, 1), (3, 4)])
- self.helper(self.ls, splitter, 2)
-
- # point on linear interior but twice --> return 2 segments
- splitter = MultiPoint([(1, 1), (1.5, 1.5), (1, 1)])
- self.helper(self.ls, splitter, 3)
-
- def test_split_line_with_line(self):
- # crosses at one point --> return 2 segments
- splitter = LineString([(0, 1), (1, 0)])
- self.helper(self.ls, splitter, 2)
-
- # crosses at two points --> return 3 segments
- splitter = LineString([(0, 1), (1, 0), (1, 2)])
- self.helper(self.ls, splitter, 3)
-
- # overlaps --> raise
- splitter = LineString([(0, 0), (15, 15)])
- with self.assertRaises(ValueError):
- self.helper(self.ls, splitter, 1)
-
- # does not cross --> return equal
- splitter = LineString([(0, 1), (0, 2)])
- self.helper(self.ls, splitter, 1)
-
- # is touching the boundary --> return equal
- splitter = LineString([(-1, 1), (1, -1)])
- self.assertTrue(splitter.touches(self.ls))
- self.helper(self.ls, splitter, 1)
-
- # splitter boundary touches interior of line --> return 2 segments
- splitter = LineString([(0, 1), (1, 1)]) # touches at (1, 1)
- self.assertTrue(splitter.touches(self.ls))
- self.helper(self.ls, splitter, 2)
-
- def test_split_line_with_multiline(self):
- # crosses at one point --> return 2 segments
- splitter = MultiLineString([[(0, 1), (1, 0)], [(0, 0), (2, -2)]])
- self.helper(self.ls, splitter, 2)
-
- # crosses at two points --> return 3 segments
- splitter = MultiLineString([[(0, 1), (1, 0)], [(0, 2), (2, 0)]])
- self.helper(self.ls, splitter, 3)
-
- # crosses at three points --> return 4 segments
- splitter = MultiLineString([[(0, 1), (1, 0)], [(0, 2), (2, 0), (2.2, 3.2)]])
- self.helper(self.ls, splitter, 4)
-
- # overlaps --> raise
- splitter = MultiLineString([[(0, 0), (1.5, 1.5)], [(1.5, 1.5), (3, 4)]])
- with self.assertRaises(ValueError):
- self.helper(self.ls, splitter, 1)
-
- # does not cross --> return equal
- splitter = MultiLineString([[(0, 1), (0, 2)], [(1, 0), (2, 0)]])
- self.helper(self.ls, splitter, 1)
-
- def test_split_line_with_polygon(self):
- # crosses at two points --> return 3 segments
- splitter = Polygon([(1, 0), (1, 2), (2, 2), (2, 0), (1, 0)])
- self.helper(self.ls, splitter, 3)
-
- # crosses at one point and touches boundary --> return 2 segments
- splitter = Polygon([(0, 0), (1, 2), (2, 2), (1, 0), (0, 0)])
- self.helper(self.ls, splitter, 2)
-
- # exterior crosses at one point and touches at (0, 0)
- # interior crosses at two points
- splitter = Polygon([(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)], [[(0.5, 0.5), (0.5, 1.5), (1.5, 1.5), (1.5, 0.5), (0.5, 0.5)]])
- self.helper(self.ls, splitter, 4)
-
- def test_split_line_with_multipolygon(self):
- poly1 = Polygon([(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)]) # crosses at one point and touches at (0, 0)
- poly2 = Polygon([(0.5, 0.5), (0.5, 1.5), (1.5, 1.5), (1.5, 0.5), (0.5, 0.5)]) # crosses at two points
- poly3 = Polygon([(0, 0), (0, -2), (-2, -2), (-2, 0), (0, 0)]) # not crossing
- splitter = MultiPolygon([poly1, poly2, poly3])
- self.helper(self.ls, splitter, 4)
+ ls = LineString([(0, 0), (1.5, 1.5), (3.0, 4.0)])
+
+ def test_split_line_with_point(self):
+ # point on line interior --> return 2 segments
+ splitter = Point(1, 1)
+ self.helper(self.ls, splitter, 2)
+
+ # point on line point --> return 2 segments
+ splitter = Point(1.5, 1.5)
+ self.helper(self.ls, splitter, 2)
+
+ # point on boundary --> return equal
+ splitter = Point(3, 4)
+ self.helper(self.ls, splitter, 1)
+
+ # point on exterior of line --> return equal
+ splitter = Point(2, 2)
+ self.helper(self.ls, splitter, 1)
+
+ def test_split_line_with_multipoint(self):
+ # points on line interior --> return 4 segments
+ splitter = MultiPoint([(1, 1), (1.5, 1.5), (0.5, 0.5)])
+ self.helper(self.ls, splitter, 4)
+
+ # points on line interior and boundary -> return 2 segments
+ splitter = MultiPoint([(1, 1), (3, 4)])
+ self.helper(self.ls, splitter, 2)
+
+ # point on linear interior but twice --> return 2 segments
+ splitter = MultiPoint([(1, 1), (1.5, 1.5), (1, 1)])
+ self.helper(self.ls, splitter, 3)
+
+ def test_split_line_with_line(self):
+ # crosses at one point --> return 2 segments
+ splitter = LineString([(0, 1), (1, 0)])
+ self.helper(self.ls, splitter, 2)
+
+ # crosses at two points --> return 3 segments
+ splitter = LineString([(0, 1), (1, 0), (1, 2)])
+ self.helper(self.ls, splitter, 3)
+
+ # overlaps --> raise
+ splitter = LineString([(0, 0), (15, 15)])
+ with self.assertRaises(ValueError):
+ self.helper(self.ls, splitter, 1)
+
+ # does not cross --> return equal
+ splitter = LineString([(0, 1), (0, 2)])
+ self.helper(self.ls, splitter, 1)
+
+ # is touching the boundary --> return equal
+ splitter = LineString([(-1, 1), (1, -1)])
+ self.assertTrue(splitter.touches(self.ls))
+ self.helper(self.ls, splitter, 1)
+
+ # splitter boundary touches interior of line --> return 2 segments
+ splitter = LineString([(0, 1), (1, 1)]) # touches at (1, 1)
+ self.assertTrue(splitter.touches(self.ls))
+ self.helper(self.ls, splitter, 2)
+
+ def test_split_line_with_multiline(self):
+ # crosses at one point --> return 2 segments
+ splitter = MultiLineString([[(0, 1), (1, 0)], [(0, 0), (2, -2)]])
+ self.helper(self.ls, splitter, 2)
+
+ # crosses at two points --> return 3 segments
+ splitter = MultiLineString([[(0, 1), (1, 0)], [(0, 2), (2, 0)]])
+ self.helper(self.ls, splitter, 3)
+
+ # crosses at three points --> return 4 segments
+ splitter = MultiLineString([[(0, 1), (1, 0)], [(0, 2), (2, 0), (2.2, 3.2)]])
+ self.helper(self.ls, splitter, 4)
+
+ # overlaps --> raise
+ splitter = MultiLineString([[(0, 0), (1.5, 1.5)], [(1.5, 1.5), (3, 4)]])
+ with self.assertRaises(ValueError):
+ self.helper(self.ls, splitter, 1)
+
+ # does not cross --> return equal
+ splitter = MultiLineString([[(0, 1), (0, 2)], [(1, 0), (2, 0)]])
+ self.helper(self.ls, splitter, 1)
+
+ def test_split_line_with_polygon(self):
+ # crosses at two points --> return 3 segments
+ splitter = Polygon([(1, 0), (1, 2), (2, 2), (2, 0), (1, 0)])
+ self.helper(self.ls, splitter, 3)
+
+ # crosses at one point and touches boundary --> return 2 segments
+ splitter = Polygon([(0, 0), (1, 2), (2, 2), (1, 0), (0, 0)])
+ self.helper(self.ls, splitter, 2)
+
+ # exterior crosses at one point and touches at (0, 0)
+ # interior crosses at two points
+ splitter = Polygon(
+ [(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)],
+ [[(0.5, 0.5), (0.5, 1.5), (1.5, 1.5), (1.5, 0.5), (0.5, 0.5)]],
+ )
+ self.helper(self.ls, splitter, 4)
+
+ def test_split_line_with_multipolygon(self):
+ poly1 = Polygon(
+ [(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)]
+ ) # crosses at one point and touches at (0, 0)
+ poly2 = Polygon(
+ [(0.5, 0.5), (0.5, 1.5), (1.5, 1.5), (1.5, 0.5), (0.5, 0.5)]
+ ) # crosses at two points
+ poly3 = Polygon([(0, 0), (0, -2), (-2, -2), (-2, 0), (0, 0)]) # not crossing
+ splitter = MultiPolygon([poly1, poly2, poly3])
+ self.helper(self.ls, splitter, 4)
class TestSplitClosedRing(TestSplitGeometry):
- ls = LineString([[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]])
+ ls = LineString([[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]])
- def test_split_closed_ring_with_point(self):
- splitter = Point([0.0, 0.0])
- self.helper(self.ls, splitter, 1)
+ def test_split_closed_ring_with_point(self):
+ splitter = Point([0.0, 0.0])
+ self.helper(self.ls, splitter, 1)
- splitter = Point([0.0, 0.5])
- self.helper(self.ls, splitter, 2)
- result = split(self.ls, splitter)
- assert result.geoms[0].coords[:] == [(0, 0), (0.0, 0.5)]
- assert result.geoms[1].coords[:] == [(0.0, 0.5), (0, 1), (1, 1), (1, 0), (0, 0)]
+ splitter = Point([0.0, 0.5])
+ self.helper(self.ls, splitter, 2)
+ result = split(self.ls, splitter)
+ assert result.geoms[0].coords[:] == [(0, 0), (0.0, 0.5)]
+ assert result.geoms[1].coords[:] == [(0.0, 0.5), (0, 1), (1, 1), (1, 0), (0, 0)]
- # previously failed, see GH#585
- splitter = Point([0.5, 0.0])
- self.helper(self.ls, splitter, 2)
- result = split(self.ls, splitter)
- assert result.geoms[0].coords[:] == [(0, 0), (0, 1), (1, 1), (1, 0), (0.5, 0)]
- assert result.geoms[1].coords[:] == [(0.5, 0), (0, 0)]
+ # previously failed, see GH#585
+ splitter = Point([0.5, 0.0])
+ self.helper(self.ls, splitter, 2)
+ result = split(self.ls, splitter)
+ assert result.geoms[0].coords[:] == [(0, 0), (0, 1), (1, 1), (1, 0), (0.5, 0)]
+ assert result.geoms[1].coords[:] == [(0.5, 0), (0, 0)]
- splitter = Point([2.0, 2.0])
- self.helper(self.ls, splitter, 1)
+ splitter = Point([2.0, 2.0])
+ self.helper(self.ls, splitter, 1)
class TestSplitMulti(TestSplitGeometry):
- def test_split_multiline_with_point(self):
- # a cross-like multilinestring with a point in the middle --> return 4 line segments
- l1 = LineString([(0, 1), (2, 1)])
- l2 = LineString([(1, 0), (1, 2)])
- ml = MultiLineString([l1, l2])
- splitter = Point((1, 1))
- self.helper(ml, splitter, 4)
-
- def test_split_multiline_with_multipoint(self):
- # a cross-like multilinestring with a point in middle, a point on one of the lines and a point in the exterior
- # --> return 4+1 line segments
- l1 = LineString([(0, 1), (3, 1)])
- l2 = LineString([(1, 0), (1, 2)])
- ml = MultiLineString([l1, l2])
- splitter = MultiPoint([(1, 1), (2, 1), (4, 2)])
- self.helper(ml, splitter, 5)
-
- def test_split_multipolygon_with_line(self):
- # two polygons with a crossing line --> return 4 triangles
- poly1 = Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)])
- poly2 = Polygon([(1, 1), (1, 2), (2, 2), (2, 1), (1, 1)])
- mpoly = MultiPolygon([poly1, poly2])
- ls = LineString([(-1, -1), (3, 3)])
- self.helper(mpoly, ls, 4)
-
- # two polygons away from the crossing line --> return identity
- poly1 = Polygon([(10, 10), (10, 11), (11, 11), (11, 10), (10, 10)])
- poly2 = Polygon([(-10, -10), (-10, -11), (-11, -11), (-11, -10), (-10, -10)])
- mpoly = MultiPolygon([poly1, poly2])
- ls = LineString([(-1, -1), (3, 3)])
- self.helper(mpoly, ls, 2)
+ def test_split_multiline_with_point(self):
+ # a cross-like multilinestring with a point in the middle --> return 4 line segments
+ l1 = LineString([(0, 1), (2, 1)])
+ l2 = LineString([(1, 0), (1, 2)])
+ ml = MultiLineString([l1, l2])
+ splitter = Point((1, 1))
+ self.helper(ml, splitter, 4)
+
+ def test_split_multiline_with_multipoint(self):
+ # a cross-like multilinestring with a point in middle, a point on one of the lines and a point in the exterior
+ # --> return 4+1 line segments
+ l1 = LineString([(0, 1), (3, 1)])
+ l2 = LineString([(1, 0), (1, 2)])
+ ml = MultiLineString([l1, l2])
+ splitter = MultiPoint([(1, 1), (2, 1), (4, 2)])
+ self.helper(ml, splitter, 5)
+
+ def test_split_multipolygon_with_line(self):
+ # two polygons with a crossing line --> return 4 triangles
+ poly1 = Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)])
+ poly2 = Polygon([(1, 1), (1, 2), (2, 2), (2, 1), (1, 1)])
+ mpoly = MultiPolygon([poly1, poly2])
+ ls = LineString([(-1, -1), (3, 3)])
+ self.helper(mpoly, ls, 4)
+
+ # two polygons away from the crossing line --> return identity
+ poly1 = Polygon([(10, 10), (10, 11), (11, 11), (11, 10), (10, 10)])
+ poly2 = Polygon([(-10, -10), (-10, -11), (-11, -11), (-11, -10), (-10, -10)])
+ mpoly = MultiPolygon([poly1, poly2])
+ ls = LineString([(-1, -1), (3, 3)])
+ self.helper(mpoly, ls, 2)
=====================================
tests/test_strtree.py
=====================================
@@ -6,6 +6,7 @@ import sys
import pytest
+from shapely.errors import ShapelyDeprecationWarning
from shapely.geometry import Point, Polygon, box
from shapely.geos import geos_version
from shapely import strtree
@@ -26,7 +27,8 @@ empty = wkt.loads("GEOMETRYCOLLECTION EMPTY")
[(Point(2, 2).buffer(0.99), 1), (Point(2, 2).buffer(1.0), 3)],
)
def test_query(geoms, query_geom, num_results):
- tree = STRtree(geoms)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms)
results = tree.query(query_geom)
assert len(results) == num_results
@@ -39,7 +41,8 @@ def test_query(geoms, query_geom, num_results):
)
def test_query_enumeration_idx(geoms, query_geom, expected):
"""Store enumeration idx"""
- tree = STRtree(geoms, range(len(geoms)))
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms, range(len(geoms)))
results = tree.query_items(query_geom)
assert sorted(results) == sorted(expected)
@@ -53,7 +56,8 @@ def test_query_enumeration_idx(geoms, query_geom, expected):
)
def test_query_items(geoms, items, query_geom, expected):
"""Store enumeration idx"""
- tree = STRtree(geoms, items)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms, items)
results = tree.query_items(query_geom)
expected = [items[idx] for idx in expected] if items is not None else expected
assert sorted(results) == sorted(expected)
@@ -70,7 +74,8 @@ def test_query_items(geoms, items, query_geom, expected):
],
)
def test_query_items_with_empty(tree_geometry, geometry, expected):
- tree = STRtree(tree_geometry)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(tree_geometry)
assert tree.query_items(geometry) == expected
@@ -82,7 +87,8 @@ def test_insert_empty_geometry():
"""
empty = Polygon()
geoms = [empty]
- tree = STRtree(geoms)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms)
query = Polygon([(0, 0), (1, 1), (2, 0), (0, 0)])
results = tree.query(query)
assert len(results) == 0
@@ -97,7 +103,8 @@ def test_query_empty_geometry():
empty = Polygon()
point = Point(1, 0.5)
geoms = [empty, point]
- tree = STRtree(geoms)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms)
query = Polygon([(0, 0), (1, 1), (2, 0), (0, 0)])
results = tree.query(query)
assert len(results) == 1
@@ -110,7 +117,8 @@ def test_references():
empty = Polygon()
point = Point(1, 0.5)
geoms = [empty, point]
- tree = STRtree(geoms)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms)
empty = None
point = None
@@ -124,7 +132,8 @@ def test_references():
@requires_geos_342
def test_safe_delete():
- tree = STRtree([])
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree([])
_lgeos = strtree.lgeos
strtree.lgeos = None
@@ -139,7 +148,8 @@ def test_pickle_persistence():
"""
Don't crash trying to use unpickled GEOS handle.
"""
- tree = STRtree([Point(i, i).buffer(0.1) for i in range(3)], range(3))
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree([Point(i, i).buffer(0.1) for i in range(3)], range(3))
pickled_strtree = pickle.dumps(tree)
unpickle_script_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "unpickle-strtree.py")
@@ -165,7 +175,8 @@ def test_pickle_persistence():
)
@pytest.mark.parametrize("query_geom", [Point(0, 0.4)])
def test_nearest_geom(geoms, query_geom):
- tree = STRtree(geoms)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms)
result = tree.nearest(query_geom)
assert result.geom_type == "Point"
assert result.x == 0.0
@@ -186,19 +197,22 @@ def test_nearest_geom(geoms, query_geom):
@pytest.mark.parametrize("items", [list(range(1, 4)), list("abc")])
@pytest.mark.parametrize("query_geom", [Point(0, 0.4)])
def test_nearest_item(geoms, items, query_geom):
- tree = STRtree(geoms, items)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms, items)
assert tree.nearest_item(query_geom) == items[0]
@pytest.mark.parametrize(["geoms", "items"], [([], None), ([], [])])
def test_nearest_empty(geoms, items):
- tree = STRtree(geoms, items)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms, items)
assert tree.nearest_item(None) is None
@pytest.mark.parametrize(["geoms", "items"], [([], None), ([], [])])
def test_nearest_items(geoms, items):
- tree = STRtree(geoms, items)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms, items)
assert tree.nearest_item(None) is None
@@ -216,5 +230,6 @@ def test_nearest_items(geoms, items):
@pytest.mark.parametrize("items", [list(range(1, 4)), list("abc")])
@pytest.mark.parametrize("query_geom", [Point(0, 0.5)])
def test_nearest_item_exclusive(geoms, items, query_geom):
- tree = STRtree(geoms, items)
+ with pytest.warns(ShapelyDeprecationWarning):
+ tree = STRtree(geoms, items)
assert tree.nearest_item(query_geom, exclusive=True) != items[0]
=====================================
tests/test_substring.py
=====================================
@@ -1,7 +1,9 @@
import json
+import pytest
+
from . import unittest
-from shapely.errors import GeometryTypeError
+from shapely.errors import GeometryTypeError, ShapelyDeprecationWarning
from shapely.ops import substring
from shapely.geometry import Point, LineString, shape
@@ -106,7 +108,8 @@ class SubstringTestCase(unittest.TestCase):
assert len(cut_line.coords) == 53
def test_raise_type_error(self):
- self.assertRaises(GeometryTypeError, substring, Point(0, 0), 0, 0)
+ with pytest.warns(ShapelyDeprecationWarning):
+ self.assertRaises(GeometryTypeError, substring, Point(0, 0), 0, 0)
data_issue_848 = '{"type": "LineString", "coordinates": [[-87.71314, 41.96793], [-87.71312, 41.96667], [-87.71311, 41.96643], [-87.7131, 41.96635], [-87.71309, 41.9663], [-87.71303, 41.96621], [-87.71298, 41.96615], [-87.71292, 41.96611], [-87.7128, 41.96607], [-87.71268, 41.96605], [-87.71255, 41.96605], [-87.7124, 41.96605], [-87.71219, 41.96605], [-87.71173, 41.96606], [-87.71108, 41.96607], [-87.71027, 41.96607], [-87.70884, 41.96609], [-87.70763, 41.96611], [-87.70645, 41.96612], [-87.70399, 41.96613], [-87.70267, 41.96614], [-87.70166, 41.96615], [-87.70075, 41.96615], [-87.69954, 41.96615], [-87.69873, 41.96616], [-87.69789, 41.96618], [-87.69675, 41.9662], [-87.69502, 41.96621], [-87.69411, 41.96621], [-87.69145, 41.96623], [-87.69026, 41.96624], [-87.68946, 41.96625], [-87.6885, 41.96625], [-87.68718, 41.96628], [-87.68545, 41.96631], [-87.68399, 41.96632], [-87.68271, 41.96635], [-87.68159, 41.96636], [-87.68034, 41.96638], [-87.67863, 41.96641], [-87.67766, 41.96642], [-87.67741, 41.96641], [-87.67722, 41.9664], [-87.67695, 41.96638], [-87.67665, 41.96632], [-87.67638, 41.96623], [-87.67613, 41.96612], [-87.67589, 41.96596], [-87.6757, 41.96579], [-87.67557, 41.96565], [-87.67544, 41.96547], [-87.67539, 41.96536], [-87.6753, 41.96519], [-87.67524, 41.96503], [-87.67523, 41.96491], [-87.67522, 41.96477], [-87.67521, 41.96457], [-87.6752, 41.96434], [-87.67519, 41.96371], [-87.67517, 41.96175], [-87.67513, 41.96077], [-87.67505, 41.95798], [-87.67501, 41.95666], [-87.67497, 41.95513], [-87.67496, 41.95452], [-87.67491, 41.95392], [-87.67487, 41.95302], [-87.67485, 41.95202], [-87.67484, 41.95101], [-87.67479, 41.94959], [-87.67476, 41.94859], [-87.67474, 41.94703], [-87.67468, 41.94596], [-87.67466, 41.94513], [-87.67463, 41.94494], [-87.67457, 41.94474], [-87.6745, 41.94455], [-87.67442, 41.94438], [-87.6743, 41.94424], [-87.67419, 41.94414], [-87.67405, 41.94404], [-87.67386, 41.94393], [-87.67367, 41.94386], [-87.67348, 41.9438], [-87.67334, 41.94376], [-87.67311, 41.94373], [-87.67289, 41.9437], [-87.67263, 41.94369], [-87.67234, 41.94369], [-87.6715, 41.9437], [-87.67088, 41.94371], [-87.66938, 41.94373], [-87.66749, 41.94377], [-87.66585, 41.94378], [-87.66508, 41.94379], [-87.66361, 41.94381], [-87.6591, 41.94391], [-87.65767, 41.94391], [-87.65608, 41.94393], [-87.6555, 41.94394], [-87.65521, 41.94394], [-87.65503, 41.94393], [-87.65488, 41.9439], [-87.6547, 41.94386], [-87.65454, 41.9438], [-87.65441, 41.94375], [-87.65425, 41.94364], [-87.6541, 41.94351], [-87.654, 41.94342], [-87.65392, 41.94331], [-87.65382, 41.94319], [-87.65375, 41.94306], [-87.65367, 41.94292], [-87.65361, 41.9428], [-87.65355, 41.94269], [-87.65351, 41.94257], [-87.65347, 41.94238], [-87.65345, 41.94218], [-87.65338, 41.93975], [-87.65337, 41.93939], [-87.65337, 41.93893], [-87.65336, 41.93865], [-87.65333, 41.93763], [-87.65331, 41.93717], [-87.65328, 41.93627], [-87.65327, 41.93603], [-87.65323, 41.93532], [-87.65322, 41.93491], [-87.6532, 41.93445], [-87.65314, 41.93312], [-87.65313, 41.93273], [-87.6531, 41.93218], [-87.65307, 41.93151], [-87.65305, 41.9309], [-87.65302, 41.9303], [-87.65299, 41.92951], [-87.65296, 41.9287], [-87.65295, 41.92842], [-87.65294, 41.92768], [-87.65292, 41.92715], [-87.65289, 41.92599], [-87.65288, 41.92537], [-87.65287, 41.92505], [-87.65282, 41.92352], [-87.65276, 41.92172], [-87.65274, 41.92113], [-87.65264, 41.91822], [-87.65264, 41.91808], [-87.65262, 41.91763], [-87.65261, 41.91718], [-87.65255, 41.91563], [-87.6525, 41.91406], [-87.65242, 41.91377], [-87.65234, 41.91362], [-87.65223, 41.91351], [-87.65208, 41.91339], [-87.65183, 41.91322], [-87.65093, 41.9126], [-87.65017, 41.91203], [-87.64985, 41.9118], [-87.64971, 41.91171], [-87.64957, 41.91164], [-87.64948, 41.9116], [-87.64939, 41.91158], [-87.6492, 41.91153], [-87.649, 41.9115], [-87.64883, 41.9115], [-87.64863, 41.9115], [-87.64792, 41.91151], [-87.64781, 41.9115], [-87.64768, 41.91146], [-87.64756, 41.91139], [-87.64745, 41.91122], [-87.6474, 41.91112], [-87.64739, 41.91101], [-87.64738, 41.91086], [-87.64736, 41.91071], [-87.64734, 41.91061], [-87.64728, 41.91051], [-87.64718, 41.91044], [-87.64709, 41.9104], [-87.64697, 41.91036], [-87.64682, 41.91034], [-87.64664, 41.91033], [-87.64646, 41.91033], [-87.6458, 41.91034], [-87.64523, 41.91034], [-87.64348, 41.91036], [-87.64255, 41.91039], [-87.641, 41.9104], [-87.64038, 41.9104], [-87.63975, 41.9104], [-87.6393, 41.91041], [-87.63814, 41.91042], [-87.63798, 41.91041], [-87.63787, 41.91039], [-87.63771, 41.91034], [-87.63757, 41.91027], [-87.63746, 41.91021], [-87.63736, 41.91011], [-87.6373, 41.90999], [-87.63727, 41.90986], [-87.63726, 41.90973], [-87.63725, 41.90951], [-87.63723, 41.90874], [-87.63718, 41.90758], [-87.63713, 41.90607], [-87.63711, 41.90543], [-87.63702, 41.90381], [-87.63702, 41.90368], [-87.63701, 41.90334], [-87.63699, 41.90322], [-87.63694, 41.90312], [-87.63688, 41.90299], [-87.63682, 41.90292], [-87.63671, 41.90279], [-87.63659, 41.90265], [-87.63653, 41.90255], [-87.63649, 41.90245], [-87.63646, 41.90235], [-87.63647, 41.90221], [-87.63647, 41.90211], [-87.6365, 41.90202], [-87.63653, 41.9019], [-87.63659, 41.90177], [-87.63666, 41.90156], [-87.63669, 41.90143], [-87.6367, 41.90131], [-87.6367, 41.90119], [-87.63664, 41.90029], [-87.63664, 41.90008], [-87.63662, 41.89975], [-87.63658, 41.89892], [-87.63657, 41.89867], [-87.63654, 41.89761], [-87.63654, 41.89738], [-87.63649, 41.89726], [-87.63641, 41.89715], [-87.63634, 41.89708], [-87.63623, 41.89699], [-87.63595, 41.89677], [-87.63583, 41.89667], [-87.63574, 41.89654], [-87.63569, 41.89645], [-87.63568, 41.89633], [-87.63565, 41.89542], [-87.63563, 41.89434], [-87.6356, 41.89327], [-87.63558, 41.89261], [-87.63554, 41.89147], [-87.63553, 41.89051], [-87.63548, 41.8903], [-87.6354, 41.89021], [-87.63533, 41.89012], [-87.63524, 41.89007], [-87.63508, 41.89001], [-87.63493, 41.88997], [-87.63475, 41.88994], [-87.63462, 41.88991], [-87.63447, 41.88989], [-87.63436, 41.88984], [-87.63425, 41.88979], [-87.63414, 41.8897], [-87.63407, 41.88962], [-87.63402, 41.88952], [-87.63399, 41.88943], [-87.63397, 41.88897], [-87.63396, 41.88707], [-87.63391, 41.88572], [-87.63389, 41.88441], [-87.63385, 41.8827], [-87.63384, 41.88144], [-87.63378, 41.88014], [-87.63374, 41.87872], [-87.63369, 41.87726], [-87.63369, 41.87706], [-87.63365, 41.87695], [-87.63359, 41.87691], [-87.63353, 41.87688], [-87.63345, 41.87686], [-87.63338, 41.87685], [-87.63263, 41.87685], [-87.63173, 41.87686], [-87.62925, 41.87689], [-87.62821, 41.87691], [-87.62757, 41.87693], [-87.6265, 41.87696], [-87.62635, 41.87696], [-87.62603, 41.87697], [-87.62605, 41.87831], [-87.6261, 41.87951], [-87.62616, 41.88203], [-87.62619, 41.88322], [-87.62622, 41.88443], [-87.62626, 41.88534], [-87.62625, 41.88552], [-87.62625, 41.88557], [-87.62627, 41.88562], [-87.6263, 41.88566], [-87.62635, 41.88569], [-87.62642, 41.88572], [-87.6265, 41.88573], [-87.62655, 41.88574], [-87.62661, 41.88574], [-87.62683, 41.88574], [-87.62784, 41.88574], [-87.62887, 41.88574], [-87.62948, 41.88574], [-87.62982, 41.88574], [-87.62992, 41.88574], [-87.63011, 41.88574], [-87.6302, 41.88574], [-87.63089, 41.88574], [-87.63204, 41.88574], [-87.63285, 41.88573], [-87.63391, 41.88572], [-87.63396, 41.88707], [-87.63397, 41.88897], [-87.63399, 41.88943], [-87.63402, 41.88952], [-87.63407, 41.88962], [-87.63414, 41.8897], [-87.63425, 41.88979], [-87.63436, 41.88984], [-87.63447, 41.88989], [-87.63462, 41.88991], [-87.63475, 41.88994], [-87.63493, 41.88997], [-87.63508, 41.89001], [-87.63524, 41.89007], [-87.63533, 41.89012], [-87.6354, 41.89021], [-87.63548, 41.8903], [-87.63553, 41.89051], [-87.63554, 41.89147], [-87.63558, 41.89261], [-87.6356, 41.89327], [-87.63563, 41.89434], [-87.63565, 41.89542], [-87.63568, 41.89633], [-87.63569, 41.89645], [-87.63574, 41.89654], [-87.63583, 41.89667], [-87.63595, 41.89677], [-87.63623, 41.89699], [-87.63634, 41.89708], [-87.63641, 41.89715], [-87.63649, 41.89726], [-87.63654, 41.89738], [-87.63654, 41.89761], [-87.63657, 41.89867], [-87.63658, 41.89892], [-87.63662, 41.89975], [-87.63664, 41.90008], [-87.63664, 41.90029], [-87.6367, 41.90119], [-87.6367, 41.90131], [-87.63669, 41.90143], [-87.63666, 41.90156], [-87.63659, 41.90177], [-87.63653, 41.9019], [-87.6365, 41.90202], [-87.63647, 41.90211], [-87.63647, 41.90221], [-87.63646, 41.90235], [-87.63649, 41.90245], [-87.63653, 41.90255], [-87.63659, 41.90265], [-87.63671, 41.90279], [-87.63682, 41.90292], [-87.63688, 41.90299], [-87.63694, 41.90312], [-87.63699, 41.90322], [-87.63701, 41.90334], [-87.63702, 41.90368], [-87.63702, 41.90381], [-87.63711, 41.90543], [-87.63713, 41.90607], [-87.63718, 41.90758], [-87.63723, 41.90874], [-87.63725, 41.90951], [-87.63726, 41.90973], [-87.63727, 41.90986], [-87.6373, 41.90999], [-87.63736, 41.91011], [-87.63746, 41.91021], [-87.63757, 41.91027], [-87.63771, 41.91034], [-87.63787, 41.91039], [-87.63798, 41.91041], [-87.63814, 41.91042], [-87.6393, 41.91041], [-87.63975, 41.9104], [-87.64038, 41.9104], [-87.641, 41.9104], [-87.64255, 41.91039], [-87.64348, 41.91036], [-87.64523, 41.91034], [-87.6458, 41.91034], [-87.64646, 41.91033], [-87.64664, 41.91033], [-87.64682, 41.91034], [-87.64697, 41.91036], [-87.64709, 41.9104], [-87.64718, 41.91044], [-87.64728, 41.91051], [-87.64734, 41.91061], [-87.64736, 41.91071], [-87.64738, 41.91086], [-87.64739, 41.91101], [-87.6474, 41.91112], [-87.64745, 41.91122], [-87.64756, 41.91139], [-87.64768, 41.91146], [-87.64781, 41.9115], [-87.64792, 41.91151], [-87.64863, 41.9115], [-87.64883, 41.9115], [-87.649, 41.9115], [-87.6492, 41.91153], [-87.64939, 41.91158], [-87.64948, 41.9116], [-87.64957, 41.91164], [-87.64971, 41.91171], [-87.64985, 41.9118], [-87.65017, 41.91203], [-87.65093, 41.9126], [-87.65183, 41.91322], [-87.65208, 41.91339], [-87.65223, 41.91351], [-87.65234, 41.91362], [-87.65242, 41.91377], [-87.6525, 41.91406], [-87.65255, 41.91563], [-87.65261, 41.91718], [-87.65262, 41.91763], [-87.65264, 41.91808], [-87.65264, 41.91822], [-87.65274, 41.92113], [-87.65276, 41.92172], [-87.65282, 41.92352], [-87.65287, 41.92505], [-87.65288, 41.92537], [-87.65289, 41.92599], [-87.65292, 41.92715], [-87.65294, 41.92768], [-87.65295, 41.92842], [-87.65296, 41.9287], [-87.65299, 41.92951], [-87.65302, 41.9303], [-87.65305, 41.9309], [-87.65307, 41.93151], [-87.6531, 41.93218], [-87.65313, 41.93273], [-87.65314, 41.93312], [-87.6532, 41.93445], [-87.65322, 41.93491], [-87.65323, 41.93532], [-87.65327, 41.93603], [-87.65328, 41.93627], [-87.65331, 41.93717], [-87.65333, 41.93763], [-87.65336, 41.93865], [-87.65337, 41.93893], [-87.65337, 41.93939], [-87.65338, 41.93975], [-87.65345, 41.94218], [-87.65347, 41.94238], [-87.65351, 41.94257], [-87.65355, 41.94269], [-87.65361, 41.9428], [-87.65367, 41.94292], [-87.65375, 41.94306], [-87.65382, 41.94319], [-87.65392, 41.94331], [-87.654, 41.94342], [-87.6541, 41.94351], [-87.65425, 41.94364], [-87.65441, 41.94375], [-87.65454, 41.9438], [-87.6547, 41.94386], [-87.65488, 41.9439], [-87.65503, 41.94393], [-87.65521, 41.94394], [-87.6555, 41.94394], [-87.65608, 41.94393], [-87.65767, 41.94391], [-87.6591, 41.94391], [-87.66361, 41.94381], [-87.66508, 41.94379], [-87.66585, 41.94378], [-87.66749, 41.94377], [-87.66938, 41.94373], [-87.67088, 41.94371], [-87.6715, 41.9437], [-87.67234, 41.94369], [-87.67263, 41.94369], [-87.67289, 41.9437], [-87.67311, 41.94373], [-87.67334, 41.94376], [-87.67348, 41.9438], [-87.67367, 41.94386], [-87.67386, 41.94393], [-87.67405, 41.94404], [-87.67419, 41.94414], [-87.6743, 41.94424], [-87.67442, 41.94438], [-87.6745, 41.94455], [-87.67457, 41.94474], [-87.67463, 41.94494], [-87.67466, 41.94513], [-87.67468, 41.94596], [-87.67474, 41.94703], [-87.67476, 41.94859], [-87.67479, 41.94959], [-87.67484, 41.95101], [-87.67485, 41.95202], [-87.67487, 41.95302], [-87.67491, 41.95392], [-87.67496, 41.95452], [-87.67497, 41.95513], [-87.67501, 41.95666], [-87.67505, 41.95798], [-87.67513, 41.96077], [-87.67517, 41.96175], [-87.67519, 41.96371], [-87.6752, 41.96434], [-87.67521, 41.96457], [-87.67522, 41.96477], [-87.67523, 41.96491], [-87.67524, 41.96503], [-87.6753, 41.96519], [-87.67539, 41.96536], [-87.67544, 41.96547], [-87.67557, 41.96565], [-87.6757, 41.96579], [-87.67589, 41.96596], [-87.67613, 41.96612], [-87.67638, 41.96623], [-87.67665, 41.96632], [-87.67695, 41.96638], [-87.67722, 41.9664], [-87.67741, 41.96641], [-87.67766, 41.96642], [-87.67863, 41.96641], [-87.68034, 41.96638], [-87.68159, 41.96636], [-87.68271, 41.96635], [-87.68399, 41.96632], [-87.68545, 41.96631], [-87.68718, 41.96628], [-87.6885, 41.96625], [-87.68946, 41.96625], [-87.69026, 41.96624], [-87.69145, 41.96623], [-87.69411, 41.96621], [-87.69502, 41.96621], [-87.69675, 41.9662], [-87.69789, 41.96618], [-87.69873, 41.96616], [-87.69954, 41.96615], [-87.70075, 41.96615], [-87.70166, 41.96615], [-87.70267, 41.96614], [-87.70399, 41.96613], [-87.70645, 41.96612], [-87.70763, 41.96611], [-87.70884, 41.96609], [-87.71027, 41.96607], [-87.71108, 41.96607], [-87.71173, 41.96606], [-87.71219, 41.96605], [-87.7124, 41.96605], [-87.71255, 41.96605], [-87.71268, 41.96605], [-87.7128, 41.96607], [-87.71292, 41.96611], [-87.71298, 41.96615], [-87.71303, 41.96621], [-87.71309, 41.9663], [-87.7131, 41.96635], [-87.71311, 41.96643], [-87.71312, 41.96667], [-87.71314, 41.96793]]}'
View it on GitLab: https://salsa.debian.org/debian-gis-team/python-shapely/-/commit/418789883d799f8e56fa45e345569495c51bc80d
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/python-shapely/-/commit/418789883d799f8e56fa45e345569495c51bc80d
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20220817/71e5aa3b/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list