Repository: shapely/shapely
Pull request #2074 (2024-06-24 14:15:42)

BUG: fix Point x/y/z/m attribtues to return Python floats
Closes https://github.com/shapely/shapely/issues/2070

coveralls: ## Pull Request Test Coverage Report for [Build 9646980112](https://coveralls.io/builds/68261168)


### Details

* **3** of **4**   **(75.0%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.3%**) to **88.134%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [shapely/geometry/point.py](https://coveralls.io/builds/68261168/source?filename=shapely%2Fgeometry%2Fpoint.py#L111) | 3 | 4 | 75.0%
<!-- | **Total:** | **3** | **4** | **75.0%** | -->


|  Totals | [![Coverage Status](https://coveralls.io/builds/68261168/badge)](https://coveralls.io/builds/68261168) |
| :-- | --: |
| Change from base [Build 9645569914](https://coveralls.io/builds/68259044): |  0.3% |
| Covered Lines: | 2622 |
| Relevant Lines: | 2975 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 5f08e39..b1db1e3 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -136,14 +136,7 @@ jobs:
             GEOS_INCLUDE_PATH='${{ runner.temp }}\geos-${{ env.GEOS_VERSION }}\include'
           CIBW_BEFORE_ALL: ./ci/install_geos.sh
           CIBW_BEFORE_ALL_WINDOWS: ci\install_geos.cmd
-          # TEMP don't use automated/isolated build environment, but manually
-          # install build dependencies so we can build with numpy 2.0
-          # once numpy 2.0 is out, this can be removed again
-          CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation"
-          CIBW_BEFORE_BUILD: pip install --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy setuptools cython wheel
-          CIBW_BEFORE_BUILD_WINDOWS:
-            pip install --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy setuptools cython wheel
-            pip install delvewheel
+          CIBW_BEFORE_BUILD_WINDOWS: pip install delvewheel
           CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: delvewheel repair --add-path ${{ runner.temp }}\geos-${{ env.GEOS_VERSION }}\bin -w {dest_dir} {wheel}
           CIBW_TEST_REQUIRES: pytest
           CIBW_TEST_COMMAND: pytest --pyargs shapely.tests
diff --git a/MANIFEST.in b/MANIFEST.in
index 8112841..aaba5c5 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,7 +4,6 @@ exclude MANIFEST.in
 include CITATION.cff CHANGES.txt CREDITS.txt LICENSE.txt README.rst
 include pyproject.toml versioneer.py
 recursive-include src *.c *.h
-recursive-include tests *.py
 recursive-include shapely *.pxd *.pyx
 recursive-exclude shapely *.c
 include docs/*.rst
diff --git a/setup.py b/setup.py
index edbb430..f5c5dcf 100644
--- a/setup.py
+++ b/setup.py
@@ -5,8 +5,7 @@ import subprocess
 import sys
 from pathlib import Path
 
-from pkg_resources import parse_version
-from setuptools import Extension, find_packages, setup
+from setuptools import Extension, setup
 from setuptools.command.build_ext import build_ext as _build_ext
 
 # ensure the current directory is on sys.path so versioneer can be imported
@@ -42,15 +41,13 @@ def get_geos_config(option):
     """
     cmd = os.environ.get("GEOS_CONFIG", "geos-config")
     try:
-        stdout, stderr = subprocess.Popen(
-            [cmd, option], stdout=subprocess.PIPE, stderr=subprocess.PIPE
-        ).communicate()
+        proc = subprocess.run([cmd, option], capture_output=True, text=True)
     except OSError:
         return
-    if stderr and not stdout:
-        log.warning("geos-config %s returned '%s'", option, stderr.decode().strip())
+    if proc.stderr and not proc.stdout:
+        log.warning("geos-config %s returned '%s'", option, proc.stderr.strip())
         return
-    result = stdout.decode().strip()
+    result = proc.stdout.strip()
     log.debug("geos-config %s returned '%s'", option, result)
     return result
 
@@ -86,11 +83,12 @@ def get_geos_paths():
         )
         return {}
 
-    if parse_version(geos_version) < parse_version(MIN_GEOS_VERSION):
+    def version_tuple(ver):
+        return tuple(int(itm) if itm.isnumeric() else itm for itm in ver.split("."))
+
+    if version_tuple(geos_version) < version_tuple(MIN_GEOS_VERSION):
         raise ImportError(
-            "GEOS version should be >={}, found {}".format(
-                MIN_GEOS_VERSION, geos_version
-            )
+            f"GEOS version should be >={MIN_GEOS_VERSION}, found {geos_version}"
         )
 
     libraries = []
@@ -133,7 +131,7 @@ class build_ext(_build_ext):
 
         import numpy
 
-        self.include_dirs.append(numpy.get_include())
+        self.include_dirs.insert(0, numpy.get_include())
 
 
 ext_modules = []
diff --git a/shapely/geometry/point.py b/shapely/geometry/point.py
index 8c1660e..045c796 100644
--- a/shapely/geometry/point.py
+++ b/shapely/geometry/point.py
@@ -85,19 +85,19 @@ class Point(BaseGeometry):
     @property
     def x(self):
         """Return x coordinate."""
-        return shapely.get_x(self)
+        return float(shapely.get_x(self))
 
     @property
     def y(self):
         """Return y coordinate."""
-        return shapely.get_y(self)
+        return float(shapely.get_y(self))
 
     @property
     def z(self):
         """Return z coordinate."""
         if not shapely.has_z(self):
             raise DimensionError("This point has no z coordinate.")
-        return shapely.get_z(self)
+        return float(shapely.get_z(self))
 
     @property
     def m(self):
@@ -108,7 +108,7 @@ class Point(BaseGeometry):
         """
         if not shapely.has_m(self):
             raise DimensionError("This point has no m coordinate.")
-        return shapely.get_m(self)
+        return float(shapely.get_m(self))
 
     @property
     def __geo_interface__(self):


Test patch:
diff --git a/shapely/tests/geometry/test_point.py b/shapely/tests/geometry/test_point.py
index 505459c..bb5811a 100644
--- a/shapely/tests/geometry/test_point.py
+++ b/shapely/tests/geometry/test_point.py
@@ -101,7 +101,9 @@ class TestPoint:
         # Test XY point
         p = Point(1.0, 2.0)
         assert p.x == 1.0
+        assert type(p.x) is float
         assert p.y == 2.0
+        assert type(p.y) is float
         assert p.coords[:] == [(1.0, 2.0)]
         assert str(p) == p.wkt
         assert p.has_z is False
@@ -121,6 +123,7 @@ class TestPoint:
         assert str(p) == p.wkt
         assert p.has_z is True
         assert p.z == 3.0
+        assert type(p.z) is float
         if geos_version >= (3, 12, 0):
             assert p.has_m is False
             with pytest.raises(DimensionError):