Skip to content

Commit 19f06d9

Browse files
authored
CLN: de-duplicate Ellipsis-handling (#44238)
* CLN: de-duplicate Ellipsis-handling * mypy fixup
1 parent 80789b8 commit 19f06d9

File tree

6 files changed

+37
-33
lines changed

6 files changed

+37
-33
lines changed

pandas/core/arrays/sparse/array.py

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from pandas.compat.numpy import function as nv
4343
from pandas.errors import PerformanceWarning
4444
from pandas.util._exceptions import find_stack_level
45+
from pandas.util._validators import validate_insert_loc
4546

4647
from pandas.core.dtypes.cast import (
4748
astype_nansafe,
@@ -81,7 +82,10 @@
8182
extract_array,
8283
sanitize_array,
8384
)
84-
from pandas.core.indexers import check_array_indexer
85+
from pandas.core.indexers import (
86+
check_array_indexer,
87+
unpack_tuple_and_ellipses,
88+
)
8589
from pandas.core.missing import interpolate_2d
8690
from pandas.core.nanops import check_below_min_count
8791
import pandas.core.ops as ops
@@ -878,16 +882,13 @@ def __getitem__(
878882
) -> SparseArrayT | Any:
879883

880884
if isinstance(key, tuple):
881-
if len(key) > 1:
882-
if key[0] is Ellipsis:
883-
key = key[1:]
884-
elif key[-1] is Ellipsis:
885-
key = key[:-1]
886-
if len(key) > 1:
887-
raise IndexError("too many indices for array.")
888-
if key[0] is Ellipsis:
885+
key = unpack_tuple_and_ellipses(key)
886+
# Non-overlapping identity check (left operand type:
887+
# "Union[Union[Union[int, integer[Any]], Union[slice, List[int],
888+
# ndarray[Any, Any]]], Tuple[Union[int, ellipsis], ...]]",
889+
# right operand type: "ellipsis")
890+
if key is Ellipsis: # type: ignore[comparison-overlap]
889891
raise ValueError("Cannot slice with Ellipsis")
890-
key = key[0]
891892

892893
if is_integer(key):
893894
return self._get_val_at(key)
@@ -952,12 +953,7 @@ def __getitem__(
952953
return type(self)(data_slice, kind=self.kind)
953954

954955
def _get_val_at(self, loc):
955-
n = len(self)
956-
if loc < 0:
957-
loc += n
958-
959-
if loc >= n or loc < 0:
960-
raise IndexError("Out of bounds access")
956+
loc = validate_insert_loc(loc, len(self))
961957

962958
sp_loc = self.sp_index.lookup(loc)
963959
if sp_loc == -1:

pandas/core/arrays/string_arrow.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
)
5959
from pandas.core.indexers import (
6060
check_array_indexer,
61+
unpack_tuple_and_ellipses,
6162
validate_indices,
6263
)
6364
from pandas.core.strings.object_array import ObjectStringArrayMixin
@@ -313,14 +314,7 @@ def __getitem__(
313314
"boolean arrays are valid indices."
314315
)
315316
elif isinstance(item, tuple):
316-
# possibly unpack arr[..., n] to arr[n]
317-
if len(item) == 1:
318-
item = item[0]
319-
elif len(item) == 2:
320-
if item[0] is Ellipsis:
321-
item = item[1]
322-
elif item[1] is Ellipsis:
323-
item = item[0]
317+
item = unpack_tuple_and_ellipses(item)
324318

325319
# We are not an array indexer, so maybe e.g. a slice or integer
326320
# indexer. We dispatch to pyarrow.

pandas/core/indexers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
length_of_indexer,
1212
maybe_convert_indices,
1313
unpack_1tuple,
14+
unpack_tuple_and_ellipses,
1415
validate_indices,
1516
)
1617

@@ -28,4 +29,5 @@
2829
"unpack_1tuple",
2930
"check_key_length",
3031
"check_array_indexer",
32+
"unpack_tuple_and_ellipses",
3133
]

pandas/core/indexers/utils.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,24 @@ def check_key_length(columns: Index, key, value: DataFrame) -> None:
435435
raise ValueError("Columns must be same length as key")
436436

437437

438+
def unpack_tuple_and_ellipses(item: tuple):
439+
"""
440+
Possibly unpack arr[..., n] to arr[n]
441+
"""
442+
if len(item) > 1:
443+
# Note: we are assuming this indexing is being done on a 1D arraylike
444+
if item[0] is Ellipsis:
445+
item = item[1:]
446+
elif item[-1] is Ellipsis:
447+
item = item[:-1]
448+
449+
if len(item) > 1:
450+
raise IndexError("too many indices for array.")
451+
452+
item = item[0]
453+
return item
454+
455+
438456
# -----------------------------------------------------------
439457
# Public indexer validation
440458

pandas/tests/arrays/sparse/test_array.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def test_get_item(self):
258258
assert self.zarr[2] == 1
259259
assert self.zarr[7] == 5
260260

261-
errmsg = re.compile("bounds")
261+
errmsg = "must be an integer between -10 and 10"
262262

263263
with pytest.raises(IndexError, match=errmsg):
264264
self.arr[11]

pandas/tests/extension/json/array.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
ExtensionDtype,
4141
)
4242
from pandas.api.types import is_bool_dtype
43+
from pandas.core.indexers import unpack_tuple_and_ellipses
4344

4445

4546
class JSONDtype(ExtensionDtype):
@@ -86,14 +87,7 @@ def _from_factorized(cls, values, original):
8687

8788
def __getitem__(self, item):
8889
if isinstance(item, tuple):
89-
if len(item) > 1:
90-
if item[0] is Ellipsis:
91-
item = item[1:]
92-
elif item[-1] is Ellipsis:
93-
item = item[:-1]
94-
if len(item) > 1:
95-
raise IndexError("too many indices for array.")
96-
item = item[0]
90+
item = unpack_tuple_and_ellipses(item)
9791

9892
if isinstance(item, numbers.Integral):
9993
return self.data[item]

0 commit comments

Comments
 (0)