Browse Source

Fixed #36058 -- Refactored SpatialRefSysMixin.srs to use cached_property.

Replaced manual caching complexity with cached_property for efficiency.
Enhanced error handling with distinct messages for WKT and PROJ.4.

Thanks to Sarah Boyce for the suggestions.
Arnaldo Govenem 2 months ago
parent
commit
8ff1399f06
2 changed files with 32 additions and 25 deletions
  1. 17 25
      django/contrib/gis/db/backends/base/models.py
  2. 15 0
      tests/gis_tests/test_spatialrefsys.py

+ 17 - 25
django/contrib/gis/db/backends/base/models.py

@@ -1,4 +1,5 @@
 from django.contrib.gis import gdal
+from django.utils.functional import cached_property
 
 
 class SpatialRefSysMixin:
@@ -7,35 +8,26 @@ class SpatialRefSysMixin:
     SpatialRefSys objects to reduce redundant code.
     """
 
-    @property
+    @cached_property
     def srs(self):
         """
         Return a GDAL SpatialReference object.
         """
-        # TODO: Is caching really necessary here?  Is complexity worth it?
-        if hasattr(self, "_srs"):
-            # Returning a clone of the cached SpatialReference object.
-            return self._srs.clone()
-        else:
-            # Attempting to cache a SpatialReference object.
-
-            # Trying to get from WKT first.
-            try:
-                self._srs = gdal.SpatialReference(self.wkt)
-                return self.srs
-            except Exception as e:
-                msg = e
-
-            try:
-                self._srs = gdal.SpatialReference(self.proj4text)
-                return self.srs
-            except Exception as e:
-                msg = e
-
-            raise Exception(
-                "Could not get OSR SpatialReference from WKT: %s\nError:\n%s"
-                % (self.wkt, msg)
-            )
+        try:
+            return gdal.SpatialReference(self.wkt)
+        except Exception as e:
+            wkt_error = e
+
+        try:
+            return gdal.SpatialReference(self.proj4text)
+        except Exception as e:
+            proj4_error = e
+
+        raise Exception(
+            "Could not get OSR SpatialReference.\n"
+            f"Error for WKT '{self.wkt}': {wkt_error}\n"
+            f"Error for PROJ.4 '{self.proj4text}': {proj4_error}"
+        )
 
     @property
     def ellipsoid(self):

+ 15 - 0
tests/gis_tests/test_spatialrefsys.py

@@ -1,5 +1,6 @@
 import re
 
+from django.contrib.gis.db.backends.base.models import SpatialRefSysMixin
 from django.db import connection
 from django.test import TestCase, skipUnlessDBFeature
 from django.utils.functional import cached_property
@@ -147,3 +148,17 @@ class SpatialRefSysTest(TestCase):
         self.assertTrue(
             self.SpatialRefSys.get_spheroid(srs.wkt).startswith("SPHEROID[")
         )
+
+    def test_srs_with_invalid_wkt_and_proj4(self):
+        class MockSpatialRefSys(SpatialRefSysMixin):
+            def __init__(self, wkt=None, proj4text=None):
+                self.wkt = wkt
+                self.proj4text = proj4text
+
+        with self.assertRaisesMessage(
+            Exception,
+            "Could not get OSR SpatialReference.\n"
+            "Error for WKT 'INVALID_WKT': Corrupt data.\n"
+            "Error for PROJ.4 '+proj=invalid': Corrupt data.",
+        ):
+            MockSpatialRefSys(wkt="INVALID_WKT", proj4text="+proj=invalid").srs