Skip to content

Commit f6a5dd4

Browse files
jbrockmendeljreback
authored andcommitted
Continue simplifying indexing code (#27619)
1 parent 6e28b67 commit f6a5dd4

File tree

5 files changed

+49
-65
lines changed

5 files changed

+49
-65
lines changed

pandas/core/frame.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -2836,11 +2836,13 @@ def __getitem__(self, key):
28362836
# Do we have a slicer (on rows)?
28372837
indexer = convert_to_index_sliceable(self, key)
28382838
if indexer is not None:
2839+
# either we have a slice or we have a string that can be converted
2840+
# to a slice for partial-string date indexing
28392841
return self._slice(indexer, axis=0)
28402842

28412843
# Do we have a (boolean) DataFrame?
28422844
if isinstance(key, DataFrame):
2843-
return self._getitem_frame(key)
2845+
return self.where(key)
28442846

28452847
# Do we have a (boolean) 1d indexer?
28462848
if com.is_bool_indexer(key):
@@ -2938,11 +2940,6 @@ def _getitem_multilevel(self, key):
29382940
else:
29392941
return self._get_item_cache(key)
29402942

2941-
def _getitem_frame(self, key):
2942-
if key.values.size and not is_bool_dtype(key.values):
2943-
raise ValueError("Must pass DataFrame with boolean values only")
2944-
return self.where(key)
2945-
29462943
def _get_value(self, index, col, takeable: bool = False):
29472944
"""
29482945
Quickly retrieve single value at passed column and index.
@@ -2986,6 +2983,8 @@ def __setitem__(self, key, value):
29862983
# see if we can slice the rows
29872984
indexer = convert_to_index_sliceable(self, key)
29882985
if indexer is not None:
2986+
# either we have a slice or we have a string that can be converted
2987+
# to a slice for partial-string date indexing
29892988
return self._setitem_slice(indexer, value)
29902989

29912990
if isinstance(key, DataFrame) or getattr(key, "ndim", None) == 2:

pandas/core/indexing.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ def __iter__(self):
117117
raise NotImplementedError("ix is not iterable")
118118

119119
def __getitem__(self, key):
120+
# Used in ix and downstream in geopandas _CoordinateIndexer
120121
if type(key) is tuple:
121122
# Note: we check the type exactly instead of with isinstance
122123
# because NamedTuple is checked separately.
@@ -181,7 +182,7 @@ def _get_setitem_indexer(self, key):
181182
pass
182183

183184
if isinstance(key, range):
184-
return self._convert_range(key, is_setter=True)
185+
return list(key)
185186

186187
axis = self.axis or 0
187188
try:
@@ -258,10 +259,6 @@ def _convert_tuple(self, key):
258259
keyidx.append(idx)
259260
return tuple(keyidx)
260261

261-
def _convert_range(self, key: range, is_setter: bool = False):
262-
""" convert a range argument """
263-
return list(key)
264-
265262
def _convert_scalar_indexer(self, key, axis: int):
266263
# if we are accessing via lowered dim, use the last dim
267264
ax = self.obj._get_axis(min(axis, self.ndim - 1))

pandas/core/series.py

+40-52
Original file line numberDiff line numberDiff line change
@@ -1131,8 +1131,7 @@ def __getitem__(self, key):
11311131
def _get_with(self, key):
11321132
# other: fancy integer or otherwise
11331133
if isinstance(key, slice):
1134-
indexer = self.index._convert_slice_indexer(key, kind="getitem")
1135-
return self._get_values(indexer)
1134+
return self._slice(key)
11361135
elif isinstance(key, ABCDataFrame):
11371136
raise TypeError(
11381137
"Indexing a Series with DataFrame is not "
@@ -1148,7 +1147,6 @@ def _get_with(self, key):
11481147
return self._get_values(key)
11491148
raise
11501149

1151-
# pragma: no cover
11521150
if not isinstance(key, (list, np.ndarray, Series, Index)):
11531151
key = list(key)
11541152

@@ -1165,19 +1163,18 @@ def _get_with(self, key):
11651163
elif key_type == "boolean":
11661164
return self._get_values(key)
11671165

1168-
try:
1169-
# handle the dup indexing case (GH 4246)
1170-
if isinstance(key, (list, tuple)):
1171-
return self.loc[key]
1172-
1173-
return self.reindex(key)
1174-
except Exception:
1175-
# [slice(0, 5, None)] will break if you convert to ndarray,
1176-
# e.g. as requested by np.median
1177-
# hack
1178-
if isinstance(key[0], slice):
1166+
if isinstance(key, (list, tuple)):
1167+
# TODO: de-dup with tuple case handled above?
1168+
# handle the dup indexing case GH#4246
1169+
if len(key) == 1 and isinstance(key[0], slice):
1170+
# [slice(0, 5, None)] will break if you convert to ndarray,
1171+
# e.g. as requested by np.median
1172+
# FIXME: hack
11791173
return self._get_values(key)
1180-
raise
1174+
1175+
return self.loc[key]
1176+
1177+
return self.reindex(key)
11811178

11821179
def _get_values_tuple(self, key):
11831180
# mpl hackaround
@@ -1220,33 +1217,28 @@ def _get_value(self, label, takeable: bool = False):
12201217

12211218
def __setitem__(self, key, value):
12221219
key = com.apply_if_callable(key, self)
1220+
cacher_needs_updating = self._check_is_chained_assignment_possible()
12231221

1224-
def setitem(key, value):
1225-
try:
1226-
self._set_with_engine(key, value)
1227-
return
1228-
except com.SettingWithCopyError:
1229-
raise
1230-
except (KeyError, ValueError):
1231-
values = self._values
1232-
if is_integer(key) and not self.index.inferred_type == "integer":
1233-
1234-
values[key] = value
1235-
return
1236-
elif key is Ellipsis:
1237-
self[:] = value
1238-
return
1239-
1222+
try:
1223+
self._set_with_engine(key, value)
1224+
except com.SettingWithCopyError:
1225+
raise
1226+
except (KeyError, ValueError):
1227+
values = self._values
1228+
if is_integer(key) and not self.index.inferred_type == "integer":
1229+
values[key] = value
1230+
elif key is Ellipsis:
1231+
self[:] = value
1232+
else:
12401233
self.loc[key] = value
1241-
return
12421234

1243-
except TypeError as e:
1244-
if isinstance(key, tuple) and not isinstance(self.index, MultiIndex):
1245-
raise ValueError("Can only tuple-index with a MultiIndex")
1235+
except TypeError as e:
1236+
if isinstance(key, tuple) and not isinstance(self.index, MultiIndex):
1237+
raise ValueError("Can only tuple-index with a MultiIndex")
12461238

1247-
# python 3 type errors should be raised
1248-
if _is_unorderable_exception(e):
1249-
raise IndexError(key)
1239+
# python 3 type errors should be raised
1240+
if _is_unorderable_exception(e):
1241+
raise IndexError(key)
12501242

12511243
if com.is_bool_indexer(key):
12521244
key = check_bool_indexer(self.index, key)
@@ -1258,9 +1250,6 @@ def setitem(key, value):
12581250

12591251
self._set_with(key, value)
12601252

1261-
# do the setitem
1262-
cacher_needs_updating = self._check_is_chained_assignment_possible()
1263-
setitem(key, value)
12641253
if cacher_needs_updating:
12651254
self._maybe_update_cacher()
12661255

@@ -1282,20 +1271,21 @@ def _set_with(self, key, value):
12821271
if isinstance(key, slice):
12831272
indexer = self.index._convert_slice_indexer(key, kind="getitem")
12841273
return self._set_values(indexer, value)
1274+
1275+
elif is_scalar(key) and not is_integer(key) and key not in self.index:
1276+
# GH#12862 adding an new key to the Series
1277+
# Note: have to exclude integers because that is ambiguously
1278+
# position-based
1279+
self.loc[key] = value
1280+
return
1281+
12851282
else:
12861283
if isinstance(key, tuple):
12871284
try:
12881285
self._set_values(key, value)
12891286
except Exception:
12901287
pass
12911288

1292-
if is_scalar(key) and not is_integer(key) and key not in self.index:
1293-
# GH#12862 adding an new key to the Series
1294-
# Note: have to exclude integers because that is ambiguously
1295-
# position-based
1296-
self.loc[key] = value
1297-
return
1298-
12991289
if is_scalar(key):
13001290
key = [key]
13011291
elif not isinstance(key, (list, Series, np.ndarray)):
@@ -1306,6 +1296,7 @@ def _set_with(self, key, value):
13061296

13071297
if isinstance(key, Index):
13081298
key_type = key.inferred_type
1299+
key = key._values
13091300
else:
13101301
key_type = lib.infer_dtype(key, skipna=False)
13111302

@@ -1320,10 +1311,7 @@ def _set_with(self, key, value):
13201311
self._set_labels(key, value)
13211312

13221313
def _set_labels(self, key, value):
1323-
if isinstance(key, Index):
1324-
key = key.values
1325-
else:
1326-
key = com.asarray_tuplesafe(key)
1314+
key = com.asarray_tuplesafe(key)
13271315
indexer = self.index.get_indexer(key)
13281316
mask = indexer == -1
13291317
if mask.any():

pandas/core/sparse/series.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ def _ixs(self, i: int, axis: int = 0):
324324
Parameters
325325
----------
326326
i : int
327-
axis: int
327+
axis : int
328328
default 0, ignored
329329
330330
Returns

pandas/tests/frame/test_indexing.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def test_getitem_boolean(
269269
subframe_obj = datetime_frame[indexer_obj]
270270
assert_frame_equal(subframe_obj, subframe)
271271

272-
with pytest.raises(ValueError, match="boolean values only"):
272+
with pytest.raises(ValueError, match="Boolean array expected"):
273273
datetime_frame[datetime_frame]
274274

275275
# test that Series work

0 commit comments

Comments
 (0)