Skip to content

Commit 4e994e7

Browse files
authored
Merge pull request Unidata#1384 from RandallPittmanOrSt/disable_dataset_iteration
Disable Dataset iteration and membership operations (raise error on __iter__ and __contains__)
2 parents f7b00f8 + 38f5aaa commit 4e994e7

File tree

3 files changed

+49
-1
lines changed

3 files changed

+49
-1
lines changed

src/netCDF4/__init__.pyi

+3
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,9 @@ class Dataset:
384384
def has_bzip2_filter(self) -> bool: ...
385385
def has_szip_filter(self) -> bool: ...
386386
def __getitem__(self, elem: str) -> Any: ... # should be Group | Variable, but this causes too many problems
387+
# __iter__ and __contains__ always error because iteration and membership ops are not allowed
388+
def __iter__(self) -> NoReturn: ...
389+
def __contains__(self, key) -> NoReturn: ...
387390
def __setattr__(self, name: str, value: Any) -> None: ...
388391
def __getattr__(self, name: str) -> Any: ...
389392
def __delattr__(self, name: str): ...

src/netCDF4/_netCDF4.pyx

+12-1
Original file line numberDiff line numberDiff line change
@@ -2569,6 +2569,17 @@ strings.
25692569
else:
25702570
raise IndexError('%s not found in %s' % (lastname,group.path))
25712571

2572+
def __iter__(self):
2573+
raise TypeError(
2574+
"Dataset is not iterable. Consider iterating on Dataset.variables."
2575+
)
2576+
2577+
def __contains__(self, key):
2578+
raise TypeError(
2579+
"Dataset does not support membership operations. Perhaps try 'varname in"
2580+
" dataset.variables' or 'dimname in dataset.dimensions'."
2581+
)
2582+
25722583
def filepath(self,encoding=None):
25732584
"""**`filepath(self,encoding=None)`**
25742585
@@ -4041,7 +4052,7 @@ behavior is similar to Fortran or Matlab, but different than numpy.
40414052
If fill_value is set to `False`, then the variable is not pre-filled.
40424053
The default netCDF fill values can be found in the dictionary `netCDF4.default_fillvals`.
40434054
If not set, the default fill value will be used but no `_FillValue` attribute will be created
4044-
(this is the default behavior of the netcdf-c library). If you want to use the
4055+
(this is the default behavior of the netcdf-c library). If you want to use the
40454056
default fill value, but have the `_FillValue` attribute set, use
40464057
`fill_value='default'` (note - this only works for primitive data types). `Variable.get_fill_value`
40474058
can be used to retrieve the fill value, even if the `_FillValue` attribute is not set.

test/test_no_iter_contains.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import os
2+
import tempfile
3+
import unittest
4+
5+
import netCDF4
6+
7+
FILE_NAME = tempfile.NamedTemporaryFile(suffix='.nc', delete=False).name
8+
9+
10+
class TestNoIterNoContains(unittest.TestCase):
11+
def setUp(self) -> None:
12+
self.file = FILE_NAME
13+
with netCDF4.Dataset(self.file, "w") as dataset:
14+
# just create a simple variable
15+
dataset.createVariable("var1", int)
16+
17+
def tearDown(self) -> None:
18+
os.remove(self.file)
19+
20+
def test_no_iter(self) -> None:
21+
"""Verify that iteration is explicitly not supported"""
22+
with netCDF4.Dataset(self.file, "r") as dataset:
23+
with self.assertRaises(TypeError):
24+
for _ in dataset: # type: ignore # type checker catches that this doesn't work
25+
pass
26+
27+
def test_no_contains(self) -> None:
28+
"""Verify the membership operations are explicity not supported"""
29+
with netCDF4.Dataset(self.file, "r") as dataset:
30+
with self.assertRaises(TypeError):
31+
_ = "var1" in dataset
32+
33+
if __name__ == "__main__":
34+
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)