shapely 2.1.0__tar.gz → 2.1.1__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 (185) hide show
  1. {shapely-2.1.0 → shapely-2.1.1}/CHANGES.txt +11 -0
  2. {shapely-2.1.0 → shapely-2.1.1}/CITATION.cff +2 -2
  3. {shapely-2.1.0 → shapely-2.1.1}/PKG-INFO +1 -1
  4. {shapely-2.1.0 → shapely-2.1.1}/docs/geometry.rst +28 -14
  5. {shapely-2.1.0 → shapely-2.1.1}/docs/manual.rst +1 -28
  6. {shapely-2.1.0 → shapely-2.1.1}/docs/migration.rst +27 -26
  7. {shapely-2.1.0 → shapely-2.1.1}/shapely/_geometry_helpers.pyx +46 -11
  8. {shapely-2.1.0 → shapely-2.1.1}/shapely/_version.py +3 -3
  9. {shapely-2.1.0 → shapely-2.1.1}/shapely/decorators.py +84 -34
  10. {shapely-2.1.0 → shapely-2.1.1}/shapely/io.py +2 -1
  11. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_polylabel.py +4 -1
  12. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_constructive.py +6 -4
  13. shapely-2.1.1/shapely/tests/test_decorators.py +138 -0
  14. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_ragged_array.py +77 -0
  15. {shapely-2.1.0 → shapely-2.1.1}/shapely.egg-info/PKG-INFO +1 -1
  16. {shapely-2.1.0 → shapely-2.1.1}/shapely.egg-info/SOURCES.txt +1 -0
  17. {shapely-2.1.0 → shapely-2.1.1}/CREDITS.txt +0 -0
  18. {shapely-2.1.0 → shapely-2.1.1}/LICENSE.txt +0 -0
  19. {shapely-2.1.0 → shapely-2.1.1}/README.rst +0 -0
  20. {shapely-2.1.0 → shapely-2.1.1}/docs/constructive.rst +0 -0
  21. {shapely-2.1.0 → shapely-2.1.1}/docs/coordinates.rst +0 -0
  22. {shapely-2.1.0 → shapely-2.1.1}/docs/coverage.rst +0 -0
  23. {shapely-2.1.0 → shapely-2.1.1}/docs/creation.rst +0 -0
  24. {shapely-2.1.0 → shapely-2.1.1}/docs/design.rst +0 -0
  25. {shapely-2.1.0 → shapely-2.1.1}/docs/index.rst +0 -0
  26. {shapely-2.1.0 → shapely-2.1.1}/docs/installation.rst +0 -0
  27. {shapely-2.1.0 → shapely-2.1.1}/docs/io.rst +0 -0
  28. {shapely-2.1.0 → shapely-2.1.1}/docs/linear.rst +0 -0
  29. {shapely-2.1.0 → shapely-2.1.1}/docs/measurement.rst +0 -0
  30. {shapely-2.1.0 → shapely-2.1.1}/docs/migration_pygeos.rst +0 -0
  31. {shapely-2.1.0 → shapely-2.1.1}/docs/plotting.rst +0 -0
  32. {shapely-2.1.0 → shapely-2.1.1}/docs/predicates.rst +0 -0
  33. {shapely-2.1.0 → shapely-2.1.1}/docs/properties.rst +0 -0
  34. {shapely-2.1.0 → shapely-2.1.1}/docs/release.rst +0 -0
  35. {shapely-2.1.0 → shapely-2.1.1}/docs/set_operations.rst +0 -0
  36. {shapely-2.1.0 → shapely-2.1.1}/docs/strtree.rst +0 -0
  37. {shapely-2.1.0 → shapely-2.1.1}/docs/testing.rst +0 -0
  38. {shapely-2.1.0 → shapely-2.1.1}/pyproject.toml +0 -0
  39. {shapely-2.1.0 → shapely-2.1.1}/setup.cfg +0 -0
  40. {shapely-2.1.0 → shapely-2.1.1}/setup.py +0 -0
  41. {shapely-2.1.0 → shapely-2.1.1}/shapely/__init__.py +0 -0
  42. {shapely-2.1.0 → shapely-2.1.1}/shapely/_coverage.py +0 -0
  43. {shapely-2.1.0 → shapely-2.1.1}/shapely/_enum.py +0 -0
  44. {shapely-2.1.0 → shapely-2.1.1}/shapely/_geometry.py +0 -0
  45. {shapely-2.1.0 → shapely-2.1.1}/shapely/_geos.pxd +0 -0
  46. {shapely-2.1.0 → shapely-2.1.1}/shapely/_geos.pyx +0 -0
  47. {shapely-2.1.0 → shapely-2.1.1}/shapely/_pygeos_api.pxd +0 -0
  48. {shapely-2.1.0 → shapely-2.1.1}/shapely/_ragged_array.py +0 -0
  49. {shapely-2.1.0 → shapely-2.1.1}/shapely/affinity.py +0 -0
  50. {shapely-2.1.0 → shapely-2.1.1}/shapely/algorithms/__init__.py +0 -0
  51. {shapely-2.1.0 → shapely-2.1.1}/shapely/algorithms/_oriented_envelope.py +0 -0
  52. {shapely-2.1.0 → shapely-2.1.1}/shapely/algorithms/cga.py +0 -0
  53. {shapely-2.1.0 → shapely-2.1.1}/shapely/algorithms/polylabel.py +0 -0
  54. {shapely-2.1.0 → shapely-2.1.1}/shapely/conftest.py +0 -0
  55. {shapely-2.1.0 → shapely-2.1.1}/shapely/constructive.py +0 -0
  56. {shapely-2.1.0 → shapely-2.1.1}/shapely/coordinates.py +0 -0
  57. {shapely-2.1.0 → shapely-2.1.1}/shapely/coords.py +0 -0
  58. {shapely-2.1.0 → shapely-2.1.1}/shapely/creation.py +0 -0
  59. {shapely-2.1.0 → shapely-2.1.1}/shapely/errors.py +0 -0
  60. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/__init__.py +0 -0
  61. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/base.py +0 -0
  62. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/collection.py +0 -0
  63. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/geo.py +0 -0
  64. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/linestring.py +0 -0
  65. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/multilinestring.py +0 -0
  66. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/multipoint.py +0 -0
  67. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/multipolygon.py +0 -0
  68. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/point.py +0 -0
  69. {shapely-2.1.0 → shapely-2.1.1}/shapely/geometry/polygon.py +0 -0
  70. {shapely-2.1.0 → shapely-2.1.1}/shapely/geos.py +0 -0
  71. {shapely-2.1.0 → shapely-2.1.1}/shapely/linear.py +0 -0
  72. {shapely-2.1.0 → shapely-2.1.1}/shapely/measurement.py +0 -0
  73. {shapely-2.1.0 → shapely-2.1.1}/shapely/ops.py +0 -0
  74. {shapely-2.1.0 → shapely-2.1.1}/shapely/plotting.py +0 -0
  75. {shapely-2.1.0 → shapely-2.1.1}/shapely/predicates.py +0 -0
  76. {shapely-2.1.0 → shapely-2.1.1}/shapely/prepared.py +0 -0
  77. {shapely-2.1.0 → shapely-2.1.1}/shapely/set_operations.py +0 -0
  78. {shapely-2.1.0 → shapely-2.1.1}/shapely/speedups.py +0 -0
  79. {shapely-2.1.0 → shapely-2.1.1}/shapely/strtree.py +0 -0
  80. {shapely-2.1.0 → shapely-2.1.1}/shapely/testing.py +0 -0
  81. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/__init__.py +0 -0
  82. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/common.py +0 -0
  83. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/__init__.py +0 -0
  84. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_collection.py +0 -0
  85. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_coords.py +0 -0
  86. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_decimal.py +0 -0
  87. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_emptiness.py +0 -0
  88. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_equality.py +0 -0
  89. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_format.py +0 -0
  90. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_geometry_base.py +0 -0
  91. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_hash.py +0 -0
  92. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_linestring.py +0 -0
  93. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_multi.py +0 -0
  94. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_multilinestring.py +0 -0
  95. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_multipoint.py +0 -0
  96. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_multipolygon.py +0 -0
  97. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_point.py +0 -0
  98. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/geometry/test_polygon.py +0 -0
  99. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/__init__.py +0 -0
  100. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/conftest.py +0 -0
  101. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_affinity.py +0 -0
  102. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_box.py +0 -0
  103. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_buffer.py +0 -0
  104. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_cga.py +0 -0
  105. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_clip_by_rect.py +0 -0
  106. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_create_inconsistent_dimensionality.py +0 -0
  107. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_delaunay.py +0 -0
  108. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_empty_polygons.py +0 -0
  109. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_equality.py +0 -0
  110. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_geointerface.py +0 -0
  111. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_invalid_geometries.py +0 -0
  112. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_linear_referencing.py +0 -0
  113. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_linemerge.py +0 -0
  114. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_locale.py +0 -0
  115. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_make_valid.py +0 -0
  116. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_mapping.py +0 -0
  117. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_minimum_clearance.py +0 -0
  118. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_ndarrays.py +0 -0
  119. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_nearest.py +0 -0
  120. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_operations.py +0 -0
  121. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_operators.py +0 -0
  122. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_orient.py +0 -0
  123. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_parallel_offset.py +0 -0
  124. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_persist.py +0 -0
  125. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_pickle.py +0 -0
  126. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_polygonize.py +0 -0
  127. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_predicates.py +0 -0
  128. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_prepared.py +0 -0
  129. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_products_z.py +0 -0
  130. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_shape.py +0 -0
  131. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_shared_paths.py +0 -0
  132. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_singularity.py +0 -0
  133. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_snap.py +0 -0
  134. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_split.py +0 -0
  135. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_substring.py +0 -0
  136. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_svg.py +0 -0
  137. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_transform.py +0 -0
  138. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_union.py +0 -0
  139. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_validation.py +0 -0
  140. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_vectorized.py +0 -0
  141. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_voronoi_diagram.py +0 -0
  142. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_wkb.py +0 -0
  143. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/test_wkt.py +0 -0
  144. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/legacy/threading_test.py +0 -0
  145. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_coordinates.py +0 -0
  146. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_coverage.py +0 -0
  147. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_creation.py +0 -0
  148. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_creation_indices.py +0 -0
  149. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_geometry.py +0 -0
  150. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_io.py +0 -0
  151. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_linear.py +0 -0
  152. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_measurement.py +0 -0
  153. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_misc.py +0 -0
  154. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_plotting.py +0 -0
  155. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_predicates.py +0 -0
  156. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_set_operations.py +0 -0
  157. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_strtree.py +0 -0
  158. {shapely-2.1.0 → shapely-2.1.1}/shapely/tests/test_testing.py +0 -0
  159. {shapely-2.1.0 → shapely-2.1.1}/shapely/validation.py +0 -0
  160. {shapely-2.1.0 → shapely-2.1.1}/shapely/vectorized/__init__.py +0 -0
  161. {shapely-2.1.0 → shapely-2.1.1}/shapely/wkb.py +0 -0
  162. {shapely-2.1.0 → shapely-2.1.1}/shapely/wkt.py +0 -0
  163. {shapely-2.1.0 → shapely-2.1.1}/shapely.egg-info/dependency_links.txt +0 -0
  164. {shapely-2.1.0 → shapely-2.1.1}/shapely.egg-info/requires.txt +0 -0
  165. {shapely-2.1.0 → shapely-2.1.1}/shapely.egg-info/top_level.txt +0 -0
  166. {shapely-2.1.0 → shapely-2.1.1}/src/c_api.c +0 -0
  167. {shapely-2.1.0 → shapely-2.1.1}/src/c_api.h +0 -0
  168. {shapely-2.1.0 → shapely-2.1.1}/src/coords.c +0 -0
  169. {shapely-2.1.0 → shapely-2.1.1}/src/coords.h +0 -0
  170. {shapely-2.1.0 → shapely-2.1.1}/src/fast_loop_macros.h +0 -0
  171. {shapely-2.1.0 → shapely-2.1.1}/src/geos.c +0 -0
  172. {shapely-2.1.0 → shapely-2.1.1}/src/geos.h +0 -0
  173. {shapely-2.1.0 → shapely-2.1.1}/src/kvec.h +0 -0
  174. {shapely-2.1.0 → shapely-2.1.1}/src/lib.c +0 -0
  175. {shapely-2.1.0 → shapely-2.1.1}/src/pygeom.c +0 -0
  176. {shapely-2.1.0 → shapely-2.1.1}/src/pygeom.h +0 -0
  177. {shapely-2.1.0 → shapely-2.1.1}/src/pygeos.c +0 -0
  178. {shapely-2.1.0 → shapely-2.1.1}/src/pygeos.h +0 -0
  179. {shapely-2.1.0 → shapely-2.1.1}/src/strtree.c +0 -0
  180. {shapely-2.1.0 → shapely-2.1.1}/src/strtree.h +0 -0
  181. {shapely-2.1.0 → shapely-2.1.1}/src/ufuncs.c +0 -0
  182. {shapely-2.1.0 → shapely-2.1.1}/src/ufuncs.h +0 -0
  183. {shapely-2.1.0 → shapely-2.1.1}/src/vector.c +0 -0
  184. {shapely-2.1.0 → shapely-2.1.1}/src/vector.h +0 -0
  185. {shapely-2.1.0 → shapely-2.1.1}/versioneer.py +0 -0
@@ -1,6 +1,17 @@
1
1
  Changes
2
2
  =======
3
3
 
4
+ 2.1.1 (2025-05-19)
5
+ ------------------
6
+
7
+ Bug fixes:
8
+
9
+ - Fix performance degradation calling shapely functions (caused by deprecation
10
+ of certain positional arguments) (#2283).
11
+ - Fix crash caused by `from_ragged_array()` (#2291).
12
+ - Fix compilation error building with recent LLVM toolchain (#2293).
13
+
14
+
4
15
  2.1.0 (2025-04-03)
5
16
  ------------------
6
17
 
@@ -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.1.0"
6
- date-released: "2025-04-03"
5
+ version: "2.1.1"
6
+ date-released: "2025-05-19"
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.4
2
2
  Name: shapely
3
- Version: 2.1.0
3
+ Version: 2.1.1
4
4
  Summary: Manipulation and analysis of geometric objects
5
5
  Author: Sean Gillies
6
6
  Maintainer: Shapely contributors
@@ -84,7 +84,7 @@ Therefore, geometries are equal if and only if their WKB representations are equ
84
84
  >>> point_1 = Point(5.2, 52.1)
85
85
  >>> point_2 = Point(1, 1)
86
86
  >>> point_3 = Point(5.2, 52.1)
87
- >>> {point_1, point_2, point_3}
87
+ >>> {point_1, point_2, point_3} # doctest: +SKIP
88
88
  {<POINT (1 1)>, <POINT (5.2 52.1)>}
89
89
 
90
90
  .. warning:: Due to limitations of WKB, linearrings will equal linestrings if they contain the exact same points.
@@ -113,9 +113,9 @@ The most convenient is to use ``.wkb_hex`` and ``.wkt`` properties.
113
113
  >>> from shapely import Point, to_wkb, to_wkt, to_geojson
114
114
  >>> pt = Point(-169.910918, -18.997564)
115
115
  >>> pt.wkb_hex
116
- 0101000000CF6A813D263D65C0BDAAB35A60FF32C0
116
+ '0101000000CF6A813D263D65C0BDAAB35A60FF32C0'
117
117
  >>> pt.wkt
118
- POINT (-169.910918 -18.997564)
118
+ 'POINT (-169.910918 -18.997564)'
119
119
 
120
120
  More output options can be found using using :func:`~shapely.to_wkb`,
121
121
  :func:`~shapely.to_wkt`, and :func:`~shapely.to_geojson` functions.
@@ -123,9 +123,9 @@ More output options can be found using using :func:`~shapely.to_wkb`,
123
123
  .. code:: python
124
124
 
125
125
  >>> to_wkb(pt, hex=True, byte_order=0)
126
- 0000000001C0653D263D816ACFC032FF605AB3AABD
126
+ '0000000001C0653D263D816ACFC032FF605AB3AABD'
127
127
  >>> to_wkt(pt, rounding_precision=3)
128
- POINT (-169.911 -18.998)
128
+ 'POINT (-169.911 -18.998)'
129
129
  >>> print(to_geojson(pt, indent=2))
130
130
  {
131
131
  "type": "Point",
@@ -158,21 +158,35 @@ Semantic for format specification
158
158
 
159
159
  Format types ``'f'`` and ``'F'`` are to use a fixed-point notation, which is
160
160
  activated by setting GEOS' trim option off.
161
- The upper case variant converts ``nan`` to ``NAN`` and ``inf`` to ``INF``.
162
161
 
163
- Format types ``'g'`` and ``'G'`` are to use a "general format",
162
+ Format types ``'g'`` (default) and ``'G'`` are to use a "general format",
164
163
  where unnecessary digits are trimmed. This notation is activated by setting
165
- GEOS' trim option on. The upper case variant is similar to
166
- ``'F'``, and may also display an upper-case ``"E"`` if scientific notation
167
- is required. Note that this representation may be different for GEOS 3.10.0
168
- and later, which does not use scientific notation.
164
+ GEOS' trim option on. This option sometimes enables
165
+ :ref:`scientific-formatting`.
169
166
 
170
- For numeric outputs ``'f'`` and ``'g'``, the precision is optional, and if not
167
+ For numeric outputs ``[fFgG]``, the precision is optional, and if not
171
168
  specified, rounding precision will be disabled showing full precision.
172
169
 
173
170
  Format types ``'x'`` and ``'X'`` show a hex-encoded string representation of
174
- WKB or Well-Known Binary, with the case of the output matched the
175
- case of the format type character.
171
+ WKB or Well-Known Binary.
172
+
173
+ The upper case letter variant converts all non-numeric values to uppercase,
174
+ e.g. ``nan`` to ``NAN``, or ``e`` to ``E``.
175
+
176
+ .. _scientific-formatting:
177
+
178
+ Scientific formatting
179
+ ---------------------
180
+
181
+ WKT outputs may sometimes use scientific formatting, depending on the GEOS
182
+ version, coordinate value and WKT writer options. GEOS versions 3.10 to 3.12
183
+ never use scientific formatting (only showing positional), while older and
184
+ newer versions may use scientific formatting for large and small coordinate
185
+ values (e.g. ``POINT (1.234e+18 1.234e-11)``).
186
+
187
+ Scientific formatting can always be disabled by setting ``trim=False`` for
188
+ :func:`~shapely.to_wkt` or other WKT writer methods,
189
+ which sets the WKT writer to use fixed-precision number formatting.
176
190
 
177
191
  .. _canonical-form:
178
192
 
@@ -1285,34 +1285,7 @@ and that copies of these are collected into a list
1285
1285
  >>> features = [c, a, d, b, c]
1286
1286
 
1287
1287
  that we'd prefer to have ordered as ``[d, c, c, b, a]`` in reverse containment
1288
- order. As explained in the Python `Sorting HowTo`_, we can define a key
1289
- function that operates on each list element and returns a value for comparison.
1290
- Our key function will be a wrapper class that implements ``__lt__()`` using
1291
- Shapely's binary :meth:`~object.within` predicate.
1292
-
1293
- .. code-block:: python
1294
-
1295
- >>> class Within:
1296
- ... def __init__(self, o):
1297
- ... self.o = o
1298
- ... def __lt__(self, other):
1299
- ... return self.o.within(other.o)
1300
-
1301
- As the howto says, the `less than` comparison is guaranteed to be used in
1302
- sorting. That's what we'll rely on to spatially sort. Trying it out on features
1303
- `d` and `c`, we see that it works.
1304
-
1305
- .. code-block:: pycon
1306
-
1307
- >>> Within(d) < Within(c)
1308
- False
1309
-
1310
- It also works on the list of features, producing the order we want.
1311
-
1312
- .. code-block:: pycon
1313
-
1314
- >>> [d, c, c, b, a] == sorted(features, key=Within, reverse=True)
1315
- True
1288
+ order.
1316
1289
 
1317
1290
  DE-9IM Relationships
1318
1291
  --------------------
@@ -5,9 +5,9 @@ Migrating to Shapely 1.8 / 2.0
5
5
  ==============================
6
6
 
7
7
  Shapely 1.8.0 is a transitional version introducing several warnings in
8
- preparation of the upcoming changes in 2.0.0.
8
+ transition to 2.0.0.
9
9
 
10
- Shapely 2.0.0 will be a major release with a refactor of the internals with
10
+ Shapely 2.0.0 was a major release with a refactor of the internals with
11
11
  considerable performance improvements (based on the developments in the
12
12
  `PyGEOS <https://github.com/pygeos/pygeos>`__ package), along with several
13
13
  breaking changes.
@@ -33,13 +33,13 @@ can change their coordinates in-place. Illustrative code::
33
33
  >>> print(line)
34
34
  LINESTRING (0 0, 2 2)
35
35
 
36
- >>> line.coords = [(0, 0), (10, 0), (10, 10)]
37
- >>> print(line)
36
+ >>> line.coords = [(0, 0), (10, 0), (10, 10)] # doctest: +SKIP
37
+ >>> print(line) # doctest: +SKIP
38
38
  LINESTRING (0 0, 10 0, 10 10)
39
39
 
40
40
  In Shapely 1.8, this will start raising a warning::
41
41
 
42
- >>> line.coords = [(0, 0), (10, 0), (10, 10)]
42
+ >>> line.coords = [(0, 0), (10, 0), (10, 10)] # doctest: +SKIP
43
43
  ShapelyDeprecationWarning: Setting the 'coords' to mutate a Geometry
44
44
  in place is deprecated, and will not be possible any more in Shapely 2.0
45
45
 
@@ -56,15 +56,16 @@ Setting custom attributes
56
56
  -------------------------
57
57
 
58
58
  Another consequence of the geometry objects becoming immutable is that
59
- assigning custom attributes, which currently works, will no longer be possible.
59
+ assigning custom attributes, which previously worked, will no longer be
60
+ possible.
60
61
 
61
- Currently you can do::
62
+ Previously, custom attributes could have ben added::
62
63
 
63
- >>> line.name = "my_geometry"
64
- >>> line.name
64
+ >>> line.name = "my_geometry" # doctest: +SKIP
65
+ >>> line.name # doctest: +SKIP
65
66
  'my_geometry'
66
67
 
67
- In Shapely 1.8, this will start raising a warning, and will raise an
68
+ In Shapely 1.8, this will raise a warning, and will raise an
68
69
  AttributeError in Shapely 2.0.
69
70
 
70
71
  **How do I update my code?** There is no direct alternative for adding custom
@@ -85,18 +86,18 @@ Some examples of this with Shapely 1.x:
85
86
 
86
87
  >>> from shapely.geometry import Point, MultiPoint
87
88
  >>> mp = MultiPoint([(1, 1), (2, 2), (3, 3)])
88
- >>> print(mp)
89
+ >>> print(mp) # doctest: +SKIP
89
90
  MULTIPOINT (1 1, 2 2, 3 3)
90
- >>> for part in mp:
91
- ... print(part)
91
+ >>> for part in mp: # doctest: +SKIP
92
+ ... print(part) # doctest: +SKIP
92
93
  POINT (1 1)
93
94
  POINT (2 2)
94
95
  POINT (3 3)
95
- >>> print(mp[1])
96
+ >>> print(mp[1]) # doctest: +SKIP
96
97
  POINT (2 2)
97
- >>> len(mp)
98
+ >>> len(mp) # doctest: +SKIP
98
99
  3
99
- >>> list(mp)
100
+ >>> list(mp) # doctest: +SKIP
100
101
  [<shapely.geometry.point.Point at 0x7f2e0912bf10>,
101
102
  <shapely.geometry.point.Point at 0x7f2e09fed820>,
102
103
  <shapely.geometry.point.Point at 0x7f2e09fed4c0>]
@@ -104,8 +105,8 @@ Some examples of this with Shapely 1.x:
104
105
  Starting with Shapely 1.8, all the examples above will start raising a
105
106
  deprecation warning. For example:
106
107
 
107
- >>> for part in mp:
108
- ... print(part)
108
+ >>> for part in mp: # doctest: +SKIP
109
+ ... print(part) # doctest: +SKIP
109
110
  ShapelyDeprecationWarning: Iteration over multi-part geometries is deprecated
110
111
  and will be removed in Shapely 2.0. Use the `geoms` property to access the
111
112
  constituent parts of a multi-part geometry.
@@ -129,7 +130,7 @@ The examples above can be updated to::
129
130
  POINT (2 2)
130
131
  >>> len(mp.geoms)
131
132
  3
132
- >>> list(mp.geoms)
133
+ >>> list(mp.geoms) # doctest: +SKIP
133
134
  [<shapely.geometry.point.Point at 0x7f2e0912bf10>,
134
135
  <shapely.geometry.point.Point at 0x7f2e09fed820>,
135
136
  <shapely.geometry.point.Point at 0x7f2e09fed4c0>]
@@ -152,7 +153,7 @@ A small example::
152
153
 
153
154
  >>> line = LineString([(0, 0), (1, 1), (2, 2)])
154
155
  >>> import numpy as np
155
- >>> np.asarray(line)
156
+ >>> np.asarray(line) # doctest: +SKIP
156
157
  array([[0., 0.],
157
158
  [1., 1.],
158
159
  [2., 2.]])
@@ -160,9 +161,9 @@ A small example::
160
161
  In addition, there are also the explicit ``array_interface()`` method and
161
162
  ``ctypes`` attribute to get access to the coordinates as array data:
162
163
 
163
- >>> line.ctypes
164
+ >>> line.ctypes # doctest: +SKIP
164
165
  <shapely.geometry.linestring.c_double_Array_6 at 0x7f75261eb740>
165
- >>> line.array_interface()
166
+ >>> line.array_interface() # doctest: +SKIP
166
167
  {'version': 3,
167
168
  'typestr': '<f8',
168
169
  'data': <shapely.geometry.linestring.c_double_Array_6 at 0x7f752664ae40>,
@@ -177,7 +178,7 @@ removed from those geometry classes, and limited to the ``coords``.
177
178
  Starting with Shapely 1.8, converting a geometry object to a NumPy array
178
179
  directly will start raising a warning::
179
180
 
180
- >>> np.asarray(line)
181
+ >>> np.asarray(line) # doctest: +SKIP
181
182
  ShapelyDeprecationWarning: The array interface is deprecated and will no longer
182
183
  work in Shapely 2.0. Convert the '.coords' to a NumPy array instead.
183
184
  array([[0., 0.],
@@ -209,7 +210,7 @@ as follows::
209
210
 
210
211
  >>> from shapely.geometry import Point
211
212
  >>> arr = np.array([Point(0, 0), Point(1, 1), Point(2, 2)])
212
- >>> arr
213
+ >>> arr # doctest: +SKIP
213
214
  array([<shapely.geometry.point.Point object at 0x7fb798407cd0>,
214
215
  <shapely.geometry.point.Point object at 0x7fb7982831c0>,
215
216
  <shapely.geometry.point.Point object at 0x7fb798283b80>],
@@ -300,7 +301,7 @@ creation methods. A small example for an empty Polygon geometry:
300
301
  >>> g1 = Polygon()
301
302
  >>> type(g1)
302
303
  <class 'shapely.geometry.polygon.Polygon'>
303
- >>> g1.wkt
304
+ >>> g1.wkt # doctest: +SKIP
304
305
  GEOMETRYCOLLECTION EMPTY
305
306
 
306
307
  # Converting from WKT gives a correct empty polygon
@@ -309,7 +310,7 @@ creation methods. A small example for an empty Polygon geometry:
309
310
  >>> type(g2)
310
311
  <class 'shapely.geometry.polygon.Polygon'>
311
312
  >>> g2.wkt
312
- POLYGON EMPTY
313
+ 'POLYGON EMPTY'
313
314
 
314
315
  Shapely 1.8 does not yet change this inconsistent behaviour, but starting
315
316
  with Shapely 2.0, the different methods will always consistently give an
@@ -284,7 +284,7 @@ def get_parts(object[:] array, bint extract_rings=0):
284
284
 
285
285
  @cython.boundscheck(False)
286
286
  @cython.wraparound(False)
287
- cdef void _deallocate_arr(void* handle, np.intp_t[:] arr, Py_ssize_t last_geom_i) noexcept nogil:
287
+ cdef void _deallocate_arr(GEOSContextHandle_t handle, np.intp_t[:] arr, Py_ssize_t last_geom_i) noexcept nogil:
288
288
  """Deallocate a temporary geometry array to prevent memory leaks"""
289
289
  cdef Py_ssize_t i = 0
290
290
  cdef GEOSGeometry *g
@@ -421,7 +421,7 @@ def collections_1d(object geometries, object indices, int geometry_type = 7, obj
421
421
  coll = GEOSGeom_createPolygon_r(
422
422
  geos_handle,
423
423
  <GEOSGeometry*> temp_geoms_view[0],
424
- NULL if coll_size <= 1 else <GEOSGeometry**> &temp_geoms_view[1],
424
+ <GEOSGeometry**> NULL if coll_size <= 1 else <GEOSGeometry**> &temp_geoms_view[1],
425
425
  coll_size - 1
426
426
  )
427
427
  else: # Polygon, empty
@@ -454,7 +454,7 @@ def _from_ragged_array_multi_linear(
454
454
  MultiLineString (geometry_type 5): linear_type is a LineString (1)
455
455
  """
456
456
  cdef:
457
- Py_ssize_t n_geoms
457
+ Py_ssize_t n_total_coords, n_rings, n_geoms
458
458
  Py_ssize_t i, k
459
459
  Py_ssize_t i1, i2, k1, k2
460
460
  Py_ssize_t n_coords, linear_idx
@@ -463,12 +463,26 @@ def _from_ragged_array_multi_linear(
463
463
  GEOSGeometry *linear = NULL
464
464
  GEOSGeometry *geom = NULL
465
465
 
466
+ n_total_coords = coordinates.shape[0]
467
+ n_rings = offsets1.shape[0] - 1
466
468
  n_geoms = offsets2.shape[0] - 1
467
469
 
470
+ if offsets2[n_geoms] > n_rings:
471
+ raise ValueError(
472
+ f"Number of rings indicated by the geometry offsets ({offsets2[n_geoms]}) "
473
+ f"larger than indicated by the shape of the linear offsets array ({n_rings})"
474
+ )
475
+
476
+ if offsets1[n_rings] > n_total_coords:
477
+ raise ValueError(
478
+ f"Number of coordinates indicated by the linear offsets ({offsets1[n_rings]}) "
479
+ f"larger than the shape of the coordinates array ({n_total_coords})"
480
+ )
481
+
468
482
  # A temporary array for the geometries that will be given to CreatePolygon/Collection.
469
- # For simplicity, we use n_geoms instead of calculating
470
- # the max needed size (trading performance for a bit more memory usage)
471
- temp_linear = np.empty(shape=(n_geoms, ), dtype=np.intp)
483
+ # For simplicity, we use n_rings instead of calculating the max needed size
484
+ # as max(diff(offsets2)) (trading performance for a bit more memory usage)
485
+ temp_linear = np.empty(shape=(n_rings, ), dtype=np.intp)
472
486
  cdef np.intp_t[:] temp_linear_view = temp_linear
473
487
  # A temporary array for resulting geometries
474
488
  temp_geoms = np.empty(shape=(n_geoms, ), dtype=np.intp)
@@ -570,7 +584,7 @@ def _from_ragged_array_multipolygon(
570
584
  Create MultiPolygons from coordinate and offset arrays.
571
585
  """
572
586
  cdef:
573
- Py_ssize_t n_geoms
587
+ Py_ssize_t n_total_coords, n_rings, n_parts, n_geoms
574
588
  Py_ssize_t i, j, k
575
589
  Py_ssize_t i1, i2, j1, j2, k1, k2
576
590
  Py_ssize_t n_coords, rings_idx, parts_idx
@@ -580,14 +594,35 @@ def _from_ragged_array_multipolygon(
580
594
  GEOSGeometry *part = NULL
581
595
  GEOSGeometry *geom = NULL
582
596
 
597
+ n_total_coords = coordinates.shape[0]
598
+ n_rings = offsets1.shape[0] - 1
599
+ n_parts = offsets2.shape[0] - 1
583
600
  n_geoms = offsets3.shape[0] - 1
584
601
 
602
+ if offsets3[n_geoms] > n_parts:
603
+ raise ValueError(
604
+ f"Number of geometry parts indicated by the geometry offsets ({offsets3[n_geoms]}) "
605
+ f"larger than indicated by the shape of the part offsets array ({n_parts})"
606
+ )
607
+
608
+ if offsets2[n_parts] > n_rings:
609
+ raise ValueError(
610
+ f"Number of rings indicated by the part offsets ({offsets2[n_parts]}) "
611
+ f"larger than indicated by the shape of the linear offsets array ({n_rings})"
612
+ )
613
+
614
+ if offsets1[n_rings] > n_total_coords:
615
+ raise ValueError(
616
+ f"Number of coordinates indicated by the linear offsets ({offsets1[n_rings]}) "
617
+ f"larger than the shape of the coordinates array ({n_total_coords})"
618
+ )
619
+
585
620
  # A temporary array for the geometries that will be given to CreatePolygon
586
- # and CreateCollection. For simplicity, we use n_geoms instead of calculating
587
- # the max needed size (trading performance for a bit more memory usage)
588
- temp_rings = np.empty(shape=(n_geoms, ), dtype=np.intp)
621
+ # and CreateCollection. For simplicity, we use n_rings/n_parts instead of
622
+ # calculating the max needed size (trading performance for a bit more memory usage)
623
+ temp_rings = np.empty(shape=(n_rings, ), dtype=np.intp)
589
624
  cdef np.intp_t[:] temp_rings_view = temp_rings
590
- temp_parts = np.empty(shape=(n_geoms, ), dtype=np.intp)
625
+ temp_parts = np.empty(shape=(n_parts, ), dtype=np.intp)
591
626
  cdef np.intp_t[:] temp_parts_view = temp_parts
592
627
  # A temporary array for resulting geometries
593
628
  temp_geoms = np.empty(shape=(n_geoms, ), dtype=np.intp)
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2025-04-03T10:55:05+0200",
11
+ "date": "2025-05-19T12:40:46+0200",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "4940c6405ac9ef2d77c9e9990954b68294c3c399",
15
- "version": "2.1.0"
14
+ "full-revisionid": "b49155ea7eaec698a0357fb9bc1147533b566916",
15
+ "version": "2.1.1"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -1,9 +1,10 @@
1
1
  """Decorators for Shapely functions."""
2
2
 
3
- import inspect
4
3
  import os
5
4
  import warnings
6
- from functools import wraps
5
+ from collections.abc import Callable, Iterable
6
+ from functools import lru_cache, wraps
7
+ from inspect import unwrap
7
8
 
8
9
  import numpy as np
9
10
 
@@ -92,41 +93,90 @@ def multithreading_enabled(func):
92
93
  return wrapped
93
94
 
94
95
 
95
- def deprecate_positional(should_be_kwargs, category=DeprecationWarning):
96
- """Show warning if positional arguments are used that should be keyword."""
96
+ def deprecate_positional(
97
+ should_be_kwargs: Iterable[str],
98
+ category: type[Warning] = DeprecationWarning,
99
+ ):
100
+ """Show warning if positional arguments are used that should be keyword.
101
+
102
+ Parameters
103
+ ----------
104
+ should_be_kwargs : Iterable[str]
105
+ Names of parameters that should be passed as keyword arguments.
106
+ category : type[Warning], optional (default: DeprecationWarning)
107
+ Warning category to use for deprecation warnings.
108
+
109
+ Returns
110
+ -------
111
+ callable
112
+ Decorator function that adds positional argument deprecation warnings.
113
+
114
+ Examples
115
+ --------
116
+ >>> from shapely.decorators import deprecate_positional
117
+ >>> @deprecate_positional(['b', 'c'])
118
+ ... def example(a, b, c=None):
119
+ ... return a, b, c
120
+ ...
121
+ >>> example(1, 2) # doctest: +SKIP
122
+ DeprecationWarning: positional argument `b` for `example` is deprecated. ...
123
+ (1, 2, None)
124
+ >>> example(1, b=2) # No warnings
125
+ (1, 2, None)
126
+ """
127
+
128
+ def decorator(func: Callable):
129
+ code = unwrap(func).__code__
130
+
131
+ # positional parameters are the first co_argcount names
132
+ pos_names = code.co_varnames[: code.co_argcount]
133
+ # build a name -> index map
134
+ name_to_idx = {name: idx for idx, name in enumerate(pos_names)}
135
+ # pick out only those names we care about
136
+ deprecate_positions = [
137
+ (name_to_idx[name], name)
138
+ for name in should_be_kwargs
139
+ if name in name_to_idx
140
+ ]
141
+
142
+ # early exit if there are no deprecated positional args
143
+ if not deprecate_positions:
144
+ return func
145
+
146
+ # earliest position where a warning could occur
147
+ warn_from = min(deprecate_positions)[0]
148
+
149
+ @lru_cache(10)
150
+ def make_msg(n_args: int):
151
+ used = [name for idx, name in deprecate_positions if idx < n_args]
152
+
153
+ if len(used) == 1:
154
+ args_txt = f"`{used[0]}`"
155
+ plr = ""
156
+ isare = "is"
157
+ else:
158
+ plr = "s"
159
+ isare = "are"
160
+ if len(used) == 2:
161
+ args_txt = " and ".join(f"`{u}`" for u in used)
162
+ else:
163
+ args_txt = ", ".join(f"`{u}`" for u in used[:-1])
164
+ args_txt += f", and `{used[-1]}`"
165
+
166
+ return (
167
+ f"positional argument{plr} {args_txt} for `{func.__name__}` "
168
+ f"{isare} deprecated. Please use keyword argument{plr} instead."
169
+ )
97
170
 
98
- def decorator(func):
99
171
  @wraps(func)
100
172
  def wrapper(*args, **kwargs):
101
- # call the function first, to make sure the signature matches
102
- ret_value = func(*args, **kwargs)
103
-
104
- # check signature to see which positional args were used
105
- sig = inspect.signature(func)
106
- args_bind = sig.bind_partial(*args)
107
- warn_args = [
108
- f"`{arg}`"
109
- for arg in args_bind.arguments.keys()
110
- if arg in should_be_kwargs
111
- ]
112
- if warn_args:
113
- if len(warn_args) == 1:
114
- plr = ""
115
- isare = "is"
116
- args = warn_args[0]
117
- else:
118
- plr = "s"
119
- isare = "are"
120
- if len(warn_args) < 3:
121
- args = " and ".join(warn_args)
122
- else:
123
- args = ", ".join(warn_args[:-1]) + ", and " + warn_args[-1]
124
- msg = (
125
- f"positional argument{plr} {args} for `{func.__name__}` "
126
- f"{isare} deprecated. Please use keyword argument{plr} instead."
127
- )
128
- warnings.warn(msg, category=category, stacklevel=2)
129
- return ret_value
173
+ result = func(*args, **kwargs)
174
+
175
+ n = len(args)
176
+ if n > warn_from:
177
+ warnings.warn(make_msg(n), category=category, stacklevel=2)
178
+
179
+ return result
130
180
 
131
181
  return wrapper
132
182
 
@@ -56,7 +56,8 @@ def to_wkt(
56
56
  The rounding precision when writing the WKT string. Set to a value of
57
57
  -1 to indicate the full precision.
58
58
  trim : bool, default True
59
- If True, trim unnecessary decimals (trailing zeros).
59
+ If True, trim unnecessary decimals (trailing zeros). If False,
60
+ use fixed-precision number formatting.
60
61
  output_dimension : int, default None
61
62
  The output dimension for the WKT string. Supported values are 2, 3 and
62
63
  4 for GEOS 3.12+. Default None will automatically choose 3 or 4,
@@ -48,7 +48,10 @@ class PolylabelTestCase(unittest.TestCase):
48
48
  ]
49
49
  )
50
50
  label = polylabel(polygon)
51
- if shapely.geos_version >= (3, 12, 0):
51
+ if shapely.geos_version >= (3, 14, 0):
52
+ # https://github.com/libgeos/geos/issues/1265
53
+ assert label.coords[:] == [(32.722025, -117.195155)]
54
+ elif shapely.geos_version >= (3, 12, 0):
52
55
  # recent GEOS corrects for this
53
56
  assert label.coords[:] == [(32.722025, -117.201875)]
54
57
  else:
@@ -1184,7 +1184,7 @@ def test_maximum_inscribed_circle_all_types(geometry):
1184
1184
  GEOSException,
1185
1185
  match=(
1186
1186
  "Argument must be Polygonal or LinearRing|" # GEOS < 3.10.4
1187
- "Input geometry must be a Polygon or MultiPolygon|"
1187
+ "must be a Polygon or MultiPolygon|"
1188
1188
  "Operation not supported by GeometryCollection"
1189
1189
  ),
1190
1190
  ):
@@ -1193,7 +1193,7 @@ def test_maximum_inscribed_circle_all_types(geometry):
1193
1193
 
1194
1194
  if geometry.is_empty:
1195
1195
  with pytest.raises(
1196
- GEOSException, match="Empty input geometry is not supported"
1196
+ GEOSException, match="Empty input(?: geometry)? is not supported"
1197
1197
  ):
1198
1198
  shapely.maximum_inscribed_circle(geometry)
1199
1199
  return
@@ -1227,13 +1227,15 @@ def test_maximum_inscribed_circle_empty():
1227
1227
  GEOSException,
1228
1228
  match=(
1229
1229
  "Argument must be Polygonal or LinearRing|" # GEOS < 3.10.4
1230
- "Input geometry must be a Polygon or MultiPolygon"
1230
+ "must be a Polygon or MultiPolygon"
1231
1231
  ),
1232
1232
  ):
1233
1233
  shapely.maximum_inscribed_circle(geometry)
1234
1234
 
1235
1235
  geometry = shapely.from_wkt("POLYGON EMPTY")
1236
- with pytest.raises(GEOSException, match="Empty input geometry is not supported"):
1236
+ with pytest.raises(
1237
+ GEOSException, match="Empty input(?: geometry)? is not supported"
1238
+ ):
1237
1239
  shapely.maximum_inscribed_circle(geometry)
1238
1240
 
1239
1241