This is an automated email from the ASF dual-hosted git repository.

jiayu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sedona.git


The following commit(s) were added to refs/heads/master by this push:
     new ddd0e32202 [GH-2513] chore(python): Make 
'assert_geometry_almost_equal' check for Z and M dimensions too (#2517)
ddd0e32202 is described below

commit ddd0e32202d228f797d43f4685540b7e287aed2e
Author: Peter Nguyen <[email protected]>
AuthorDate: Sat Nov 22 21:40:25 2025 -0800

    [GH-2513] chore(python): Make 'assert_geometry_almost_equal' check for Z 
and M dimensions too (#2517)
---
 python/tests/sql/test_dataframe_api.py |  2 +-
 python/tests/test_base.py              | 85 +++++++++++++++++++++++++++++++++-
 2 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/python/tests/sql/test_dataframe_api.py 
b/python/tests/sql/test_dataframe_api.py
index 9751803d7e..9683fc3029 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -916,7 +916,7 @@ test_configurations = [
         ("line", 10.0),
         "4D_line",
         "ST_ReducePrecision(geom, 2)",
-        "LINESTRING Z (1 -0.3 -1.383092639965822, 2 -0.59 -2.766185279931644, 
3 -0.89 -4.149277919897466, -1 0.3 1.383092639965822)",
+        "LINESTRING ZM (1 -0.3 -1.383092639965822 1, 2 -0.59 
-2.766185279931644 2, 3 -0.89 -4.149277919897466 3, -1 0.3 1.383092639965822 
-1)",
     ),
     (
         stf.ST_RotateY,
diff --git a/python/tests/test_base.py b/python/tests/test_base.py
index f9978ca4a8..cc2b09e422 100644
--- a/python/tests/test_base.py
+++ b/python/tests/test_base.py
@@ -28,9 +28,12 @@ from sedona.spark.utils.decorators import classproperty
 SPARK_REMOTE = os.getenv("SPARK_REMOTE")
 EXTRA_JARS = os.getenv("SEDONA_PYTHON_EXTRA_JARS")
 
+import shapely
 from shapely import wkt
 from shapely.geometry.base import BaseGeometry
 
+SHAPELY_GE_210 = shapely.__version__ >= "2.1.0"
+
 
 class TestBase:
 
@@ -122,6 +125,13 @@ class TestBase:
         right_geom: Union[str, BaseGeometry],
         tolerance=1e-6,
     ):
+        """
+        Assert that two geometries are almost equal.
+
+        Note: this function will only check Z and M dimensions for shapely >= 
2.1.0 (python >= 3.10)
+
+        When comparing geometries with Z or M dimensions, this function will 
ignore `tolerance` and check for exact equality.
+        """
         expected_geom = (
             wkt.loads(left_geom) if isinstance(left_geom, str) else left_geom
         )
@@ -129,7 +139,17 @@ class TestBase:
             wkt.loads(right_geom) if isinstance(right_geom, str) else 
right_geom
         )
 
-        if not actual_geom.equals_exact(expected_geom, tolerance=tolerance):
+        # Note: only shapely >= 2.1.0 supports Z and M dimensions
+        # If has Z or M dimension, use equals_identical to check the equality
+        if SHAPELY_GE_210 and (has_zm(actual_geom) or has_zm(expected_geom)):
+            if not shapely.equals_identical(actual_geom, expected_geom):
+                raise ValueError(
+                    f"Geometry equality check failed for {left_geom} and 
{right_geom}"
+                )
+
+        # Comparison for XY geometries
+        # Note: equals_exact doesn't check for Z or M dimensions
+        elif not actual_geom.equals_exact(expected_geom, tolerance=tolerance):
             # If the exact equals check fails, perform a buffer check with 
tolerance
             if (
                 actual_geom.is_valid
@@ -143,3 +163,66 @@ class TestBase:
                 raise ValueError(
                     f"Geometry equality check failed for {left_geom} and 
{right_geom}"
                 )
+
+
+def has_zm(geom: BaseGeometry):
+    return geom.has_z or geom.has_m
+
+
+def test_assert_geometry_almost_equal():
+    import pytest
+
+    TestBase.assert_geometry_almost_equal("POINT (1 1)", "POINT (1 1)")
+    TestBase.assert_geometry_almost_equal("POINT (1 1)", "POINT (1.000001 1)")
+    TestBase.assert_geometry_almost_equal("POINT (1 1)", "POINT (1.000001 1)")
+
+    with pytest.raises(ValueError):
+        TestBase.assert_geometry_almost_equal("POINT (1 1)", "POINT (2 2)")
+
+    with pytest.raises(ValueError):
+        TestBase.assert_geometry_almost_equal("POINT (1 1)", "POINT (2 2)")
+
+    # Check Z and M dimension compatibility (requires shapely >= 2.1.0)
+    if SHAPELY_GE_210:
+        # 2D vs 3D should fail
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal("POINT (1 1)", "POINT (1 1 
0)")
+
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal("POINT (1 1 0)", "POINT (1 
1)")
+
+        # Different 3D should fail
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal("POINT (1 1 1)", "POINT (1 1 
2)")
+
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal("POINT (1 1 2)", "POINT (1 1 
1)")
+
+        # Z vs M dimension should fail
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal("POINT Z (1 1 1)", "POINT M 
(1 1 1)")
+
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal("POINT M (1 1 1)", "POINT Z 
(1 1 1)")
+
+        # 3D vs 4D should fail
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal(
+                "POINT Z (1 1 1)", "POINT ZM (1 1 1 1)"
+            )
+
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal(
+                "POINT ZM (1 1 1 1)", "POINT Z (1 1 1)"
+            )
+
+        # Different 4D should fail
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal(
+                "POINT ZM (1 1 1 1)", "POINT ZM (1 1 1 2)"
+            )
+
+        with pytest.raises(ValueError):
+            TestBase.assert_geometry_almost_equal(
+                "POINT ZM (1 1 1 2)", "POINT ZM (1 1 1 1)"
+            )

Reply via email to