@@ -491,6 +491,13 @@ def _oindex_get(self, key):
491491 def _vindex_get (self , key ):
492492 raise NotImplementedError ("This method should be overridden" )
493493
494+ def _check_and_raise_if_non_basic_indexer (self , key ):
495+ if isinstance (key , (VectorizedIndexer , OuterIndexer )):
496+ raise TypeError (
497+ "Vectorized indexing with vectorized or outer indexers is not supported. "
498+ "Please use .vindex and .oindex properties to index the array."
499+ )
500+
494501 @property
495502 def oindex (self ):
496503 return IndexCallable (self ._oindex_get )
@@ -517,7 +524,10 @@ def get_duck_array(self):
517524
518525 def __getitem__ (self , key ):
519526 key = expanded_indexer (key , self .ndim )
520- result = self .array [self .indexer_cls (key )]
527+ indexer = self .indexer_cls (key )
528+
529+ result = apply_indexer (self .array , indexer )
530+
521531 if isinstance (result , ExplicitlyIndexed ):
522532 return type (self )(result , self .indexer_cls )
523533 else :
@@ -577,7 +587,13 @@ def shape(self) -> tuple[int, ...]:
577587 return tuple (shape )
578588
579589 def get_duck_array (self ):
580- array = self .array [self .key ]
590+ if isinstance (self .array , ExplicitlyIndexedNDArrayMixin ):
591+ array = apply_indexer (self .array , self .key )
592+ else :
593+ # If the array is not an ExplicitlyIndexedNDArrayMixin,
594+ # it may wrap a BackendArray so use its __getitem__
595+ array = self .array [self .key ]
596+
581597 # self.array[self.key] is now a numpy array when
582598 # self.array is a BackendArray subclass
583599 # and self.key is BasicIndexer((slice(None, None, None),))
@@ -594,12 +610,10 @@ def _oindex_get(self, indexer):
594610
595611 def _vindex_get (self , indexer ):
596612 array = LazilyVectorizedIndexedArray (self .array , self .key )
597- return array [indexer ]
613+ return array . vindex [indexer ]
598614
599615 def __getitem__ (self , indexer ):
600- if isinstance (indexer , VectorizedIndexer ):
601- array = LazilyVectorizedIndexedArray (self .array , self .key )
602- return array [indexer ]
616+ self ._check_and_raise_if_non_basic_indexer (indexer )
603617 return type (self )(self .array , self ._updated_key (indexer ))
604618
605619 def __setitem__ (self , key , value ):
@@ -643,7 +657,13 @@ def shape(self) -> tuple[int, ...]:
643657 return np .broadcast (* self .key .tuple ).shape
644658
645659 def get_duck_array (self ):
646- array = self .array [self .key ]
660+
661+ if isinstance (self .array , ExplicitlyIndexedNDArrayMixin ):
662+ array = apply_indexer (self .array , self .key )
663+ else :
664+ # If the array is not an ExplicitlyIndexedNDArrayMixin,
665+ # it may wrap a BackendArray so use its __getitem__
666+ array = self .array [self .key ]
647667 # self.array[self.key] is now a numpy array when
648668 # self.array is a BackendArray subclass
649669 # and self.key is BasicIndexer((slice(None, None, None),))
@@ -662,6 +682,7 @@ def _vindex_get(self, indexer):
662682 return type (self )(self .array , self ._updated_key (indexer ))
663683
664684 def __getitem__ (self , indexer ):
685+ self ._check_and_raise_if_non_basic_indexer (indexer )
665686 # If the indexed array becomes a scalar, return LazilyIndexedArray
666687 if all (isinstance (ind , integer_types ) for ind in indexer .tuple ):
667688 key = BasicIndexer (tuple (k [indexer .tuple ] for k in self .key .tuple ))
@@ -706,12 +727,13 @@ def get_duck_array(self):
706727 return self .array .get_duck_array ()
707728
708729 def _oindex_get (self , key ):
709- return type (self )(_wrap_numpy_scalars (self .array [key ]))
730+ return type (self )(_wrap_numpy_scalars (self .array . oindex [key ]))
710731
711732 def _vindex_get (self , key ):
712- return type (self )(_wrap_numpy_scalars (self .array [key ]))
733+ return type (self )(_wrap_numpy_scalars (self .array . vindex [key ]))
713734
714735 def __getitem__ (self , key ):
736+ self ._check_and_raise_if_non_basic_indexer (key )
715737 return type (self )(_wrap_numpy_scalars (self .array [key ]))
716738
717739 def transpose (self , order ):
@@ -745,12 +767,13 @@ def get_duck_array(self):
745767 return self .array .get_duck_array ()
746768
747769 def _oindex_get (self , key ):
748- return type (self )(_wrap_numpy_scalars (self .array [key ]))
770+ return type (self )(_wrap_numpy_scalars (self .array . oindex [key ]))
749771
750772 def _vindex_get (self , key ):
751- return type (self )(_wrap_numpy_scalars (self .array [key ]))
773+ return type (self )(_wrap_numpy_scalars (self .array . vindex [key ]))
752774
753775 def __getitem__ (self , key ):
776+ self ._check_and_raise_if_non_basic_indexer (key )
754777 return type (self )(_wrap_numpy_scalars (self .array [key ]))
755778
756779 def transpose (self , order ):
@@ -912,10 +935,21 @@ def explicit_indexing_adapter(
912935 result = raw_indexing_method (raw_key .tuple )
913936 if numpy_indices .tuple :
914937 # index the loaded np.ndarray
915- result = NumpyIndexingAdapter (result )[numpy_indices ]
938+ indexable = NumpyIndexingAdapter (result )
939+ result = apply_indexer (indexable , numpy_indices )
916940 return result
917941
918942
943+ def apply_indexer (indexable , indexer ):
944+ """Apply an indexer to an indexable object."""
945+ if isinstance (indexer , VectorizedIndexer ):
946+ return indexable .vindex [indexer ]
947+ elif isinstance (indexer , OuterIndexer ):
948+ return indexable .oindex [indexer ]
949+ else :
950+ return indexable [indexer ]
951+
952+
919953def decompose_indexer (
920954 indexer : ExplicitIndexer , shape : tuple [int , ...], indexing_support : IndexingSupport
921955) -> tuple [ExplicitIndexer , ExplicitIndexer ]:
@@ -987,10 +1021,10 @@ def _decompose_vectorized_indexer(
9871021 >>> array = np.arange(36).reshape(6, 6)
9881022 >>> backend_indexer = OuterIndexer((np.array([0, 1, 3]), np.array([2, 3])))
9891023 >>> # load subslice of the array
990- ... array = NumpyIndexingAdapter(array)[backend_indexer]
1024+ ... array = NumpyIndexingAdapter(array).oindex [backend_indexer]
9911025 >>> np_indexer = VectorizedIndexer((np.array([0, 2, 1]), np.array([0, 1, 0])))
9921026 >>> # vectorized indexing for on-memory np.ndarray.
993- ... NumpyIndexingAdapter(array)[np_indexer]
1027+ ... NumpyIndexingAdapter(array).vindex [np_indexer]
9941028 array([ 2, 21, 8])
9951029 """
9961030 assert isinstance (indexer , VectorizedIndexer )
@@ -1072,7 +1106,7 @@ def _decompose_outer_indexer(
10721106 ... array = NumpyIndexingAdapter(array)[backend_indexer]
10731107 >>> np_indexer = OuterIndexer((np.array([0, 2, 1]), np.array([0, 1, 0])))
10741108 >>> # outer indexing for on-memory np.ndarray.
1075- ... NumpyIndexingAdapter(array)[np_indexer]
1109+ ... NumpyIndexingAdapter(array).oindex [np_indexer]
10761110 array([[ 2, 3, 2],
10771111 [14, 15, 14],
10781112 [ 8, 9, 8]])
@@ -1395,6 +1429,7 @@ def _vindex_get(self, key):
13951429 return array [key .tuple ]
13961430
13971431 def __getitem__ (self , key ):
1432+ self ._check_and_raise_if_non_basic_indexer (key )
13981433 array , key = self ._indexing_array_and_key (key )
13991434 return array [key ]
14001435
@@ -1450,15 +1485,8 @@ def _vindex_get(self, key):
14501485 raise TypeError ("Vectorized indexing is not supported" )
14511486
14521487 def __getitem__ (self , key ):
1453- if isinstance (key , BasicIndexer ):
1454- return self .array [key .tuple ]
1455- elif isinstance (key , OuterIndexer ):
1456- return self .oindex [key ]
1457- else :
1458- if isinstance (key , VectorizedIndexer ):
1459- raise TypeError ("Vectorized indexing is not supported" )
1460- else :
1461- raise TypeError (f"Unrecognized indexer: { key } " )
1488+ self ._check_and_raise_if_non_basic_indexer (key )
1489+ return self .array [key .tuple ]
14621490
14631491 def __setitem__ (self , key , value ):
14641492 if isinstance (key , (BasicIndexer , OuterIndexer )):
@@ -1499,13 +1527,8 @@ def _vindex_get(self, key):
14991527 return self .array .vindex [key .tuple ]
15001528
15011529 def __getitem__ (self , key ):
1502- if isinstance (key , BasicIndexer ):
1503- return self .array [key .tuple ]
1504- elif isinstance (key , VectorizedIndexer ):
1505- return self .vindex [key ]
1506- else :
1507- assert isinstance (key , OuterIndexer )
1508- return self .oindex [key ]
1530+ self ._check_and_raise_if_non_basic_indexer (key )
1531+ return self .array [key .tuple ]
15091532
15101533 def __setitem__ (self , key , value ):
15111534 if isinstance (key , BasicIndexer ):
@@ -1603,7 +1626,8 @@ def __getitem__(
16031626 (key ,) = key
16041627
16051628 if getattr (key , "ndim" , 0 ) > 1 : # Return np-array if multidimensional
1606- return NumpyIndexingAdapter (np .asarray (self ))[indexer ]
1629+ indexable = NumpyIndexingAdapter (np .asarray (self ))
1630+ return apply_indexer (indexable , indexer )
16071631
16081632 result = self .array [key ]
16091633
0 commit comments