-
Notifications
You must be signed in to change notification settings - Fork 41
Replace .ds with immutable DatasetView #99
Changes from all commits
22004e4
8f0518c
3a4f874
8c6a68a
b503b06
1efd7f2
438d73a
904eae3
2ca1c1a
547d1ac
6f78fcd
715ce49
edd2f67
b2c51aa
a20e85f
8387a1c
52ef23b
4a5317e
09a22e4
b60a4af
3077bf7
5368f8b
cae0a4e
72af61c
ec11072
a2381e1
7f9a9ea
d22c2f8
c715387
4dd3675
7c2c4f8
66b7adf
b61e940
0e9b384
d56f89b
07f6d4d
322f1e9
15b89fc
44254d7
cf5051c
9c3331a
2b0226d
0be76df
e30bba0
4505514
bffeed8
cd575d2
47f8319
c2c6aa6
46de4d3
69bf9ff
993905d
3bf6d59
c1cc571
19cc897
c0a5ae7
70fb9ed
68a9faf
6a7244b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
import pytest | ||
import xarray as xr | ||
import xarray.testing as xrt | ||
from xarray.tests import source_ndarray | ||
from xarray.tests import create_test_data, source_ndarray | ||
|
||
import datatree.testing as dtt | ||
from datatree import DataTree | ||
|
@@ -16,7 +16,7 @@ def test_empty(self): | |
assert dt.name == "root" | ||
assert dt.parent is None | ||
assert dt.children == {} | ||
xrt.assert_identical(dt.ds, xr.Dataset()) | ||
xrt.assert_identical(dt.to_dataset(), xr.Dataset()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure whether it's better to use If it weren't for the explicit type comparisons in |
||
|
||
def test_unnamed(self): | ||
dt = DataTree() | ||
|
@@ -66,7 +66,7 @@ class TestStoreDatasets: | |
def test_create_with_data(self): | ||
dat = xr.Dataset({"a": 0}) | ||
john = DataTree(name="john", data=dat) | ||
xrt.assert_identical(john.ds, dat) | ||
xrt.assert_identical(john.to_dataset(), dat) | ||
|
||
with pytest.raises(TypeError): | ||
DataTree(name="mary", parent=john, data="junk") # noqa | ||
|
@@ -75,7 +75,7 @@ def test_set_data(self): | |
john = DataTree(name="john") | ||
dat = xr.Dataset({"a": 0}) | ||
john.ds = dat | ||
xrt.assert_identical(john.ds, dat) | ||
xrt.assert_identical(john.to_dataset(), dat) | ||
with pytest.raises(TypeError): | ||
john.ds = "junk" | ||
|
||
|
@@ -100,16 +100,9 @@ def test_assign_when_already_child_with_variables_name(self): | |
dt.ds = xr.Dataset({"a": 0}) | ||
|
||
dt.ds = xr.Dataset() | ||
new_ds = dt.to_dataset().assign(a=xr.DataArray(0)) | ||
with pytest.raises(KeyError, match="names would collide"): | ||
dt.ds = dt.ds.assign(a=xr.DataArray(0)) | ||
|
||
@pytest.mark.xfail | ||
def test_update_when_already_child_with_variables_name(self): | ||
# See issue #38 | ||
dt = DataTree(name="root", data=None) | ||
DataTree(name="a", data=None, parent=dt) | ||
with pytest.raises(KeyError, match="names would collide"): | ||
dt.ds["a"] = xr.DataArray(0) | ||
dt.ds = new_ds | ||
|
||
|
||
class TestGet: | ||
|
@@ -275,13 +268,13 @@ def test_setitem_new_empty_node(self): | |
john["mary"] = DataTree() | ||
mary = john["mary"] | ||
assert isinstance(mary, DataTree) | ||
xrt.assert_identical(mary.ds, xr.Dataset()) | ||
xrt.assert_identical(mary.to_dataset(), xr.Dataset()) | ||
|
||
def test_setitem_overwrite_data_in_node_with_none(self): | ||
john = DataTree(name="john") | ||
mary = DataTree(name="mary", parent=john, data=xr.Dataset()) | ||
john["mary"] = DataTree() | ||
xrt.assert_identical(mary.ds, xr.Dataset()) | ||
xrt.assert_identical(mary.to_dataset(), xr.Dataset()) | ||
|
||
john.ds = xr.Dataset() | ||
with pytest.raises(ValueError, match="has no name"): | ||
|
@@ -292,21 +285,21 @@ def test_setitem_dataset_on_this_node(self): | |
data = xr.Dataset({"temp": [0, 50]}) | ||
results = DataTree(name="results") | ||
results["."] = data | ||
xrt.assert_identical(results.ds, data) | ||
xrt.assert_identical(results.to_dataset(), data) | ||
|
||
@pytest.mark.xfail(reason="assigning Datasets doesn't yet create new nodes") | ||
def test_setitem_dataset_as_new_node(self): | ||
data = xr.Dataset({"temp": [0, 50]}) | ||
folder1 = DataTree(name="folder1") | ||
folder1["results"] = data | ||
xrt.assert_identical(folder1["results"].ds, data) | ||
xrt.assert_identical(folder1["results"].to_dataset(), data) | ||
|
||
@pytest.mark.xfail(reason="assigning Datasets doesn't yet create new nodes") | ||
def test_setitem_dataset_as_new_node_requiring_intermediate_nodes(self): | ||
data = xr.Dataset({"temp": [0, 50]}) | ||
folder1 = DataTree(name="folder1") | ||
folder1["results/highres"] = data | ||
xrt.assert_identical(folder1["results/highres"].ds, data) | ||
xrt.assert_identical(folder1["results/highres"].to_dataset(), data) | ||
|
||
def test_setitem_named_dataarray(self): | ||
da = xr.DataArray(name="temp", data=[0, 50]) | ||
|
@@ -341,7 +334,7 @@ def test_setitem_dataarray_replace_existing_node(self): | |
p = xr.DataArray(data=[2, 3]) | ||
results["pressure"] = p | ||
expected = t.assign(pressure=p) | ||
xrt.assert_identical(results.ds, expected) | ||
xrt.assert_identical(results.to_dataset(), expected) | ||
|
||
|
||
class TestDictionaryInterface: | ||
|
@@ -355,16 +348,16 @@ def test_data_in_root(self): | |
assert dt.name is None | ||
assert dt.parent is None | ||
assert dt.children == {} | ||
xrt.assert_identical(dt.ds, dat) | ||
xrt.assert_identical(dt.to_dataset(), dat) | ||
|
||
def test_one_layer(self): | ||
dat1, dat2 = xr.Dataset({"a": 1}), xr.Dataset({"b": 2}) | ||
dt = DataTree.from_dict({"run1": dat1, "run2": dat2}) | ||
xrt.assert_identical(dt.ds, xr.Dataset()) | ||
xrt.assert_identical(dt.to_dataset(), xr.Dataset()) | ||
assert dt.name is None | ||
xrt.assert_identical(dt["run1"].ds, dat1) | ||
xrt.assert_identical(dt["run1"].to_dataset(), dat1) | ||
assert dt["run1"].children == {} | ||
xrt.assert_identical(dt["run2"].ds, dat2) | ||
xrt.assert_identical(dt["run2"].to_dataset(), dat2) | ||
assert dt["run2"].children == {} | ||
|
||
def test_two_layers(self): | ||
|
@@ -373,13 +366,13 @@ def test_two_layers(self): | |
assert "highres" in dt.children | ||
assert "lowres" in dt.children | ||
highres_run = dt["highres/run"] | ||
xrt.assert_identical(highres_run.ds, dat1) | ||
xrt.assert_identical(highres_run.to_dataset(), dat1) | ||
|
||
def test_nones(self): | ||
dt = DataTree.from_dict({"d": None, "d/e": None}) | ||
assert [node.name for node in dt.subtree] == [None, "d", "e"] | ||
assert [node.path for node in dt.subtree] == ["/", "/d", "/d/e"] | ||
xrt.assert_identical(dt["d/e"].ds, xr.Dataset()) | ||
xrt.assert_identical(dt["d/e"].to_dataset(), xr.Dataset()) | ||
|
||
def test_full(self, simple_datatree): | ||
dt = simple_datatree | ||
|
@@ -409,8 +402,44 @@ def test_roundtrip_unnamed_root(self, simple_datatree): | |
assert roundtrip.equals(dt) | ||
|
||
|
||
class TestBrowsing: | ||
... | ||
class TestDatasetView: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This set of tests is insufficient in the sense that our subclass could have broken literally any method defined |
||
def test_view_contents(self): | ||
ds = create_test_data() | ||
dt = DataTree(data=ds) | ||
assert ds.identical( | ||
dt.ds | ||
) # this only works because Dataset.identical doesn't check types | ||
Comment on lines
+409
to
+411
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These asserts do pass because for some reason |
||
assert isinstance(dt.ds, xr.Dataset) | ||
|
||
def test_immutability(self): | ||
# See issue #38 | ||
dt = DataTree(name="root", data=None) | ||
DataTree(name="a", data=None, parent=dt) | ||
|
||
with pytest.raises( | ||
AttributeError, match="Mutation of the DatasetView is not allowed" | ||
): | ||
dt.ds["a"] = xr.DataArray(0) | ||
|
||
with pytest.raises( | ||
AttributeError, match="Mutation of the DatasetView is not allowed" | ||
): | ||
dt.ds.update({"a": 0}) | ||
|
||
# TODO are there any other ways you can normally modify state (in-place)? | ||
# (not attribute-like assignment because that doesn't work on Dataset anyway) | ||
|
||
def test_methods(self): | ||
ds = create_test_data() | ||
dt = DataTree(data=ds) | ||
assert ds.mean().identical(dt.ds.mean()) | ||
assert type(dt.ds.mean()) == xr.Dataset | ||
|
||
def test_arithmetic(self, create_test_datatree): | ||
dt = create_test_datatree() | ||
expected = create_test_datatree(modify=lambda ds: 10.0 * ds)["set1"] | ||
result = 10.0 * dt["set1"].ds | ||
assert result.identical(expected) | ||
|
||
|
||
class TestRestructuring: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to be changed by #102 to allow out-of-node access