@@ -922,32 +922,41 @@ def index(self, key) -> Union[int, np.ndarray, slice]:
922922 """
923923 mapping = self ._mapping
924924
925- if isinstance (key , Group ) and key .axis is not self and key .axis is not None :
926- try :
927- # XXX: this is potentially very expensive if key.key is an array or list and should be tried as a last
928- # resort
929- potential_tick = _to_tick (key )
930-
931- # avoid matching 0 against False or 0.0, note that None has object dtype and so always pass this test
932- if self ._is_key_type_compatible (potential_tick ):
933- try :
934- res_idx = mapping [potential_tick ]
935- if potential_tick != key .key :
936- # only warn if no KeyError was raised (potential_tick is in mapping)
937- msg = "Using a Group object which was used to create an aggregate to " \
938- "target its aggregated label is deprecated. " \
939- "Please use the aggregated label directly instead. " \
940- f"In this case, you should use { potential_tick !r} instead of " \
941- f"using { key !r} ."
942- # let us hope the stacklevel does not vary by codepath
943- warnings .warn (msg , FutureWarning , stacklevel = 8 )
944- return res_idx
945- except KeyError :
946- pass
947- # we must catch TypeError because key might not be hashable (eg slice)
948- # IndexError is for when mapping is an ndarray
949- except (KeyError , TypeError , IndexError ):
950- pass
925+ if isinstance (key , Group ):
926+ if key .axis is self :
927+ if isinstance (key , IGroup ):
928+ return key .key
929+ else :
930+ # at this point we do not care about the axis nor the name
931+ key = key .key
932+ elif key .axis is not None :
933+ try :
934+ # TODO: remove this as it is potentially very expensive
935+ # if key.key is an array or list and should be tried
936+ # as a last resort
937+ potential_tick = _to_tick (key )
938+
939+ # avoid matching 0 against False or 0.0, note that None has
940+ # object dtype and so always pass this test
941+ if self ._is_key_type_compatible (potential_tick ):
942+ try :
943+ res_idx = mapping [potential_tick ]
944+ if potential_tick != key .key :
945+ # only warn if no KeyError was raised (potential_tick is in mapping)
946+ msg = "Using a Group object which was used to create an aggregate to " \
947+ "target its aggregated label is deprecated. " \
948+ "Please use the aggregated label directly instead. " \
949+ f"In this case, you should use { potential_tick !r} instead of " \
950+ f"using { key !r} ."
951+ # let us hope the stacklevel does not vary by codepath
952+ warnings .warn (msg , FutureWarning , stacklevel = 8 )
953+ return res_idx
954+ except KeyError :
955+ pass
956+ # we must catch TypeError because key might not be hashable (eg slice)
957+ # IndexError is for when mapping is an ndarray
958+ except (KeyError , TypeError , IndexError ):
959+ pass
951960
952961 if isinstance (key , str ):
953962 # try the key as-is to allow getting at ticks with special characters (",", ":", ...)
@@ -961,24 +970,35 @@ def index(self, key) -> Union[int, np.ndarray, slice]:
961970 except (KeyError , TypeError , IndexError ):
962971 pass
963972
964- # transform "specially formatted strings" for slices, lists, LGroup and IGroup to actual objects
973+ # transform "specially formatted strings" for slices, lists, LGroup
974+ # and IGroup to actual objects
965975 key = _to_key (key )
966976
967977 if isinstance (key , range ):
968978 key = list (key )
969-
970- # this can happen when key was passed as a string and converted to a Group via _to_key
971- if isinstance (key , Group ) and isinstance (key .axis , str ) and key .axis != self .name :
972- raise KeyError (key )
973-
974- if isinstance (key , IGroup ):
975- if isinstance (key .axis , Axis ):
976- assert key .axis is self
977- return key .key
978-
979- if isinstance (key , LGroup ):
980- # at this point we do not care about the axis nor the name
981- key = key .key
979+ elif isinstance (key , Group ):
980+ key_axis = key .axis
981+ if isinstance (key_axis , str ):
982+ if key_axis != self .name :
983+ raise KeyError (key )
984+ elif isinstance (key_axis , AxisReference ):
985+ if key_axis .name != self .name :
986+ raise KeyError (key )
987+ elif isinstance (key_axis , Axis ): # we know it is not self
988+ # IGroups will be retargeted to LGroups
989+ key = key .retarget_to (self )
990+ elif isinstance (key_axis , int ):
991+ raise TypeError ('Axis.index() does not support Group keys with '
992+ 'integer axis' )
993+ else :
994+ assert key_axis is None
995+ # an IGroup can still exist at this point if the key was an IGroup
996+ # with a compatible axis (string or AxisReference axis with the
997+ # correct name or Axis object equal to self)
998+ if isinstance (key , IGroup ):
999+ return key .key
1000+ else :
1001+ key = key .key
9821002
9831003 if isinstance (key , slice ):
9841004 start = mapping [key .start ] if key .start is not None else None
@@ -1915,7 +1935,8 @@ def __contains__(self, key) -> bool:
19151935 if isinstance (key , int ):
19161936 return - len (self ) <= key < len (self )
19171937 elif isinstance (key , Axis ):
1918- # the special case is just a performance optimization to avoid scanning through the whole list
1938+ # the special case is just a performance optimization to avoid
1939+ # scanning through the whole list
19191940 if key .name is not None :
19201941 return key .name in self ._map
19211942 else :
@@ -2808,7 +2829,7 @@ def _guess_axis(self, axis_key):
28082829 # we have axis information but not necessarily an Axis object from self
28092830 real_axis = self [group_axis ]
28102831 if group_axis is not real_axis :
2811- axis_key = axis_key .with_axis (real_axis )
2832+ axis_key = axis_key .retarget_to (real_axis )
28122833 return axis_key
28132834
28142835 real_axis , axis_pos_key = self ._translate_nice_key (axis_key )
@@ -2828,6 +2849,7 @@ def _translate_axis_key_chunk(self, axis_key):
28282849 (axis, indices)
28292850 Indices group with a valid axis (from self)
28302851 """
2852+ orig_key = axis_key
28312853 axis_key = remove_nested_groups (axis_key )
28322854
28332855 if isinstance (axis_key , IGroup ):
@@ -2852,11 +2874,16 @@ def _translate_axis_key_chunk(self, axis_key):
28522874 # labels but known axis
28532875 if isinstance (axis_key , LGroup ) and axis_key .axis is not None :
28542876 try :
2855- real_axis = self [axis_key .axis ]
2877+ key_axis = axis_key .axis
2878+ real_axis = self [key_axis ]
2879+ if isinstance (key_axis , (AxisReference , int )):
2880+ # this is one of the rare cases where with_axis is correct !
2881+ axis_key = axis_key .with_axis (real_axis )
2882+
28562883 try :
28572884 axis_pos_key = real_axis .index (axis_key )
28582885 except KeyError :
2859- raise ValueError (f"{ axis_key !r} is not a valid label for the { real_axis .name !r} axis "
2886+ raise ValueError (f"{ orig_key !r} is not a valid label for the { real_axis .name !r} axis "
28602887 f"with labels: { ', ' .join (repr (label ) for label in real_axis .labels )} " )
28612888 return real_axis , axis_pos_key
28622889 except KeyError :
@@ -3889,6 +3916,7 @@ def align_axis_collections(axis_collections, join='outer', axes=None):
38893916
38903917class AxisReference (ABCAxisReference , ExprNode , Axis ):
38913918 def __init__ (self , name ):
3919+ assert isinstance (name , (int , str ))
38923920 self .name = name
38933921 self ._labels = None
38943922 self ._iswildcard = False
0 commit comments