Skip to content

Commit 52ef23b

Browse files
committed
pseudocode implementation of DatasetView
1 parent 8387a1c commit 52ef23b

File tree

1 file changed

+53
-5
lines changed

1 file changed

+53
-5
lines changed

datatree/datatree.py

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,50 @@ def _check_for_name_collisions(
8282
)
8383

8484

85+
class DatasetView(Dataset):
86+
_wrapping_node: DataTree
87+
88+
__slots__ = ["_wrapping_node"]
89+
90+
@classmethod
91+
def _from_node(
92+
cls,
93+
wrapping_node,
94+
) -> DatasetView:
95+
"""Constructor, using dataset attributes from wrapping node"""
96+
97+
obj: DatasetView = object.__new__(cls)
98+
obj._wrapping_node = wrapping_node
99+
obj._variables = wrapping_node._variables
100+
obj._coord_names = wrapping_node._coord_names
101+
obj._dims = wrapping_node._dims
102+
obj._indexes = wrapping_node._indexes
103+
obj._attrs = wrapping_node._attrs
104+
obj._close = wrapping_node._close
105+
obj._encoding = wrapping_node._encoding
106+
107+
return obj
108+
109+
def __setitem__(self, key, val) -> None:
110+
raise AttributeError(
111+
"Mutation of the DatasetView is not allowed, please use __setitem__ on the wrapping DataTree node, "
112+
"or use `DataTree.to_dataset()` if you want a mutable dataset"
113+
)
114+
115+
def __getitem__(self, key) -> DataArray:
116+
# calling the `_get_item` method of DataTree allows path-like access to contents of other nodes
117+
obj = self._wrapping_node[key]
118+
if isinstance(obj, DataArray):
119+
return obj
120+
else:
121+
raise KeyError(
122+
"DatasetView is only allowed to return variables, not entire DataTree nodes"
123+
)
124+
125+
# all API that doesn't modify state in-place can just be inherited from Dataset
126+
...
127+
128+
85129
class DataTree(
86130
TreeNode,
87131
MappedDatasetMethodsMixin,
@@ -201,15 +245,19 @@ def parent(self: DataTree) -> DataTree | None:
201245

202246
@parent.setter
203247
def parent(self: DataTree, new_parent: DataTree) -> None:
204-
if new_parent and self.name is None:
248+
if new_parent is not None and self.name is None:
205249
raise ValueError("Cannot set an unnamed node as a child of another node")
206250
self._set_parent(new_parent, self.name)
207251

208252
@property
209-
def ds(self) -> Dataset:
210-
"""The data in this node, returned as a Dataset."""
211-
# TODO change this to return only an immutable view onto this node's data (see GH #80)
212-
return self.to_dataset()
253+
def ds(self) -> DatasetView:
254+
"""
255+
An immutable Dataset-like view onto the data in this node.
256+
257+
If you want a mutable Dataset containing the same data as in this node,
258+
use `.to_dataset()` instead.
259+
"""
260+
return DatasetView._from_node(self)
213261

214262
@ds.setter
215263
def ds(self, data: Union[Dataset, DataArray] = None) -> None:

0 commit comments

Comments
 (0)