diff --git a/src/netCDF4/__init__.pyi b/src/netCDF4/__init__.pyi index 67b23404c..4d88568a7 100644 --- a/src/netCDF4/__init__.pyi +++ b/src/netCDF4/__init__.pyi @@ -384,6 +384,9 @@ class Dataset: def has_bzip2_filter(self) -> bool: ... def has_szip_filter(self) -> bool: ... def __getitem__(self, elem: str) -> Any: ... # should be Group | Variable, but this causes too many problems + # __iter__ and __contains__ always error because iteration and membership ops are not allowed + def __iter__(self) -> NoReturn: ... + def __contains__(self, key) -> NoReturn: ... def __setattr__(self, name: str, value: Any) -> None: ... def __getattr__(self, name: str) -> Any: ... def __delattr__(self, name: str): ... diff --git a/src/netCDF4/_netCDF4.pyx b/src/netCDF4/_netCDF4.pyx index 7c92f09bd..7055dc599 100644 --- a/src/netCDF4/_netCDF4.pyx +++ b/src/netCDF4/_netCDF4.pyx @@ -2569,6 +2569,17 @@ strings. else: raise IndexError('%s not found in %s' % (lastname,group.path)) + def __iter__(self): + raise TypeError( + "Dataset is not iterable. Consider iterating on Dataset.variables." + ) + + def __contains__(self, key): + raise TypeError( + "Dataset does not support membership operations. Perhaps try 'varname in" + " dataset.variables' or 'dimname in dataset.dimensions'." + ) + def filepath(self,encoding=None): """**`filepath(self,encoding=None)`** @@ -4041,7 +4052,7 @@ behavior is similar to Fortran or Matlab, but different than numpy. If fill_value is set to `False`, then the variable is not pre-filled. The default netCDF fill values can be found in the dictionary `netCDF4.default_fillvals`. If not set, the default fill value will be used but no `_FillValue` attribute will be created - (this is the default behavior of the netcdf-c library). If you want to use the + (this is the default behavior of the netcdf-c library). If you want to use the default fill value, but have the `_FillValue` attribute set, use `fill_value='default'` (note - this only works for primitive data types). `Variable.get_fill_value` can be used to retrieve the fill value, even if the `_FillValue` attribute is not set. diff --git a/test/test_no_iter_contains.py b/test/test_no_iter_contains.py new file mode 100644 index 000000000..793f0f7da --- /dev/null +++ b/test/test_no_iter_contains.py @@ -0,0 +1,34 @@ +import os +import tempfile +import unittest + +import netCDF4 + +FILE_NAME = tempfile.NamedTemporaryFile(suffix='.nc', delete=False).name + + +class TestNoIterNoContains(unittest.TestCase): + def setUp(self) -> None: + self.file = FILE_NAME + with netCDF4.Dataset(self.file, "w") as dataset: + # just create a simple variable + dataset.createVariable("var1", int) + + def tearDown(self) -> None: + os.remove(self.file) + + def test_no_iter(self) -> None: + """Verify that iteration is explicitly not supported""" + with netCDF4.Dataset(self.file, "r") as dataset: + with self.assertRaises(TypeError): + for _ in dataset: # type: ignore # type checker catches that this doesn't work + pass + + def test_no_contains(self) -> None: + """Verify the membership operations are explicity not supported""" + with netCDF4.Dataset(self.file, "r") as dataset: + with self.assertRaises(TypeError): + _ = "var1" in dataset + +if __name__ == "__main__": + unittest.main(verbosity=2)