@@ -230,7 +230,7 @@ def test_coordinates_quantified():
230
230
231
231
232
232
def test_cell_measures ():
233
- ds = airds .copy (deep = True )
233
+ ds = airds .copy (deep = False )
234
234
ds ["foo" ] = xr .DataArray (ds ["cell_area" ], attrs = dict (standard_name = "foo_std_name" ))
235
235
ds ["air" ].attrs ["cell_measures" ] += " foo_measure: foo"
236
236
assert ("foo_std_name" in ds .cf ["air_temperature" ].cf ) and ("foo_measure" in ds .cf )
@@ -307,7 +307,7 @@ def test_getitem_standard_name():
307
307
expected = airds ["lat" ]
308
308
assert_identical (actual , expected )
309
309
310
- ds = airds .copy (deep = True )
310
+ ds = airds .copy (deep = False )
311
311
ds ["air2" ] = ds .air
312
312
with pytest .raises (KeyError ):
313
313
ds .cf ["air_temperature" ]
@@ -340,19 +340,18 @@ def test_getitem_ancillary_variables():
340
340
341
341
342
342
def test_rename_like ():
343
- original = popds .copy (deep = True )
344
-
345
343
# it'll match for axis: X (lon, nlon) and coordinate="longitude" (lon, TLONG)
346
344
# so delete the axis attributes
347
- newair = airds .copy (deep = True )
345
+ original = popds
346
+ newair = airds .copy (deep = False )
348
347
del newair .lon .attrs ["axis" ]
349
348
del newair .lat .attrs ["axis" ]
350
349
351
350
renamed = popds .cf ["TEMP" ].cf .rename_like (newair )
351
+ assert original .TEMP .attrs ["coordinates" ] == "TLONG TLAT"
352
352
for k in ["TLONG" , "TLAT" ]:
353
- assert k not in renamed .coords
354
353
assert k in original .coords
355
- assert original . TEMP . attrs [ "coordinates" ] == "TLONG TLAT"
354
+ assert k not in renamed . coords
356
355
357
356
assert "lon" in renamed .coords
358
357
assert "lat" in renamed .coords
@@ -479,7 +478,7 @@ def test_pos_args_methods():
479
478
480
479
def test_preserve_unused_keys ():
481
480
482
- ds = airds .copy (deep = True )
481
+ ds = airds .copy (deep = False )
483
482
ds .time .attrs .clear ()
484
483
actual = ds .cf .sel (X = 260 , Y = 40 , time = airds .time [:2 ], method = "nearest" )
485
484
expected = ds .sel (lon = 260 , lat = 40 , time = airds .time [:2 ], method = "nearest" )
@@ -528,7 +527,7 @@ def test_args_methods(obj):
528
527
529
528
def test_dataarray_getitem ():
530
529
531
- air = airds .air .copy ()
530
+ air = airds .air .copy (deep = False )
532
531
air .name = None
533
532
534
533
assert_identical (air .cf ["longitude" ], air ["lon" ])
@@ -543,7 +542,7 @@ def test_dataarray_getitem():
543
542
544
543
def test_dataarray_plot ():
545
544
546
- obj = airds .air .copy (deep = True )
545
+ obj = airds .air .copy (deep = False )
547
546
548
547
rv = obj .isel (time = 1 ).transpose ("lon" , "lat" ).cf .plot ()
549
548
assert isinstance (rv , mpl .collections .QuadMesh )
@@ -636,14 +635,14 @@ def test_getitem(obj, key, expected_key):
636
635
def test_getitem_errors (obj ):
637
636
with pytest .raises (KeyError ):
638
637
obj .cf ["XX" ]
639
- obj2 = obj .copy (deep = True )
638
+ obj2 = obj .copy (deep = False )
640
639
obj2 .lon .attrs = {}
641
640
with pytest .raises (KeyError ):
642
641
obj2 .cf ["X" ]
643
642
644
643
645
644
def test_bad_cell_measures_attribute ():
646
- air2 = airds .copy (deep = True )
645
+ air2 = airds .copy (deep = False )
647
646
air2 .air .attrs ["cell_measures" ] = "--OPT"
648
647
with pytest .warns (UserWarning ):
649
648
air2 .cf ["air" ]
@@ -736,20 +735,21 @@ def test_plot_xincrease_yincrease():
736
735
737
736
@pytest .mark .parametrize ("dims" , ["time2" , "lat" , "time" , ["lat" , "lon" ]])
738
737
def test_add_bounds (dims ):
739
- obj = airds .copy (deep = True )
738
+ ds = airds
739
+ original = ds .copy (deep = True )
740
740
741
741
expected = {}
742
742
expected ["lat" ] = xr .concat (
743
743
[
744
- obj .lat .copy (data = np .arange (76.25 , 16.0 , - 2.5 )),
745
- obj .lat .copy (data = np .arange (73.75 , 13.6 , - 2.5 )),
744
+ ds .lat .copy (data = np .arange (76.25 , 16.0 , - 2.5 )),
745
+ ds .lat .copy (data = np .arange (73.75 , 13.6 , - 2.5 )),
746
746
],
747
747
dim = "bounds" ,
748
748
)
749
749
expected ["lon" ] = xr .concat (
750
750
[
751
- obj .lon .copy (data = np .arange (198.75 , 325 - 1.25 , 2.5 )),
752
- obj .lon .copy (data = np .arange (201.25 , 325 + 1.25 , 2.5 )),
751
+ ds .lon .copy (data = np .arange (198.75 , 325 - 1.25 , 2.5 )),
752
+ ds .lon .copy (data = np .arange (201.25 , 325 + 1.25 , 2.5 )),
753
753
],
754
754
dim = "bounds" ,
755
755
)
@@ -759,8 +759,8 @@ def test_add_bounds(dims):
759
759
dtb2 = pd .Timedelta ("3h" )
760
760
expected ["time" ] = xr .concat (
761
761
[
762
- obj .time .copy (data = pd .date_range (start = t0 - dtb2 , end = t1 - dtb2 , freq = dt )),
763
- obj .time .copy (data = pd .date_range (start = t0 + dtb2 , end = t1 + dtb2 , freq = dt )),
762
+ ds .time .copy (data = pd .date_range (start = t0 - dtb2 , end = t1 - dtb2 , freq = dt )),
763
+ ds .time .copy (data = pd .date_range (start = t0 + dtb2 , end = t1 + dtb2 , freq = dt )),
764
764
],
765
765
dim = "bounds" ,
766
766
)
@@ -769,8 +769,9 @@ def test_add_bounds(dims):
769
769
expected ["lon" ].attrs .clear ()
770
770
expected ["time" ].attrs .clear ()
771
771
772
- obj .coords ["time2" ] = obj .time
773
- added = obj .cf .add_bounds (dims )
772
+ added = ds .copy (deep = False )
773
+ added .coords ["time2" ] = ds .time
774
+ added = added .cf .add_bounds (dims )
774
775
if isinstance (dims , str ):
775
776
dims = (dims ,)
776
777
@@ -780,6 +781,8 @@ def test_add_bounds(dims):
780
781
assert added [dim ].attrs ["bounds" ] == name
781
782
assert_allclose (added [name ].reset_coords (drop = True ), expected [dim ])
782
783
784
+ _check_unchanged (original , ds )
785
+
783
786
784
787
def test_add_bounds_multiple ():
785
788
# Test multiple dimensions
@@ -810,7 +813,7 @@ def test_add_bounds_nd_variable():
810
813
811
814
812
815
def test_bounds ():
813
- ds = airds .copy (deep = True ).cf .add_bounds ("lat" )
816
+ ds = airds .copy (deep = False ).cf .add_bounds ("lat" )
814
817
815
818
actual = ds .cf .bounds
816
819
expected = {"Y" : ["lat_bounds" ], "lat" : ["lat_bounds" ], "latitude" : ["lat_bounds" ]}
@@ -858,32 +861,36 @@ def test_bounds():
858
861
859
862
def test_bounds_to_vertices ():
860
863
# All available
861
- ds = airds .cf .add_bounds (["lon" , "lat" ])
862
- dsc = ds .cf .bounds_to_vertices ()
863
- assert "lon_vertices" in dsc
864
- assert "lat_vertices" in dsc
864
+ ds = airds
865
+ original = ds .copy (deep = True )
866
+ dsb = ds .cf .add_bounds (["lon" , "lat" ])
867
+ dsv = dsb .cf .bounds_to_vertices ()
868
+ assert "lon_vertices" in dsv
869
+ assert "lat_vertices" in dsv
865
870
866
871
# Giving key
867
- dsc = ds .cf .bounds_to_vertices ("longitude" )
868
- assert "lon_vertices" in dsc
869
- assert "lat_vertices" not in dsc
872
+ dsv = dsb .cf .bounds_to_vertices ("longitude" )
873
+ assert "lon_vertices" in dsv
874
+ assert "lat_vertices" not in dsv
870
875
871
- dsc = ds .cf .bounds_to_vertices (["longitude" , "latitude" ])
872
- assert "lon_vertices" in dsc
873
- assert "lat_vertices" in dsc
876
+ dsv = dsb .cf .bounds_to_vertices (["longitude" , "latitude" ])
877
+ assert "lon_vertices" in dsv
878
+ assert "lat_vertices" in dsv
874
879
875
880
# Error
876
881
with pytest .raises (ValueError ):
877
- dsc = ds .cf .bounds_to_vertices ("T" )
882
+ dsv = dsb .cf .bounds_to_vertices ("T" )
878
883
879
884
# Words on datetime arrays to
880
- ds = airds .cf .add_bounds ("time" )
881
- dsc = ds .cf .bounds_to_vertices ()
882
- assert "time_bounds" in dsc
885
+ dsb = dsb .cf .add_bounds ("time" )
886
+ dsv = dsb .cf .bounds_to_vertices ()
887
+ assert "time_bounds" in dsv
888
+
889
+ _check_unchanged (original , ds )
883
890
884
891
885
892
def test_get_bounds_dim_name ():
886
- ds = airds .copy ( deep = True ). cf .add_bounds ("lat" )
893
+ ds = airds .cf .add_bounds ("lat" )
887
894
assert ds .cf .get_bounds_dim_name ("latitude" ) == "bounds"
888
895
assert ds .cf .get_bounds_dim_name ("lat" ) == "bounds"
889
896
@@ -921,6 +928,26 @@ def _make_names(prefixes):
921
928
]
922
929
923
930
931
+ def _check_unchanged (old , new ):
932
+ # Check data array attributes or global dataset attributes
933
+ assert type (old ) == type (new )
934
+ assert old .attrs .keys () == new .attrs .keys () # set comparison
935
+ for att , old_val in old .attrs .items ():
936
+ assert id (old_val ) == id (new .attrs [att ])
937
+
938
+ # Check coordinate attributes and data variable attributes
939
+ dicts = [(old .coords , new .coords )]
940
+ if isinstance (old , xr .Dataset ):
941
+ dicts .append ((old .data_vars , new .data_vars ))
942
+ for old_dict , new_dict in dicts :
943
+ assert old_dict .keys () == new_dict .keys () # set comparison
944
+ for key , old_obj in old_dict .items ():
945
+ new_obj = new_dict [key ]
946
+ assert old_obj .attrs .keys () == new_obj .attrs .keys () # set comparison
947
+ for att , old_val in old_obj .attrs .items ():
948
+ assert id (old_val ) == id (new_obj .attrs [att ]) # numpy-safe comparison
949
+
950
+
924
951
_TIME_NAMES = ["t" ] + _make_names (
925
952
[
926
953
"time" ,
@@ -1015,7 +1042,7 @@ def test_attributes():
1015
1042
with pytest .raises (AttributeError ):
1016
1043
airds .da .cf .chunks
1017
1044
1018
- airds2 = airds .copy (deep = True )
1045
+ airds2 = airds .copy (deep = False )
1019
1046
airds2 .lon .attrs = {}
1020
1047
actual = airds2 .cf .sizes
1021
1048
expected = {"lon" : 50 , "Y" : 25 , "T" : 4 , "latitude" : 25 , "time" : 4 }
@@ -1046,7 +1073,7 @@ def test_attributes():
1046
1073
assert_identical (ds1 .cf .data_vars ["T" ], ds1 ["T" ])
1047
1074
1048
1075
# multiple latitudes but only one latitude data_var
1049
- ds = popds .copy (deep = True )
1076
+ ds = popds .copy (deep = False )
1050
1077
for var in ["ULAT" , "TLAT" ]:
1051
1078
ds [var ].attrs ["standard_name" ] = "latitude"
1052
1079
ds = ds .reset_coords ("ULAT" )
@@ -1068,7 +1095,7 @@ def test_Z_vs_vertical_ROMS():
1068
1095
romsds .z_rho_dummy .reset_coords (drop = True ), romsds .temp .cf ["vertical" ]
1069
1096
)
1070
1097
1071
- romsds = romsds .copy (deep = True )
1098
+ romsds = romsds .copy (deep = False )
1072
1099
1073
1100
romsds .temp .attrs .clear ()
1074
1101
# look in encoding
@@ -1109,12 +1136,12 @@ def test_param_vcoord_ocean_s_coord():
1109
1136
romsds .cf .decode_vertical_coords (outnames = {"s_rho" : "ZZZ_rho" })
1110
1137
assert "ZZZ_rho" in romsds .coords
1111
1138
1112
- copy = romsds .copy (deep = True )
1139
+ copy = romsds .copy (deep = False )
1113
1140
del copy ["zeta" ]
1114
1141
with pytest .raises (KeyError ):
1115
1142
copy .cf .decode_vertical_coords (outnames = {"s_rho" : "z_rho" })
1116
1143
1117
- copy = romsds .copy (deep = True )
1144
+ copy = romsds .copy (deep = False )
1118
1145
copy .s_rho .attrs ["formula_terms" ] = "s: s_rho C: Cs_r depth: h depth_c: hc"
1119
1146
with pytest .raises (KeyError ):
1120
1147
copy .cf .decode_vertical_coords (outnames = {"s_rho" : "z_rho" })
@@ -1125,7 +1152,7 @@ def test_param_vcoord_ocean_sigma_coordinate():
1125
1152
pomds .cf .decode_vertical_coords (outnames = {"sigma" : "z" })
1126
1153
assert_allclose (pomds .z .reset_coords (drop = True ), expected .reset_coords (drop = True ))
1127
1154
1128
- copy = pomds .copy (deep = True )
1155
+ copy = pomds .copy (deep = False )
1129
1156
del copy ["zeta" ]
1130
1157
with pytest .raises (AssertionError ):
1131
1158
copy .cf .decode_vertical_coords ()
@@ -1146,7 +1173,7 @@ def test_formula_terms():
1146
1173
assert romsds ["temp" ].cf .formula_terms == srhoterms
1147
1174
assert romsds ["s_rho" ].cf .formula_terms == srhoterms
1148
1175
1149
- s_rho = romsds ["s_rho" ].copy (deep = True )
1176
+ s_rho = romsds ["s_rho" ].copy (deep = False )
1150
1177
del s_rho .attrs ["standard_name" ]
1151
1178
del s_rho .s_rho .attrs ["standard_name" ] # TODO: xarray bug
1152
1179
assert s_rho .cf .formula_terms == srhoterms
@@ -1535,6 +1562,7 @@ def test_datetime_like(reshape):
1535
1562
def test_add_canonical_attributes (override , skip , verbose , capsys ):
1536
1563
1537
1564
ds = airds
1565
+ original = ds .copy (deep = True )
1538
1566
cf_ds = ds .cf .add_canonical_attributes (
1539
1567
override = override , skip = skip , verbose = verbose
1540
1568
)
@@ -1581,6 +1609,8 @@ def test_add_canonical_attributes(override, skip, verbose, capsys):
1581
1609
cf_da .attrs .pop ("history" )
1582
1610
assert_identical (cf_da , cf_ds ["air" ])
1583
1611
1612
+ _check_unchanged (original , ds )
1613
+
1584
1614
1585
1615
@pytest .mark .parametrize ("op" , ["ge" , "gt" , "eq" , "ne" , "le" , "lt" ])
1586
1616
def test_flag_features (op ):
@@ -1617,20 +1647,20 @@ def test_flag_errors():
1617
1647
def test_missing_variables ():
1618
1648
1619
1649
# Bounds
1620
- ds = mollwds .copy (deep = True )
1650
+ ds = mollwds .copy (deep = False )
1621
1651
ds = ds .drop_vars ("lon_bounds" )
1622
1652
assert ds .cf .bounds == {"lat" : ["lat_bounds" ], "latitude" : ["lat_bounds" ]}
1623
1653
1624
1654
with pytest .raises (KeyError , match = r"No results found for 'longitude'." ):
1625
1655
ds .cf .get_bounds ("longitude" )
1626
1656
1627
1657
# Cell measures
1628
- ds = airds .copy (deep = True )
1658
+ ds = airds .copy (deep = False )
1629
1659
ds = ds .drop_vars ("cell_area" )
1630
1660
assert ds .cf .cell_measures == {}
1631
1661
1632
1662
# Formula terms
1633
- ds = vert .copy (deep = True )
1663
+ ds = vert .copy (deep = False )
1634
1664
ds = ds .drop_vars ("ap" )
1635
1665
assert ds .cf .formula_terms == {"lev" : {"b" : "b" , "ps" : "ps" }}
1636
1666
0 commit comments