66 Hashable ,
77 Iterator ,
88 Mapping ,
9- Sequence ,
109 Set ,
10+ Sequence ,
1111 Tuple ,
1212 Union ,
1313 cast ,
1717
1818from . import formatting , indexing
1919from .indexes import Indexes
20- from .merge import (
21- expand_and_merge_variables ,
22- merge_coords ,
23- merge_coords_for_inplace_math ,
24- )
20+ from .merge import merge_coords , merge_coordinates_without_align
2521from .utils import Frozen , ReprObject , either_dict_or_kwargs
2622from .variable import Variable
2723
3430_THIS_ARRAY = ReprObject ("<this-array>" )
3531
3632
37- class AbstractCoordinates (Mapping [Hashable , "DataArray" ]):
33+ class Coordinates (Mapping [Hashable , "DataArray" ]):
3834 __slots__ = ()
3935
4036 def __getitem__ (self , key : Hashable ) -> "DataArray" :
@@ -57,10 +53,10 @@ def indexes(self) -> Indexes:
5753
5854 @property
5955 def variables (self ):
60- raise NotImplementedError ()
56+ raise NotImplementedError
6157
62- def _update_coords (self , coords ):
63- raise NotImplementedError ()
58+ def _update_coords (self , coords , indexes ):
59+ raise NotImplementedError
6460
6561 def __iter__ (self ) -> Iterator ["Hashable" ]:
6662 # needs to be in the same order as the dataset variables
@@ -116,38 +112,38 @@ def to_index(self, ordered_dims: Sequence[Hashable] = None) -> pd.Index:
116112
117113 def update (self , other : Mapping [Hashable , Any ]) -> None :
118114 other_vars = getattr (other , "variables" , other )
119- coords = merge_coords (
115+ coords , indexes = merge_coords (
120116 [self .variables , other_vars ], priority_arg = 1 , indexes = self .indexes
121117 )
122- self ._update_coords (coords )
118+ self ._update_coords (coords , indexes )
123119
124120 def _merge_raw (self , other ):
125121 """For use with binary arithmetic."""
126122 if other is None :
127123 variables = OrderedDict (self .variables )
124+ indexes = OrderedDict (self .indexes )
128125 else :
129- # don't align because we already called xarray.align
130- variables = expand_and_merge_variables ([self .variables , other .variables ])
131- return variables
126+ variables , indexes = merge_coordinates_without_align ([self , other ])
127+ return variables , indexes
132128
133129 @contextmanager
134130 def _merge_inplace (self , other ):
135131 """For use with in-place binary arithmetic."""
136132 if other is None :
137133 yield
138134 else :
139- # don't include indexes in priority_vars , because we didn't align
140- # first
141- priority_vars = OrderedDict (
142- kv for kv in self .variables .items () if kv [ 0 ] not in self .dims
143- )
144- variables = merge_coords_for_inplace_math (
145- [self . variables , other . variables ], priority_vars = priority_vars
135+ # don't include indexes in prioritized , because we didn't align
136+ # first and we want indexes to be checked
137+ prioritized = {
138+ k : ( v , None ) for k , v in self .variables .items () if k not in self .indexes
139+ }
140+ variables , indexes = merge_coordinates_without_align (
141+ [self , other ], prioritized
146142 )
147143 yield
148- self ._update_coords (variables )
144+ self ._update_coords (variables , indexes )
149145
150- def merge (self , other : "AbstractCoordinates " ) -> "Dataset" :
146+ def merge (self , other : "Coordinates " ) -> "Dataset" :
151147 """Merge two sets of coordinates to create a new Dataset
152148
153149 The method implements the logic used for joining coordinates in the
@@ -173,13 +169,19 @@ def merge(self, other: "AbstractCoordinates") -> "Dataset":
173169
174170 if other is None :
175171 return self .to_dataset ()
176- else :
177- other_vars = getattr (other , "variables" , other )
178- coords = expand_and_merge_variables ([self .variables , other_vars ])
179- return Dataset ._from_vars_and_coord_names (coords , set (coords ))
172+
173+ if not isinstance (other , Coordinates ):
174+ other = Dataset (coords = other ).coords
175+
176+ coords , indexes = merge_coordinates_without_align ([self , other ])
177+ coord_names = set (coords )
178+ merged = Dataset ._construct_direct (
179+ variables = coords , coord_names = coord_names , indexes = indexes
180+ )
181+ return merged
180182
181183
182- class DatasetCoordinates (AbstractCoordinates ):
184+ class DatasetCoordinates (Coordinates ):
183185 """Dictionary like container for Dataset coordinates.
184186
185187 Essentially an immutable OrderedDict with keys given by the array's
@@ -218,7 +220,11 @@ def to_dataset(self) -> "Dataset":
218220 """
219221 return self ._data ._copy_listed (self ._names )
220222
221- def _update_coords (self , coords : Mapping [Hashable , Any ]) -> None :
223+ def _update_coords (
224+ self ,
225+ coords : "OrderedDict[Hashable, Variable]" ,
226+ indexes : Mapping [Hashable , pd .Index ],
227+ ) -> None :
222228 from .dataset import calculate_dimensions
223229
224230 variables = self ._data ._variables .copy ()
@@ -234,7 +240,12 @@ def _update_coords(self, coords: Mapping[Hashable, Any]) -> None:
234240 self ._data ._variables = variables
235241 self ._data ._coord_names .update (new_coord_names )
236242 self ._data ._dims = dims
237- self ._data ._indexes = None
243+
244+ # TODO(shoyer): once ._indexes is always populated by a dict, modify
245+ # it to update inplace instead.
246+ original_indexes = OrderedDict (self ._data .indexes )
247+ original_indexes .update (indexes )
248+ self ._data ._indexes = original_indexes
238249
239250 def __delitem__ (self , key : Hashable ) -> None :
240251 if key in self :
@@ -251,7 +262,7 @@ def _ipython_key_completions_(self):
251262 ]
252263
253264
254- class DataArrayCoordinates (AbstractCoordinates ):
265+ class DataArrayCoordinates (Coordinates ):
255266 """Dictionary like container for DataArray coordinates.
256267
257268 Essentially an OrderedDict with keys given by the array's
@@ -274,7 +285,11 @@ def _names(self) -> Set[Hashable]:
274285 def __getitem__ (self , key : Hashable ) -> "DataArray" :
275286 return self ._data ._getitem_coord (key )
276287
277- def _update_coords (self , coords ) -> None :
288+ def _update_coords (
289+ self ,
290+ coords : "OrderedDict[Hashable, Variable]" ,
291+ indexes : Mapping [Hashable , pd .Index ],
292+ ) -> None :
278293 from .dataset import calculate_dimensions
279294
280295 coords_plus_data = coords .copy ()
@@ -285,7 +300,12 @@ def _update_coords(self, coords) -> None:
285300 "cannot add coordinates with new dimensions to " "a DataArray"
286301 )
287302 self ._data ._coords = coords
288- self ._data ._indexes = None
303+
304+ # TODO(shoyer): once ._indexes is always populated by a dict, modify
305+ # it to update inplace instead.
306+ original_indexes = OrderedDict (self ._data .indexes )
307+ original_indexes .update (indexes )
308+ self ._data ._indexes = original_indexes
289309
290310 @property
291311 def variables (self ):
0 commit comments