|
27 | 27 | ) |
28 | 28 | from django.contrib.gis.gdal.srs import SpatialReference, SRSException |
29 | 29 | from django.contrib.gis.geometry import json_regex |
| 30 | +from django.core.exceptions import SuspiciousOperation |
30 | 31 | from django.utils.encoding import force_bytes, force_str |
31 | 32 | from django.utils.functional import cached_property |
32 | 33 |
|
33 | 34 |
|
| 35 | +class DisallowedRasterLookup(SuspiciousOperation): |
| 36 | + """ |
| 37 | + Types that force GDALRaster to open in write mode (dict) or values that |
| 38 | + could be virtual filesystem paths (str) are not allowed in lookup contexts. |
| 39 | + Instead, wrap values in GDALRaster explicitly. |
| 40 | + """ |
| 41 | + |
| 42 | + |
34 | 43 | class TransformPoint(list): |
35 | 44 | indices = { |
36 | 45 | "origin": (0, 3), |
@@ -77,14 +86,10 @@ def __init__(self, ds_input, write=False): |
77 | 86 | self._write = 1 if write else 0 |
78 | 87 | Driver.ensure_registered() |
79 | 88 |
|
80 | | - # Preprocess json inputs. This converts json strings to dictionaries, |
81 | | - # which are parsed below the same way as direct dictionary inputs. |
82 | | - if isinstance(ds_input, str) and json_regex.match(ds_input): |
83 | | - ds_input = json.loads(ds_input) |
| 89 | + ds_input = self._preprocess_input(ds_input) |
84 | 90 |
|
85 | 91 | # If input is a valid file path, try setting file as source. |
86 | | - if isinstance(ds_input, (str, Path)): |
87 | | - ds_input = str(ds_input) |
| 92 | + if isinstance(ds_input, str): |
88 | 93 | if not ds_input.startswith(VSI_FILESYSTEM_PREFIX) and not os.path.exists( |
89 | 94 | ds_input |
90 | 95 | ): |
@@ -226,6 +231,35 @@ def __repr__(self): |
226 | 231 | """ |
227 | 232 | return "<Raster object at %s>" % hex(addressof(self._ptr)) |
228 | 233 |
|
| 234 | + @classmethod |
| 235 | + def _preprocess_input(cls, ds_input): |
| 236 | + """ |
| 237 | + Preprocess json and Path inputs. This converts json strings to |
| 238 | + dictionaries, which are then parsed just like direct dictionary inputs. |
| 239 | + This also stringifies Path objects. |
| 240 | + """ |
| 241 | + if isinstance(ds_input, str) and json_regex.match(ds_input): |
| 242 | + ds_input = json.loads(ds_input) |
| 243 | + if isinstance(ds_input, Path): |
| 244 | + ds_input = str(ds_input) |
| 245 | + return ds_input |
| 246 | + |
| 247 | + @classmethod |
| 248 | + def check_raster_lookup_value(cls, ds_input): |
| 249 | + """ |
| 250 | + Raise DisallowedRasterLookup for values inappropriate in lookups: |
| 251 | + - No dicts, which GDALRaster(write=False) might still write to. |
| 252 | + - No strings or Paths, which might fetch over the virtual filesystem. |
| 253 | + """ |
| 254 | + normalized = cls._preprocess_input(ds_input) |
| 255 | + if isinstance(normalized, (dict, str)): |
| 256 | + msg = ( |
| 257 | + f"Cannot use object {normalized!r} for a spatial lookup " |
| 258 | + "parameter. If this is a raster, wrap it with GDALRaster() " |
| 259 | + "before using it in a lookup to enable writing or fetching." |
| 260 | + ) |
| 261 | + raise DisallowedRasterLookup(msg) |
| 262 | + |
229 | 263 | def _flush(self): |
230 | 264 | """ |
231 | 265 | Flush all data from memory into the source file if it exists. |
|
0 commit comments