55 TYPE_CHECKING ,
66 Hashable ,
77 Sequence ,
8+ final ,
89)
910import warnings
1011
@@ -626,6 +627,7 @@ class _LocationIndexer(NDFrameIndexerBase):
626627 _valid_types : str
627628 axis = None
628629
630+ @final
629631 def __call__ (self , axis = None ):
630632 # we need to return a copy of ourselves
631633 new_self = type (self )(self .name , self .obj )
@@ -640,14 +642,15 @@ def _get_setitem_indexer(self, key):
640642 Convert a potentially-label-based key into a positional indexer.
641643 """
642644 if self .name == "loc" :
645+ # always holds here bc iloc overrides _get_setitem_indexer
643646 self ._ensure_listlike_indexer (key )
644647
645648 if isinstance (key , tuple ):
646649 for x in key :
647650 check_deprecated_indexers (x )
648651
649652 if self .axis is not None :
650- return self ._convert_tuple (key )
653+ key = self ._tupleize_axis_indexer (key )
651654
652655 ax = self .obj ._get_axis (0 )
653656
@@ -658,13 +661,26 @@ def _get_setitem_indexer(self, key):
658661
659662 if isinstance (key , tuple ):
660663 with suppress (IndexingError ):
664+ # suppress "Too many indexers"
661665 return self ._convert_tuple (key )
662666
663667 if isinstance (key , range ):
664668 return list (key )
665669
666670 return self ._convert_to_indexer (key , axis = 0 )
667671
672+ @final
673+ def _tupleize_axis_indexer (self , key ) -> tuple :
674+ """
675+ If we have an axis, adapt the given key to be axis-independent.
676+ """
677+ new_key = [slice (None )] * self .ndim
678+ # error: Invalid index type "Optional[Any]" for "List[slice]"; expected
679+ # type "SupportsIndex"
680+ new_key [self .axis ] = key # type:ignore[index]
681+ return tuple (new_key )
682+
683+ @final
668684 def _ensure_listlike_indexer (self , key , axis = None , value = None ):
669685 """
670686 Ensure that a list-like of column labels are all present by adding them if
@@ -702,6 +718,7 @@ def _ensure_listlike_indexer(self, key, axis=None, value=None):
702718 keys , axis = 0 , consolidate = False , only_slice = True
703719 )
704720
721+ @final
705722 def __setitem__ (self , key , value ):
706723 check_deprecated_indexers (key )
707724 if isinstance (key , tuple ):
@@ -737,6 +754,7 @@ def _validate_key(self, key, axis: int):
737754 """
738755 raise AbstractMethodError (self )
739756
757+ @final
740758 def _expand_ellipsis (self , tup : tuple ) -> tuple :
741759 """
742760 If a tuple key includes an Ellipsis, replace it with an appropriate
@@ -758,6 +776,7 @@ def _expand_ellipsis(self, tup: tuple) -> tuple:
758776 # by _validate_key_length
759777 return tup
760778
779+ @final
761780 def _validate_tuple_indexer (self , key : tuple ) -> tuple :
762781 """
763782 Check the key for valid keys across my indexer.
@@ -774,6 +793,7 @@ def _validate_tuple_indexer(self, key: tuple) -> tuple:
774793 ) from err
775794 return key
776795
796+ @final
777797 def _is_nested_tuple_indexer (self , tup : tuple ) -> bool :
778798 """
779799 Returns
@@ -784,23 +804,18 @@ def _is_nested_tuple_indexer(self, tup: tuple) -> bool:
784804 return any (is_nested_tuple (tup , ax ) for ax in self .obj .axes )
785805 return False
786806
787- def _convert_tuple (self , key ):
807+ @final
808+ def _convert_tuple (self , key : tuple ) -> tuple :
809+ # Note: we assume _tupleize_axis_indexer has been called, if necessary.
788810 keyidx = []
789- if self .axis is not None :
790- axis = self .obj ._get_axis_number (self .axis )
791- for i in range (self .ndim ):
792- if i == axis :
793- keyidx .append (self ._convert_to_indexer (key , axis = axis ))
794- else :
795- keyidx .append (slice (None ))
796- else :
797- self ._validate_key_length (key )
798- for i , k in enumerate (key ):
799- idx = self ._convert_to_indexer (k , axis = i )
800- keyidx .append (idx )
811+ self ._validate_key_length (key )
812+ for i , k in enumerate (key ):
813+ idx = self ._convert_to_indexer (k , axis = i )
814+ keyidx .append (idx )
801815
802816 return tuple (keyidx )
803817
818+ @final
804819 def _validate_key_length (self , key : tuple ) -> tuple :
805820 if len (key ) > self .ndim :
806821 if key [0 ] is Ellipsis :
@@ -812,6 +827,7 @@ def _validate_key_length(self, key: tuple) -> tuple:
812827 raise IndexingError ("Too many indexers" )
813828 return key
814829
830+ @final
815831 def _getitem_tuple_same_dim (self , tup : tuple ):
816832 """
817833 Index with indexers that should return an object of the same dimension
@@ -831,6 +847,7 @@ def _getitem_tuple_same_dim(self, tup: tuple):
831847
832848 return retval
833849
850+ @final
834851 def _getitem_lowerdim (self , tup : tuple ):
835852
836853 # we can directly get the axis result since the axis is specified
@@ -892,6 +909,7 @@ def _getitem_lowerdim(self, tup: tuple):
892909
893910 raise IndexingError ("not applicable" )
894911
912+ @final
895913 def _getitem_nested_tuple (self , tup : tuple ):
896914 # we have a nested tuple so have at least 1 multi-index level
897915 # we should be able to match up the dimensionality here
@@ -951,6 +969,7 @@ def _getitem_nested_tuple(self, tup: tuple):
951969 def _convert_to_indexer (self , key , axis : int ):
952970 raise AbstractMethodError (self )
953971
972+ @final
954973 def __getitem__ (self , key ):
955974 check_deprecated_indexers (key )
956975 if type (key ) is tuple :
@@ -978,6 +997,7 @@ def _getitem_axis(self, key, axis: int):
978997 def _has_valid_setitem_indexer (self , indexer ) -> bool :
979998 raise AbstractMethodError (self )
980999
1000+ @final
9811001 def _getbool_axis (self , key , axis : int ):
9821002 # caller is responsible for ensuring non-None axis
9831003 labels = self .obj ._get_axis (axis )
@@ -1544,7 +1564,7 @@ def _get_setitem_indexer(self, key):
15441564 key = list (key )
15451565
15461566 if self .axis is not None :
1547- return self ._convert_tuple (key )
1567+ key = self ._tupleize_axis_indexer (key )
15481568
15491569 return key
15501570
0 commit comments