Skip to content

Commit 2c9a96f

Browse files
jbrockmendelroberthdevries
authored andcommitted
BUG: using loc[int] with object index (pandas-dev#31905)
* BUG: using loc[int] with object index * whatsnew
1 parent f6369e8 commit 2c9a96f

File tree

6 files changed

+24
-22
lines changed

6 files changed

+24
-22
lines changed

doc/source/whatsnew/v1.1.0.rst

+4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ Other API changes
5656
- :meth:`Series.describe` will now show distribution percentiles for ``datetime`` dtypes, statistics ``first`` and ``last``
5757
will now be ``min`` and ``max`` to match with numeric dtypes in :meth:`DataFrame.describe` (:issue:`30164`)
5858
- :meth:`Groupby.groups` now returns an abbreviated representation when called on large dataframes (:issue:`1135`)
59+
- ``loc`` lookups with an object-dtype :class:`Index` and an integer key will now raise ``KeyError`` instead of ``TypeError`` when key is missing (:issue:`31905`)
60+
-
5961

6062
Backwards incompatible API changes
6163
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -160,6 +162,8 @@ Indexing
160162
- Bug in :meth:`DatetimeIndex.get_loc` raising ``KeyError`` with converted-integer key instead of the user-passed key (:issue:`31425`)
161163
- Bug in :meth:`Series.xs` incorrectly returning ``Timestamp`` instead of ``datetime64`` in some object-dtype cases (:issue:`31630`)
162164
- Bug in :meth:`DataFrame.iat` incorrectly returning ``Timestamp`` instead of ``datetime`` in some object-dtype cases (:issue:`32809`)
165+
- Bug in :meth:`Series.loc` and :meth:`DataFrame.loc` when indexing with an integer key on a object-dtype :class:`Index` that is not all-integers (:issue:`31905`)
166+
-
163167

164168
Missing
165169
^^^^^^^

pandas/core/indexes/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3111,7 +3111,7 @@ def _convert_scalar_indexer(self, key, kind: str_t):
31113111
self._invalid_indexer("label", key)
31123112

31133113
elif kind == "loc" and is_integer(key):
3114-
if not self.holds_integer():
3114+
if not (is_integer_dtype(self.dtype) or is_object_dtype(self.dtype)):
31153115
self._invalid_indexer("label", key)
31163116

31173117
return key

pandas/core/series.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -969,9 +969,11 @@ def _get_value(self, label, takeable: bool = False):
969969
if takeable:
970970
return self._values[label]
971971

972+
# Similar to Index.get_value, but we do not fall back to positional
973+
loc = self.index.get_loc(label)
972974
# We assume that _convert_scalar_indexer has already been called,
973975
# with kind="loc", if necessary, by the time we get here
974-
return self.index.get_value(self, label)
976+
return self.index._get_values_for_loc(self, loc, label)
975977

976978
def __setitem__(self, key, value):
977979
key = com.apply_if_callable(key, self)

pandas/tests/indexing/test_categorical.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,7 @@ def test_loc_scalar(self):
8282
with pytest.raises(TypeError, match=msg):
8383
df.loc["d", "C"] = 10
8484

85-
msg = (
86-
"cannot do label indexing on CategoricalIndex with these "
87-
r"indexers \[1\] of type int"
88-
)
89-
with pytest.raises(TypeError, match=msg):
85+
with pytest.raises(KeyError, match="^1$"):
9086
df.loc[1]
9187

9288
def test_getitem_scalar(self):

pandas/tests/indexing/test_loc.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class TestLoc(Base):
1616
def test_loc_getitem_int(self):
1717

1818
# int label
19-
self.check_result("loc", 2, typs=["labels"], fails=TypeError)
19+
self.check_result("loc", 2, typs=["labels"], fails=KeyError)
2020

2121
def test_loc_getitem_label(self):
2222

@@ -34,7 +34,7 @@ def test_loc_getitem_label_out_of_range(self):
3434
self.check_result(
3535
"loc", 20, typs=["ints", "uints", "mixed"], fails=KeyError,
3636
)
37-
self.check_result("loc", 20, typs=["labels"], fails=TypeError)
37+
self.check_result("loc", 20, typs=["labels"], fails=KeyError)
3838
self.check_result("loc", 20, typs=["ts"], axes=0, fails=TypeError)
3939
self.check_result("loc", 20, typs=["floats"], axes=0, fails=KeyError)
4040

@@ -967,3 +967,11 @@ def test_loc_set_dataframe_multiindex():
967967
result = expected.copy()
968968
result.loc[0, [(0, 1)]] = result.loc[0, [(0, 1)]]
969969
tm.assert_frame_equal(result, expected)
970+
971+
972+
def test_loc_mixed_int_float():
973+
# GH#19456
974+
ser = pd.Series(range(2), pd.Index([1, 2.0], dtype=object))
975+
976+
result = ser.loc[1]
977+
assert result == 0

pandas/tests/indexing/test_scalar.py

+5-13
Original file line numberDiff line numberDiff line change
@@ -138,30 +138,22 @@ def test_series_at_raises_type_error(self):
138138
result = ser.loc["a"]
139139
assert result == 1
140140

141-
msg = (
142-
"cannot do label indexing on Index "
143-
r"with these indexers \[0\] of type int"
144-
)
145-
with pytest.raises(TypeError, match=msg):
141+
with pytest.raises(KeyError, match="^0$"):
146142
ser.at[0]
147-
with pytest.raises(TypeError, match=msg):
143+
with pytest.raises(KeyError, match="^0$"):
148144
ser.loc[0]
149145

150-
def test_frame_raises_type_error(self):
146+
def test_frame_raises_key_error(self):
151147
# GH#31724 .at should match .loc
152148
df = DataFrame({"A": [1, 2, 3]}, index=list("abc"))
153149
result = df.at["a", "A"]
154150
assert result == 1
155151
result = df.loc["a", "A"]
156152
assert result == 1
157153

158-
msg = (
159-
"cannot do label indexing on Index "
160-
r"with these indexers \[0\] of type int"
161-
)
162-
with pytest.raises(TypeError, match=msg):
154+
with pytest.raises(KeyError, match="^0$"):
163155
df.at["a", 0]
164-
with pytest.raises(TypeError, match=msg):
156+
with pytest.raises(KeyError, match="^0$"):
165157
df.loc["a", 0]
166158

167159
def test_series_at_raises_key_error(self):

0 commit comments

Comments
 (0)