diff --git a/CHANGES.txt b/CHANGES.txt index cf785e5e0..6216af653 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,9 @@ Changes 1.0.23 (TBD) ------------ +- Attempts to set attributes of datasets opened in "r" mode now raise a custom + DatasetAttributeError. This exception derives from both RasterioError and + NotImplementedError, which maintains backwards compatibility (#1676). - Block sizes are no longer guarded when creating untiled datasets (#1689). - CRS objects are now hashable and equivalent CRS objects have the same hash value (#1684). diff --git a/rasterio/_base.pyx b/rasterio/_base.pyx index 91d778a11..2a828386e 100644 --- a/rasterio/_base.pyx +++ b/rasterio/_base.pyx @@ -26,6 +26,7 @@ from rasterio.enums import ( ColorInterp, Compression, Interleaving, MaskFlags, PhotometricInterp) from rasterio.env import Env, env_ctx_if_needed from rasterio.errors import ( + DatasetAttributeError, RasterioIOError, CRSError, DriverRegistrationError, NotGeoreferencedWarning, RasterBlockError, BandOverviewError) from rasterio.profiles import Profile @@ -450,7 +451,7 @@ cdef class DatasetBase(object): return self.get_nodatavals() def _set_nodatavals(self, value): - raise NotImplementedError + raise DatasetAttributeError("read-only attribute") property nodata: """The dataset's single nodata value @@ -513,7 +514,7 @@ cdef class DatasetBase(object): for x in self._mask_flags()) def _set_crs(self, value): - raise NotImplementedError + raise DatasetAttributeError("read-only attribute") property crs: """The dataset's coordinate reference system @@ -533,16 +534,16 @@ cdef class DatasetBase(object): self._set_crs(value) def _set_all_descriptions(self, value): - raise NotImplementedError + raise DatasetAttributeError("read-only attribute") def _set_all_scales(self, value): - raise NotImplementedError + raise DatasetAttributeError("read-only attribute") def _set_all_offsets(self, value): - raise NotImplementedError + raise DatasetAttributeError("read-only attribute") def _set_all_units(self, value): - raise NotImplementedError + raise DatasetAttributeError("read-only attribute") property descriptions: """Descriptions for each dataset band @@ -563,7 +564,7 @@ cdef class DatasetBase(object): self._set_all_descriptions(value) def write_transform(self, value): - raise NotImplementedError + raise DatasetAttributeError("read-only attribute") property transform: """The dataset's georeferencing transformation matrix @@ -1184,7 +1185,7 @@ cdef class DatasetBase(object): for i in range(num_gcps)], crs) def _set_gcps(self, values): - raise NotImplementedError + raise DatasetAttributeError("read-only attribute") property gcps: """ground control points and their coordinate reference system. diff --git a/rasterio/errors.py b/rasterio/errors.py index 97f63303f..cf91f8456 100644 --- a/rasterio/errors.py +++ b/rasterio/errors.py @@ -102,3 +102,7 @@ class UnsupportedOperation(RasterioError): class OverviewCreationError(RasterioError): """Raised when creation of an overview fails""" + + +class DatasetAttributeError(RasterioError, NotImplementedError): + """Raised when dataset attributes are misused""" diff --git a/tests/test_dataset.py b/tests/test_dataset.py index 2b106caf5..0086b7e99 100644 --- a/tests/test_dataset.py +++ b/tests/test_dataset.py @@ -11,7 +11,7 @@ import rasterio from rasterio.enums import Compression -from rasterio.errors import RasterioIOError +from rasterio.errors import RasterioIOError, DatasetAttributeError from rasterio.transform import Affine @@ -65,3 +65,16 @@ def test_tiled_dataset_blocksize_guard(tmp_path): rasterio.open( tmp_file, "w", driver="GTiff", count=1, height=13, width=13, dtype="uint8", crs="epsg:3857", transform=Affine.identity(), tiled=True, blockxsize=256, blockysize=256) + +def test_dataset_readonly_attributes(path_rgb_byte_tif): + """Attempts to set read-only attributes fail with DatasetAttributeError""" + with pytest.raises(DatasetAttributeError): + with rasterio.open(path_rgb_byte_tif) as dataset: + dataset.crs = "foo" + + +def test_dataset_readonly_attributes(path_rgb_byte_tif): + """Attempts to set read-only attributes still fail with NotImplementedError""" + with pytest.raises(NotImplementedError): + with rasterio.open(path_rgb_byte_tif) as dataset: + dataset.crs = "foo"