shapely 2.0.2__tar.gz → 2.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. {shapely-2.0.2 → shapely-2.0.4}/CHANGES.txt +20 -0
  2. {shapely-2.0.2 → shapely-2.0.4}/CITATION.cff +2 -2
  3. {shapely-2.0.2 → shapely-2.0.4}/PKG-INFO +2 -2
  4. {shapely-2.0.2 → shapely-2.0.4}/pyproject.toml +7 -2
  5. {shapely-2.0.2 → shapely-2.0.4}/shapely/_ragged_array.py +3 -2
  6. {shapely-2.0.2 → shapely-2.0.4}/shapely/_version.py +3 -3
  7. {shapely-2.0.2 → shapely-2.0.4}/shapely/algorithms/_oriented_envelope.py +5 -2
  8. {shapely-2.0.2 → shapely-2.0.4}/shapely/constructive.py +2 -2
  9. {shapely-2.0.2 → shapely-2.0.4}/shapely/decorators.py +1 -1
  10. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/polygon.py +1 -1
  11. {shapely-2.0.2 → shapely-2.0.4}/shapely/testing.py +2 -2
  12. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/common.py +31 -0
  13. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_format.py +12 -7
  14. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_constructive.py +12 -0
  15. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_io.py +9 -0
  16. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_misc.py +15 -5
  17. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_ragged_array.py +33 -6
  18. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_set_operations.py +7 -0
  19. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_strtree.py +5 -5
  20. {shapely-2.0.2 → shapely-2.0.4}/shapely.egg-info/PKG-INFO +2 -2
  21. {shapely-2.0.2 → shapely-2.0.4}/shapely.egg-info/requires.txt +1 -1
  22. {shapely-2.0.2 → shapely-2.0.4}/src/ufuncs.c +2 -1
  23. {shapely-2.0.2 → shapely-2.0.4}/CREDITS.txt +0 -0
  24. {shapely-2.0.2 → shapely-2.0.4}/LICENSE.txt +0 -0
  25. {shapely-2.0.2 → shapely-2.0.4}/README.rst +0 -0
  26. {shapely-2.0.2 → shapely-2.0.4}/docs/constructive.rst +0 -0
  27. {shapely-2.0.2 → shapely-2.0.4}/docs/coordinates.rst +0 -0
  28. {shapely-2.0.2 → shapely-2.0.4}/docs/creation.rst +0 -0
  29. {shapely-2.0.2 → shapely-2.0.4}/docs/design.rst +0 -0
  30. {shapely-2.0.2 → shapely-2.0.4}/docs/geometry.rst +0 -0
  31. {shapely-2.0.2 → shapely-2.0.4}/docs/index.rst +0 -0
  32. {shapely-2.0.2 → shapely-2.0.4}/docs/installation.rst +0 -0
  33. {shapely-2.0.2 → shapely-2.0.4}/docs/io.rst +0 -0
  34. {shapely-2.0.2 → shapely-2.0.4}/docs/linear.rst +0 -0
  35. {shapely-2.0.2 → shapely-2.0.4}/docs/manual.rst +0 -0
  36. {shapely-2.0.2 → shapely-2.0.4}/docs/measurement.rst +0 -0
  37. {shapely-2.0.2 → shapely-2.0.4}/docs/migration.rst +0 -0
  38. {shapely-2.0.2 → shapely-2.0.4}/docs/migration_pygeos.rst +0 -0
  39. {shapely-2.0.2 → shapely-2.0.4}/docs/predicates.rst +0 -0
  40. {shapely-2.0.2 → shapely-2.0.4}/docs/properties.rst +0 -0
  41. {shapely-2.0.2 → shapely-2.0.4}/docs/release.rst +0 -0
  42. {shapely-2.0.2 → shapely-2.0.4}/docs/set_operations.rst +0 -0
  43. {shapely-2.0.2 → shapely-2.0.4}/docs/strtree.rst +0 -0
  44. {shapely-2.0.2 → shapely-2.0.4}/docs/testing.rst +0 -0
  45. {shapely-2.0.2 → shapely-2.0.4}/setup.cfg +0 -0
  46. {shapely-2.0.2 → shapely-2.0.4}/setup.py +0 -0
  47. {shapely-2.0.2 → shapely-2.0.4}/shapely/__init__.py +0 -0
  48. {shapely-2.0.2 → shapely-2.0.4}/shapely/_enum.py +0 -0
  49. {shapely-2.0.2 → shapely-2.0.4}/shapely/_geometry.py +0 -0
  50. {shapely-2.0.2 → shapely-2.0.4}/shapely/_geometry_helpers.pyx +0 -0
  51. {shapely-2.0.2 → shapely-2.0.4}/shapely/_geos.pxd +0 -0
  52. {shapely-2.0.2 → shapely-2.0.4}/shapely/_geos.pyx +0 -0
  53. {shapely-2.0.2 → shapely-2.0.4}/shapely/_pygeos_api.pxd +0 -0
  54. {shapely-2.0.2 → shapely-2.0.4}/shapely/affinity.py +0 -0
  55. {shapely-2.0.2 → shapely-2.0.4}/shapely/algorithms/__init__.py +0 -0
  56. {shapely-2.0.2 → shapely-2.0.4}/shapely/algorithms/cga.py +0 -0
  57. {shapely-2.0.2 → shapely-2.0.4}/shapely/algorithms/polylabel.py +0 -0
  58. {shapely-2.0.2 → shapely-2.0.4}/shapely/coordinates.py +0 -0
  59. {shapely-2.0.2 → shapely-2.0.4}/shapely/coords.py +0 -0
  60. {shapely-2.0.2 → shapely-2.0.4}/shapely/creation.py +0 -0
  61. {shapely-2.0.2 → shapely-2.0.4}/shapely/errors.py +0 -0
  62. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/__init__.py +0 -0
  63. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/base.py +0 -0
  64. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/collection.py +0 -0
  65. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/conftest.py +0 -0
  66. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/geo.py +0 -0
  67. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/linestring.py +0 -0
  68. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/multilinestring.py +0 -0
  69. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/multipoint.py +0 -0
  70. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/multipolygon.py +0 -0
  71. {shapely-2.0.2 → shapely-2.0.4}/shapely/geometry/point.py +0 -0
  72. {shapely-2.0.2 → shapely-2.0.4}/shapely/geos.py +0 -0
  73. {shapely-2.0.2 → shapely-2.0.4}/shapely/io.py +0 -0
  74. {shapely-2.0.2 → shapely-2.0.4}/shapely/linear.py +0 -0
  75. {shapely-2.0.2 → shapely-2.0.4}/shapely/measurement.py +0 -0
  76. {shapely-2.0.2 → shapely-2.0.4}/shapely/ops.py +0 -0
  77. {shapely-2.0.2 → shapely-2.0.4}/shapely/plotting.py +0 -0
  78. {shapely-2.0.2 → shapely-2.0.4}/shapely/predicates.py +0 -0
  79. {shapely-2.0.2 → shapely-2.0.4}/shapely/prepared.py +0 -0
  80. {shapely-2.0.2 → shapely-2.0.4}/shapely/set_operations.py +0 -0
  81. {shapely-2.0.2 → shapely-2.0.4}/shapely/speedups.py +0 -0
  82. {shapely-2.0.2 → shapely-2.0.4}/shapely/strtree.py +0 -0
  83. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/__init__.py +0 -0
  84. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/__init__.py +0 -0
  85. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_collection.py +0 -0
  86. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_coords.py +0 -0
  87. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_decimal.py +0 -0
  88. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_emptiness.py +0 -0
  89. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_equality.py +0 -0
  90. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_geometry_base.py +0 -0
  91. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_hash.py +0 -0
  92. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_linestring.py +0 -0
  93. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_multi.py +0 -0
  94. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_multilinestring.py +0 -0
  95. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_multipoint.py +0 -0
  96. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_multipolygon.py +0 -0
  97. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_point.py +0 -0
  98. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/geometry/test_polygon.py +0 -0
  99. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/__init__.py +0 -0
  100. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/conftest.py +0 -0
  101. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_affinity.py +0 -0
  102. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_box.py +0 -0
  103. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_buffer.py +0 -0
  104. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_cga.py +0 -0
  105. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_clip_by_rect.py +0 -0
  106. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_create_inconsistent_dimensionality.py +0 -0
  107. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_delaunay.py +0 -0
  108. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_empty_polygons.py +0 -0
  109. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_equality.py +0 -0
  110. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_geointerface.py +0 -0
  111. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_invalid_geometries.py +0 -0
  112. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_linear_referencing.py +0 -0
  113. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_linemerge.py +0 -0
  114. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_locale.py +0 -0
  115. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_make_valid.py +0 -0
  116. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_mapping.py +0 -0
  117. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_minimum_clearance.py +0 -0
  118. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_ndarrays.py +0 -0
  119. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_nearest.py +0 -0
  120. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_operations.py +0 -0
  121. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_operators.py +0 -0
  122. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_orient.py +0 -0
  123. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_parallel_offset.py +0 -0
  124. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_persist.py +0 -0
  125. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_pickle.py +0 -0
  126. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_polygonize.py +0 -0
  127. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_polylabel.py +0 -0
  128. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_predicates.py +0 -0
  129. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_prepared.py +0 -0
  130. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_products_z.py +0 -0
  131. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_shape.py +0 -0
  132. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_shared_paths.py +0 -0
  133. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_singularity.py +0 -0
  134. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_snap.py +0 -0
  135. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_split.py +0 -0
  136. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_substring.py +0 -0
  137. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_svg.py +0 -0
  138. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_transform.py +0 -0
  139. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_union.py +0 -0
  140. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_validation.py +0 -0
  141. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_vectorized.py +0 -0
  142. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_voronoi_diagram.py +0 -0
  143. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_wkb.py +0 -0
  144. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/test_wkt.py +0 -0
  145. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/legacy/threading_test.py +0 -0
  146. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_coordinates.py +0 -0
  147. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_creation.py +0 -0
  148. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_creation_indices.py +0 -0
  149. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_geometry.py +0 -0
  150. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_linear.py +0 -0
  151. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_measurement.py +0 -0
  152. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_plotting.py +0 -0
  153. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_predicates.py +0 -0
  154. {shapely-2.0.2 → shapely-2.0.4}/shapely/tests/test_testing.py +0 -0
  155. {shapely-2.0.2 → shapely-2.0.4}/shapely/validation.py +0 -0
  156. {shapely-2.0.2 → shapely-2.0.4}/shapely/vectorized/__init__.py +0 -0
  157. {shapely-2.0.2 → shapely-2.0.4}/shapely/wkb.py +0 -0
  158. {shapely-2.0.2 → shapely-2.0.4}/shapely/wkt.py +0 -0
  159. {shapely-2.0.2 → shapely-2.0.4}/shapely.egg-info/SOURCES.txt +0 -0
  160. {shapely-2.0.2 → shapely-2.0.4}/shapely.egg-info/dependency_links.txt +0 -0
  161. {shapely-2.0.2 → shapely-2.0.4}/shapely.egg-info/top_level.txt +0 -0
  162. {shapely-2.0.2 → shapely-2.0.4}/src/c_api.c +0 -0
  163. {shapely-2.0.2 → shapely-2.0.4}/src/c_api.h +0 -0
  164. {shapely-2.0.2 → shapely-2.0.4}/src/coords.c +0 -0
  165. {shapely-2.0.2 → shapely-2.0.4}/src/coords.h +0 -0
  166. {shapely-2.0.2 → shapely-2.0.4}/src/fast_loop_macros.h +0 -0
  167. {shapely-2.0.2 → shapely-2.0.4}/src/geos.c +0 -0
  168. {shapely-2.0.2 → shapely-2.0.4}/src/geos.h +0 -0
  169. {shapely-2.0.2 → shapely-2.0.4}/src/kvec.h +0 -0
  170. {shapely-2.0.2 → shapely-2.0.4}/src/lib.c +0 -0
  171. {shapely-2.0.2 → shapely-2.0.4}/src/pygeom.c +0 -0
  172. {shapely-2.0.2 → shapely-2.0.4}/src/pygeom.h +0 -0
  173. {shapely-2.0.2 → shapely-2.0.4}/src/strtree.c +0 -0
  174. {shapely-2.0.2 → shapely-2.0.4}/src/strtree.h +0 -0
  175. {shapely-2.0.2 → shapely-2.0.4}/src/ufuncs.h +0 -0
  176. {shapely-2.0.2 → shapely-2.0.4}/src/vector.c +0 -0
  177. {shapely-2.0.2 → shapely-2.0.4}/src/vector.h +0 -0
  178. {shapely-2.0.2 → shapely-2.0.4}/versioneer.py +0 -0
@@ -1,6 +1,26 @@
1
1
  Changes
2
2
  =======
3
3
 
4
+ 2.0.4 (2024-04-16)
5
+ ------------------
6
+
7
+ Wheels for Python versions >= 3.9 will be compatible with the upcoming NumPy 2.0
8
+ release (as well as with supported NumPy 1.x versions).
9
+
10
+ Bug fixes:
11
+
12
+ - Fix bug in ``to_wkt`` with multiple empty Z geometries (#2012).
13
+ - Fix bug in ``to_ragged_array`` for an array of Points with missing values (#2034).
14
+
15
+ 2.0.3 (2024-02-16)
16
+ ------------------
17
+
18
+ - Fix regression in the ``oriented_envelope`` ufunc to accept array-like input
19
+ in case of GEOS<3.12 (#1929).
20
+ - The binary wheels are not yet compatible with a future NumPy 2.0 release,
21
+ therefore a ``numpy<2`` upper pin was added to the requirements (#1972).
22
+ - Upgraded the GEOS version in the binary wheel distributions to 3.11.3.
23
+
4
24
  2.0.2 (2023-10-12)
5
25
  ------------------
6
26
 
@@ -2,8 +2,8 @@ cff-version: 1.2.0
2
2
  message: "Please cite this software using these metadata."
3
3
  type: software
4
4
  title: Shapely
5
- version: "2.0.2"
6
- date-released: "2023-10-12"
5
+ version: "2.0.4"
6
+ date-released: "2024-04-16"
7
7
  doi: 10.5281/zenodo.5597138
8
8
  abstract: "Manipulation and analysis of geometric objects in the Cartesian plane."
9
9
  repository-artifact: https://pypi.org/project/Shapely
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shapely
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: Manipulation and analysis of geometric objects
5
5
  Author: Sean Gillies
6
6
  Maintainer: Shapely contributors
@@ -26,7 +26,7 @@ Classifier: Topic :: Scientific/Engineering :: GIS
26
26
  Requires-Python: >=3.7
27
27
  Description-Content-Type: text/x-rst
28
28
  License-File: LICENSE.txt
29
- Requires-Dist: numpy>=1.14
29
+ Requires-Dist: numpy<3,>=1.14
30
30
  Provides-Extra: test
31
31
  Requires-Dist: pytest; extra == "test"
32
32
  Requires-Dist: pytest-cov; extra == "test"
@@ -1,7 +1,12 @@
1
1
  [build-system]
2
2
  requires = [
3
3
  "Cython",
4
- "oldest-supported-numpy",
4
+ # Starting with NumPy 1.25, NumPy is (by default) as far back compatible
5
+ # as oldest-support-numpy was (customizable with a NPY_TARGET_VERSION
6
+ # define). For older Python versions (where NumPy 1.25 is not yet avaiable)
7
+ # continue using oldest-support-numpy.
8
+ "oldest-supported-numpy; python_version<'3.9'",
9
+ "numpy>=1.25; python_version>='3.9'",
5
10
  "setuptools>=61.0.0",
6
11
  ]
7
12
  build-backend = "setuptools.build_meta"
@@ -38,7 +43,7 @@ classifiers = [
38
43
  ]
39
44
  requires-python = ">=3.7"
40
45
  dependencies = [
41
- "numpy>=1.14",
46
+ "numpy>=1.14,<3",
42
47
  ]
43
48
 
44
49
  [project.optional-dependencies]
@@ -37,7 +37,7 @@ from shapely._geometry import (
37
37
  get_type_id,
38
38
  )
39
39
  from shapely.coordinates import get_coordinates
40
- from shapely.predicates import is_empty
40
+ from shapely.predicates import is_empty, is_missing
41
41
 
42
42
  __all__ = ["to_ragged_array", "from_ragged_array"]
43
43
 
@@ -50,7 +50,8 @@ def _get_arrays_point(arr, include_z):
50
50
  coords = get_coordinates(arr, include_z=include_z)
51
51
 
52
52
  # empty points are represented by NaNs
53
- empties = is_empty(arr)
53
+ # + missing geometries should also be present with some value
54
+ empties = is_empty(arr) | is_missing(arr)
54
55
  if empties.any():
55
56
  indices = np.nonzero(empties)[0]
56
57
  indices = indices - np.arange(len(indices))
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2023-10-12T21:49:31+0200",
11
+ "date": "2024-04-16T23:57:44+0200",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "8d45d434037267ba9b1f1de409d1b5396d6c9219",
15
- "version": "2.0.2"
14
+ "full-revisionid": "3853e1170173125b7e86cbb5cc8dab1c274c3999",
15
+ "version": "2.0.4"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -17,8 +17,6 @@ def _oriented_envelope_min_area(geometry, **kwargs):
17
17
  """
18
18
  if geometry is None:
19
19
  return None
20
- if not hasattr(geometry, "geom_type"):
21
- return np.array([_oriented_envelope_min_area(g) for g in geometry])
22
20
  if geometry.is_empty:
23
21
  return shapely.from_wkt("POLYGON EMPTY")
24
22
 
@@ -53,3 +51,8 @@ def _oriented_envelope_min_area(geometry, **kwargs):
53
51
  # check for the minimum area rectangle and return it
54
52
  transf_rect, inv_matrix = min(_transformed_rects(), key=lambda r: r[0].area)
55
53
  return affine_transform(transf_rect, inv_matrix)
54
+
55
+
56
+ _oriented_envelope_min_area_vectorized = np.frompyfunc(
57
+ _oriented_envelope_min_area, 1, 1
58
+ )
@@ -2,7 +2,7 @@ import numpy as np
2
2
 
3
3
  from shapely import lib
4
4
  from shapely._enum import ParamEnum
5
- from shapely.algorithms._oriented_envelope import _oriented_envelope_min_area
5
+ from shapely.algorithms._oriented_envelope import _oriented_envelope_min_area_vectorized
6
6
  from shapely.decorators import multithreading_enabled, requires_geos
7
7
 
8
8
  __all__ = [
@@ -1028,7 +1028,7 @@ def oriented_envelope(geometry, **kwargs):
1028
1028
  <POLYGON EMPTY>
1029
1029
  """
1030
1030
  if lib.geos_version < (3, 12, 0):
1031
- f = _oriented_envelope_min_area
1031
+ f = _oriented_envelope_min_area_vectorized
1032
1032
  else:
1033
1033
  f = _oriented_envelope_geos
1034
1034
  return f(geometry, **kwargs)
@@ -39,7 +39,7 @@ class requires_geos:
39
39
  # Insert the message at the first double newline
40
40
  position = doc.find("\n\n") + 2
41
41
  # Figure out the indentation level
42
- indent = 2
42
+ indent = 0
43
43
  while True:
44
44
  if doc[position + indent] == " ":
45
45
  indent += 1
@@ -10,7 +10,7 @@ from shapely.geometry.base import BaseGeometry
10
10
  from shapely.geometry.linestring import LineString
11
11
  from shapely.geometry.point import Point
12
12
 
13
- __all__ = ["Polygon", "LinearRing"]
13
+ __all__ = ["orient", "Polygon", "LinearRing"]
14
14
 
15
15
 
16
16
  def _unpickle_linearring(wkb):
@@ -106,8 +106,8 @@ def assert_geometries_equal(
106
106
  if normalize:
107
107
  x = shapely.normalize(x)
108
108
  y = shapely.normalize(y)
109
- x = np.array(x, copy=False)
110
- y = np.array(y, copy=False)
109
+ x = np.asarray(x)
110
+ y = np.asarray(y)
111
111
 
112
112
  is_scalar = x.ndim == 0 or y.ndim == 0
113
113
 
@@ -92,3 +92,34 @@ def ignore_invalid(condition=True):
92
92
 
93
93
  with ignore_invalid():
94
94
  line_string_nan = shapely.LineString([(np.nan, np.nan), (np.nan, np.nan)])
95
+
96
+
97
+ class ArrayLike:
98
+ """
99
+ Simple numpy Array like class that implements the
100
+ ufunc protocol.
101
+ """
102
+
103
+ def __init__(self, array):
104
+ self._array = np.asarray(array)
105
+
106
+ def __len__(self):
107
+ return len(self._array)
108
+
109
+ def __getitem(self, key):
110
+ return self._array[key]
111
+
112
+ def __iter__(self):
113
+ return self._array.__iter__()
114
+
115
+ def __array__(self):
116
+ return np.asarray(self._array)
117
+
118
+ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
119
+ if method == "__call__":
120
+ inputs = [
121
+ arg._array if isinstance(arg, self.__class__) else arg for arg in inputs
122
+ ]
123
+ return self.__class__(ufunc(*inputs, **kwargs))
124
+ else:
125
+ return NotImplemented
@@ -84,23 +84,28 @@ def test_format_polygon():
84
84
  assert format(poly, "X") == poly.wkb_hex
85
85
 
86
86
  # Use f-strings with extra characters and rounding precision
87
- assert f"<{poly:.2f}>" == (
88
- "<POLYGON ((10.00 0.00, 7.07 -7.07, 0.00 -10.00, -7.07 -7.07, "
89
- "-10.00 -0.00, -7.07 7.07, -0.00 10.00, 7.07 7.07, 10.00 0.00))>"
90
- )
87
+ if geos_version < (3, 13, 0):
88
+ assert f"<{poly:.2f}>" == (
89
+ "<POLYGON ((10.00 0.00, 7.07 -7.07, 0.00 -10.00, -7.07 -7.07, "
90
+ "-10.00 -0.00, -7.07 7.07, -0.00 10.00, 7.07 7.07, 10.00 0.00))>"
91
+ )
92
+ else:
93
+ assert f"<{poly:.2f}>" == (
94
+ "<POLYGON ((10.00 0.00, 7.07 -7.07, 0.00 -10.00, -7.07 -7.07, "
95
+ "-10.00 0.00, -7.07 7.07, 0.00 10.00, 7.07 7.07, 10.00 0.00))>"
96
+ )
91
97
 
92
98
  # 'g' format varies depending on GEOS version
93
99
  if geos_version < (3, 10, 0):
94
- expected_2G = (
100
+ assert f"{poly:.2G}" == (
95
101
  "POLYGON ((10 0, 7.1 -7.1, 1.6E-14 -10, -7.1 -7.1, "
96
102
  "-10 -3.2E-14, -7.1 7.1, -4.6E-14 10, 7.1 7.1, 10 0))"
97
103
  )
98
104
  else:
99
- expected_2G = (
105
+ assert f"{poly:.2G}" == (
100
106
  "POLYGON ((10 0, 7.07 -7.07, 0 -10, -7.07 -7.07, "
101
107
  "-10 0, -7.07 7.07, 0 10, 7.07 7.07, 10 0))"
102
108
  )
103
- assert f"{poly:.2G}" == expected_2G
104
109
 
105
110
  # check empty
106
111
  empty = Polygon()
@@ -17,6 +17,7 @@ from shapely import (
17
17
  from shapely.testing import assert_geometries_equal
18
18
  from shapely.tests.common import (
19
19
  all_types,
20
+ ArrayLike,
20
21
  empty,
21
22
  empty_line_string,
22
23
  empty_point,
@@ -981,6 +982,17 @@ def test_oriented_envelope_pre_geos_312(geometry, expected):
981
982
  assert_geometries_equal(actual, expected, normalize=True, tolerance=1e-3)
982
983
 
983
984
 
985
+ def test_oriented_evelope_array_like():
986
+ # https://github.com/shapely/shapely/issues/1929
987
+ # because we have a custom python implementation, need to ensure this has
988
+ # the same capabilities as numpy ufuncs to work with array-likes
989
+ geometries = [Point(1, 1).buffer(1), Point(2, 2).buffer(1)]
990
+ actual = shapely.oriented_envelope(ArrayLike(geometries))
991
+ assert isinstance(actual, ArrayLike)
992
+ expected = shapely.oriented_envelope(geometries)
993
+ assert_geometries_equal(np.asarray(actual), expected)
994
+
995
+
984
996
  @pytest.mark.skipif(shapely.geos_version < (3, 11, 0), reason="GEOS < 3.11")
985
997
  def test_concave_hull_kwargs():
986
998
  p = Point(10, 10)
@@ -287,6 +287,15 @@ def test_to_wkt_none():
287
287
  assert shapely.to_wkt(None) is None
288
288
 
289
289
 
290
+ def test_to_wkt_array_with_empty_z():
291
+ # See GH-2004
292
+ empty_wkt = ["POINT Z EMPTY", None, "POLYGON Z EMPTY"]
293
+ empty_geoms = shapely.from_wkt(empty_wkt)
294
+ if shapely.geos_version < (3, 9, 0):
295
+ empty_wkt = ["POINT EMPTY", None, "POLYGON EMPTY"]
296
+ assert list(shapely.to_wkt(empty_geoms)) == empty_wkt
297
+
298
+
290
299
  def test_to_wkt_exceptions():
291
300
  with pytest.raises(TypeError):
292
301
  shapely.to_wkt(1)
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import sys
3
+ from inspect import cleandoc
3
4
  from itertools import chain
4
5
  from string import ascii_letters, digits
5
6
  from unittest import mock
@@ -83,13 +84,22 @@ class SomeClass:
83
84
  """
84
85
 
85
86
 
86
- expected_docstring = """Docstring that will be mocked.
87
+ def expected_docstring(**kwds):
88
+ doc = """Docstring that will be mocked.
87
89
  {indent}A multiline.
88
90
 
89
91
  {indent}.. note:: 'func' requires at least GEOS {version}.
90
92
 
91
93
  {indent}Some description.
92
- {indent}"""
94
+ {indent}""".format(
95
+ **kwds
96
+ )
97
+ if sys.version_info[:2] >= (3, 13):
98
+ # There are subtle differences between inspect.cleandoc() and
99
+ # _PyCompile_CleanDoc(). Most significantly, the latter does not remove
100
+ # leading or trailing blank lines.
101
+ return cleandoc(doc) + "\n"
102
+ return doc
93
103
 
94
104
 
95
105
  @pytest.mark.parametrize("version", ["3.7.0", "3.7.1", "3.6.2"])
@@ -104,7 +114,7 @@ def test_requires_geos_not_ok(version, mocked_geos_version):
104
114
  with pytest.raises(shapely.errors.UnsupportedGEOSVersionError):
105
115
  wrapped()
106
116
 
107
- assert wrapped.__doc__ == expected_docstring.format(version=version, indent=" " * 4)
117
+ assert wrapped.__doc__ == expected_docstring(version=version, indent=" " * 4)
108
118
 
109
119
 
110
120
  @pytest.mark.parametrize("version", ["3.6.0", "3.8.0"])
@@ -112,7 +122,7 @@ def test_requires_geos_doc_build(version, mocked_geos_version, sphinx_doc_build)
112
122
  """The requires_geos decorator always adapts the docstring."""
113
123
  wrapped = requires_geos(version)(func)
114
124
 
115
- assert wrapped.__doc__ == expected_docstring.format(version=version, indent=" " * 4)
125
+ assert wrapped.__doc__ == expected_docstring(version=version, indent=" " * 4)
116
126
 
117
127
 
118
128
  @pytest.mark.parametrize("version", ["3.6.0", "3.8.0"])
@@ -120,7 +130,7 @@ def test_requires_geos_method(version, mocked_geos_version, sphinx_doc_build):
120
130
  """The requires_geos decorator adjusts methods docstrings correctly"""
121
131
  wrapped = requires_geos(version)(SomeClass.func)
122
132
 
123
- assert wrapped.__doc__ == expected_docstring.format(version=version, indent=" " * 8)
133
+ assert wrapped.__doc__ == expected_docstring(version=version, indent=" " * 8)
124
134
 
125
135
 
126
136
  @multithreading_enabled
@@ -110,18 +110,30 @@ def test_points():
110
110
  "POINT EMPTY",
111
111
  "POINT EMPTY",
112
112
  "POINT (4 4)",
113
+ None,
113
114
  "POINT EMPTY",
114
115
  ]
115
116
  )
116
117
  typ, result, offsets = shapely.to_ragged_array(arr)
117
118
  expected = np.array(
118
- [[0, 0], [1, 1], [np.nan, np.nan], [np.nan, np.nan], [4, 4], [np.nan, np.nan]]
119
+ [
120
+ [0, 0],
121
+ [1, 1],
122
+ [np.nan, np.nan],
123
+ [np.nan, np.nan],
124
+ [4, 4],
125
+ [np.nan, np.nan],
126
+ [np.nan, np.nan],
127
+ ]
119
128
  )
120
129
  assert typ == shapely.GeometryType.POINT
130
+ assert len(result) == len(arr)
121
131
  assert_allclose(result, expected)
122
132
  assert len(offsets) == 0
123
133
 
124
134
  geoms = shapely.from_ragged_array(typ, result)
135
+ # in a roundtrip, missing geometries come back as empty
136
+ arr[-2] = shapely.from_wkt("POINT EMPTY")
125
137
  assert_geometries_equal(geoms, arr)
126
138
 
127
139
 
@@ -133,6 +145,7 @@ def test_linestrings():
133
145
  "LINESTRING EMPTY",
134
146
  "LINESTRING EMPTY",
135
147
  "LINESTRING (10 10, 20 20, 10 40)",
148
+ None,
136
149
  "LINESTRING EMPTY",
137
150
  ]
138
151
  )
@@ -151,13 +164,15 @@ def test_linestrings():
151
164
  [10.0, 40.0],
152
165
  ]
153
166
  )
154
- expected_offsets = np.array([0, 3, 7, 7, 7, 10, 10])
167
+ expected_offsets = np.array([0, 3, 7, 7, 7, 10, 10, 10])
155
168
  assert typ == shapely.GeometryType.LINESTRING
156
169
  assert_allclose(coords, expected)
157
170
  assert len(offsets) == 1
158
171
  assert_allclose(offsets[0], expected_offsets)
159
172
 
160
173
  result = shapely.from_ragged_array(typ, coords, offsets)
174
+ # in a roundtrip, missing geometries come back as empty
175
+ arr[-2] = shapely.from_wkt("LINESTRING EMPTY")
161
176
  assert_geometries_equal(result, arr)
162
177
 
163
178
 
@@ -169,6 +184,7 @@ def test_polygons():
169
184
  "POLYGON EMPTY",
170
185
  "POLYGON EMPTY",
171
186
  "POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))",
187
+ None,
172
188
  "POLYGON EMPTY",
173
189
  ]
174
190
  )
@@ -197,7 +213,7 @@ def test_polygons():
197
213
  ]
198
214
  )
199
215
  expected_offsets1 = np.array([0, 5, 10, 14, 19])
200
- expected_offsets2 = np.array([0, 1, 3, 3, 3, 4, 4])
216
+ expected_offsets2 = np.array([0, 1, 3, 3, 3, 4, 4, 4])
201
217
 
202
218
  assert typ == shapely.GeometryType.POLYGON
203
219
  assert_allclose(coords, expected)
@@ -206,6 +222,8 @@ def test_polygons():
206
222
  assert_allclose(offsets[1], expected_offsets2)
207
223
 
208
224
  result = shapely.from_ragged_array(typ, coords, offsets)
225
+ # in a roundtrip, missing geometries come back as empty
226
+ arr[-2] = shapely.from_wkt("POLYGON EMPTY")
209
227
  assert_geometries_equal(result, arr)
210
228
 
211
229
 
@@ -217,6 +235,7 @@ def test_multipoints():
217
235
  "MULTIPOINT EMPTY",
218
236
  "MULTIPOINT EMPTY",
219
237
  "MULTIPOINT (30 10, 10 30, 40 40)",
238
+ None,
220
239
  "MULTIPOINT EMPTY",
221
240
  ]
222
241
  )
@@ -233,7 +252,7 @@ def test_multipoints():
233
252
  [40.0, 40.0],
234
253
  ]
235
254
  )
236
- expected_offsets = np.array([0, 4, 5, 5, 5, 8, 8])
255
+ expected_offsets = np.array([0, 4, 5, 5, 5, 8, 8, 8])
237
256
 
238
257
  assert typ == shapely.GeometryType.MULTIPOINT
239
258
  assert_allclose(coords, expected)
@@ -241,6 +260,8 @@ def test_multipoints():
241
260
  assert_allclose(offsets[0], expected_offsets)
242
261
 
243
262
  result = shapely.from_ragged_array(typ, coords, offsets)
263
+ # in a roundtrip, missing geometries come back as empty
264
+ arr[-2] = shapely.from_wkt("MULTIPOINT EMPTY")
244
265
  assert_geometries_equal(result, arr)
245
266
 
246
267
 
@@ -252,6 +273,7 @@ def test_multilinestrings():
252
273
  "MULTILINESTRING EMPTY",
253
274
  "MULTILINESTRING EMPTY",
254
275
  "MULTILINESTRING ((35 10, 45 45), (15 40, 10 20), (30 10, 10 30, 40 40))",
276
+ None,
255
277
  "MULTILINESTRING EMPTY",
256
278
  ]
257
279
  )
@@ -278,7 +300,7 @@ def test_multilinestrings():
278
300
  ]
279
301
  )
280
302
  expected_offsets1 = np.array([0, 3, 6, 10, 12, 14, 17])
281
- expected_offsets2 = np.array([0, 1, 3, 3, 3, 6, 6])
303
+ expected_offsets2 = np.array([0, 1, 3, 3, 3, 6, 6, 6])
282
304
 
283
305
  assert typ == shapely.GeometryType.MULTILINESTRING
284
306
  assert_allclose(coords, expected)
@@ -287,6 +309,8 @@ def test_multilinestrings():
287
309
  assert_allclose(offsets[1], expected_offsets2)
288
310
 
289
311
  result = shapely.from_ragged_array(typ, coords, offsets)
312
+ # in a roundtrip, missing geometries come back as empty
313
+ arr[-2] = shapely.from_wkt("MULTILINESTRING EMPTY")
290
314
  assert_geometries_equal(result, arr)
291
315
 
292
316
 
@@ -298,6 +322,7 @@ def test_multipolygons():
298
322
  "MULTIPOLYGON EMPTY",
299
323
  "MULTIPOLYGON EMPTY",
300
324
  "MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)))",
325
+ None,
301
326
  "MULTIPOLYGON EMPTY",
302
327
  ]
303
328
  )
@@ -335,7 +360,7 @@ def test_multipolygons():
335
360
  )
336
361
  expected_offsets1 = np.array([0, 5, 9, 13, 19, 23, 27])
337
362
  expected_offsets2 = np.array([0, 2, 3, 5, 6])
338
- expected_offsets3 = np.array([0, 1, 3, 3, 3, 4, 4])
363
+ expected_offsets3 = np.array([0, 1, 3, 3, 3, 4, 4, 4])
339
364
 
340
365
  assert typ == shapely.GeometryType.MULTIPOLYGON
341
366
  assert_allclose(coords, expected)
@@ -345,6 +370,8 @@ def test_multipolygons():
345
370
  assert_allclose(offsets[2], expected_offsets3)
346
371
 
347
372
  result = shapely.from_ragged_array(typ, coords, offsets)
373
+ # in a roundtrip, missing geometries come back as empty
374
+ arr[-2] = shapely.from_wkt("MULTIPOLYGON EMPTY")
348
375
  assert_geometries_equal(result, arr)
349
376
 
350
377
 
@@ -53,6 +53,13 @@ non_polygon_types = [
53
53
  @pytest.mark.parametrize("a", all_types)
54
54
  @pytest.mark.parametrize("func", SET_OPERATIONS)
55
55
  def test_set_operation_array(a, func):
56
+ if (
57
+ func is shapely.difference
58
+ and a.geom_type == "GeometryCollection"
59
+ and shapely.get_num_geometries(a) == 2
60
+ and shapely.geos_version == (3, 9, 5)
61
+ ):
62
+ pytest.xfail("GEOS 3.9.5 crashes with mixed collection")
56
63
  actual = func(a, point)
57
64
  assert isinstance(actual, Geometry)
58
65
 
@@ -10,7 +10,7 @@ import pytest
10
10
  from numpy.testing import assert_array_equal
11
11
 
12
12
  import shapely
13
- from shapely import box, geos_version, MultiPoint, Point, STRtree
13
+ from shapely import box, geos_version, LineString, MultiPoint, Point, STRtree
14
14
  from shapely.errors import UnsupportedGEOSVersionError
15
15
  from shapely.testing import assert_geometries_equal
16
16
  from shapely.tests.common import (
@@ -928,12 +928,12 @@ def test_query_crosses_polygons(poly_tree, geometry, expected):
928
928
  # box contains points but touches only those at edges
929
929
  (box(3, 3, 6, 6), [3, 6]),
930
930
  ([box(3, 3, 6, 6)], [[0, 0], [3, 6]]),
931
- # buffer completely contains point in tree
931
+ # polygon completely contains point in tree
932
932
  (shapely.buffer(Point(3, 3), 1), []),
933
933
  ([shapely.buffer(Point(3, 3), 1)], [[], []]),
934
- # buffer intersects 2 points but touches only one
935
- (shapely.buffer(Point(0, 1), 1), [1]),
936
- ([shapely.buffer(Point(0, 1), 1)], [[0], [1]]),
934
+ # linestring intersects 2 points but touches only one
935
+ (LineString([(-1, -1), (1, 1)]), [1]),
936
+ ([LineString([(-1, -1), (1, 1)])], [[0], [1]]),
937
937
  # multipoints intersect but not valid relation
938
938
  (MultiPoint([[5, 5], [7, 7]]), []),
939
939
  ([MultiPoint([[5, 5], [7, 7]])], [[], []]),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shapely
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: Manipulation and analysis of geometric objects
5
5
  Author: Sean Gillies
6
6
  Maintainer: Shapely contributors
@@ -26,7 +26,7 @@ Classifier: Topic :: Scientific/Engineering :: GIS
26
26
  Requires-Python: >=3.7
27
27
  Description-Content-Type: text/x-rst
28
28
  License-File: LICENSE.txt
29
- Requires-Dist: numpy>=1.14
29
+ Requires-Dist: numpy<3,>=1.14
30
30
  Provides-Extra: test
31
31
  Requires-Dist: pytest; extra == "test"
32
32
  Requires-Dist: pytest-cov; extra == "test"
@@ -1,4 +1,4 @@
1
- numpy>=1.14
1
+ numpy<3,>=1.14
2
2
 
3
3
  [docs]
4
4
  numpydoc==1.1.*
@@ -3351,8 +3351,9 @@ static void to_wkt_func(char** args, const npy_intp* dimensions, const npy_intp*
3351
3351
  goto finish;
3352
3352
  }
3353
3353
  if (wkt != NULL) {
3354
+ Py_XDECREF(*out);
3354
3355
  *out = PyUnicode_FromString(wkt);
3355
- goto finish;
3356
+ continue;
3356
3357
  }
3357
3358
 
3358
3359
  #else
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes