1
1
from __future__ import annotations
2
2
3
+ import warnings
3
4
from contextlib import contextmanager
4
5
from typing import TYPE_CHECKING , Any , Hashable , Iterator , Mapping , Sequence , cast
5
6
6
7
import numpy as np
7
8
import pandas as pd
8
9
9
10
from . import formatting
10
- from .indexes import Index , Indexes , assert_no_index_corrupted
11
+ from .indexes import Index , Indexes , PandasMultiIndex , assert_no_index_corrupted
11
12
from .merge import merge_coordinates_without_align , merge_coords
12
13
from .utils import Frozen , ReprObject
13
14
from .variable import Variable , calculate_dimensions
@@ -57,6 +58,9 @@ def variables(self):
57
58
def _update_coords (self , coords , indexes ):
58
59
raise NotImplementedError ()
59
60
61
+ def _maybe_drop_multiindex_coords (self , coords ):
62
+ raise NotImplementedError ()
63
+
60
64
def __iter__ (self ) -> Iterator [Hashable ]:
61
65
# needs to be in the same order as the dataset variables
62
66
for k in self .variables :
@@ -154,6 +158,7 @@ def to_index(self, ordered_dims: Sequence[Hashable] = None) -> pd.Index:
154
158
155
159
def update (self , other : Mapping [Any , Any ]) -> None :
156
160
other_vars = getattr (other , "variables" , other )
161
+ self ._maybe_drop_multiindex_coords (set (other_vars ))
157
162
coords , indexes = merge_coords (
158
163
[self .variables , other_vars ], priority_arg = 1 , indexes = self .xindexes
159
164
)
@@ -304,6 +309,15 @@ def _update_coords(
304
309
original_indexes .update (indexes )
305
310
self ._data ._indexes = original_indexes
306
311
312
+ def _maybe_drop_multiindex_coords (self , coords : set [Hashable ]) -> None :
313
+ """Drops variables in coords, and any associated variables as well."""
314
+ assert self ._data .xindexes is not None
315
+ variables , indexes = drop_coords (
316
+ coords , self ._data ._variables , self ._data .xindexes
317
+ )
318
+ self ._data ._variables = variables
319
+ self ._data ._indexes = indexes
320
+
307
321
def __delitem__ (self , key : Hashable ) -> None :
308
322
if key in self :
309
323
del self ._data [key ]
@@ -372,6 +386,14 @@ def _update_coords(
372
386
original_indexes .update (indexes )
373
387
self ._data ._indexes = original_indexes
374
388
389
+ def _maybe_drop_multiindex_coords (self , coords : set [Hashable ]) -> None :
390
+ """Drops variables in coords, and any associated variables as well."""
391
+ variables , indexes = drop_coords (
392
+ coords , self ._data ._coords , self ._data .xindexes
393
+ )
394
+ self ._data ._coords = variables
395
+ self ._data ._indexes = indexes
396
+
375
397
@property
376
398
def variables (self ):
377
399
return Frozen (self ._data ._coords )
@@ -397,6 +419,37 @@ def _ipython_key_completions_(self):
397
419
return self ._data ._ipython_key_completions_ ()
398
420
399
421
422
+ def drop_coords (
423
+ coords_to_drop : set [Hashable ], variables , indexes : Indexes
424
+ ) -> tuple [dict , dict ]:
425
+ """Drop index variables associated with variables in coords_to_drop."""
426
+ # Only warn when we're dropping the dimension with the multi-indexed coordinate
427
+ # If asked to drop a subset of the levels in a multi-index, we raise an error
428
+ # later but skip the warning here.
429
+ new_variables = dict (variables .copy ())
430
+ new_indexes = dict (indexes .copy ())
431
+ for key in coords_to_drop & set (indexes ):
432
+ maybe_midx = indexes [key ]
433
+ idx_coord_names = set (indexes .get_all_coords (key ))
434
+ if (
435
+ isinstance (maybe_midx , PandasMultiIndex )
436
+ and key == maybe_midx .dim
437
+ and (idx_coord_names - coords_to_drop )
438
+ ):
439
+ warnings .warn (
440
+ f"Updating MultiIndexed coordinate { key !r} would corrupt indices for "
441
+ f"other variables: { list (maybe_midx .index .names )!r} . "
442
+ f"This will raise an error in the future. Use `.drop_vars({ idx_coord_names !r} )` before "
443
+ "assigning new coordinate values." ,
444
+ DeprecationWarning ,
445
+ stacklevel = 4 ,
446
+ )
447
+ for k in idx_coord_names :
448
+ del new_variables [k ]
449
+ del new_indexes [k ]
450
+ return new_variables , new_indexes
451
+
452
+
400
453
def assert_coordinate_consistent (
401
454
obj : DataArray | Dataset , coords : Mapping [Any , Variable ]
402
455
) -> None :
0 commit comments