11from __future__ import annotations
22
3+ import warnings
34from contextlib import contextmanager
45from typing import TYPE_CHECKING , Any , Hashable , Iterator , Mapping , Sequence , cast
56
67import numpy as np
78import pandas as pd
89
910from . import formatting
10- from .indexes import Index , Indexes , assert_no_index_corrupted
11+ from .indexes import Index , Indexes , PandasMultiIndex , assert_no_index_corrupted
1112from .merge import merge_coordinates_without_align , merge_coords
1213from .utils import Frozen , ReprObject
1314from .variable import Variable , calculate_dimensions
@@ -57,6 +58,9 @@ def variables(self):
5758 def _update_coords (self , coords , indexes ):
5859 raise NotImplementedError ()
5960
61+ def _maybe_drop_multiindex_coords (self , coords ):
62+ raise NotImplementedError ()
63+
6064 def __iter__ (self ) -> Iterator [Hashable ]:
6165 # needs to be in the same order as the dataset variables
6266 for k in self .variables :
@@ -154,6 +158,7 @@ def to_index(self, ordered_dims: Sequence[Hashable] = None) -> pd.Index:
154158
155159 def update (self , other : Mapping [Any , Any ]) -> None :
156160 other_vars = getattr (other , "variables" , other )
161+ self ._maybe_drop_multiindex_coords (set (other_vars ))
157162 coords , indexes = merge_coords (
158163 [self .variables , other_vars ], priority_arg = 1 , indexes = self .xindexes
159164 )
@@ -304,6 +309,15 @@ def _update_coords(
304309 original_indexes .update (indexes )
305310 self ._data ._indexes = original_indexes
306311
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+
307321 def __delitem__ (self , key : Hashable ) -> None :
308322 if key in self :
309323 del self ._data [key ]
@@ -372,6 +386,14 @@ def _update_coords(
372386 original_indexes .update (indexes )
373387 self ._data ._indexes = original_indexes
374388
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+
375397 @property
376398 def variables (self ):
377399 return Frozen (self ._data ._coords )
@@ -397,6 +419,37 @@ def _ipython_key_completions_(self):
397419 return self ._data ._ipython_key_completions_ ()
398420
399421
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+
400453def assert_coordinate_consistent (
401454 obj : DataArray | Dataset , coords : Mapping [Any , Variable ]
402455) -> None :
0 commit comments