Skip to content

Commit 71b6833

Browse files
jbrockmendeljreback
authored andcommitted
REF/BUG: Index.get_value called incorrectly, de-duplicate+simplify (#31134)
1 parent eb492a2 commit 71b6833

File tree

5 files changed

+43
-44
lines changed

5 files changed

+43
-44
lines changed

pandas/core/indexes/base.py

+25-34
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
from pandas.core.arrays import ExtensionArray
6969
from pandas.core.base import IndexOpsMixin, PandasObject
7070
import pandas.core.common as com
71-
from pandas.core.construction import extract_array
7271
from pandas.core.indexers import maybe_convert_indices
7372
from pandas.core.indexes.frozen import FrozenList
7473
import pandas.core.missing as missing
@@ -4627,48 +4626,40 @@ def get_value(self, series, key):
46274626
# would convert to numpy arrays and raise later any way) - GH29926
46284627
raise InvalidIndexError(key)
46294628

4630-
# if we have something that is Index-like, then
4631-
# use this, e.g. DatetimeIndex
4632-
# Things like `Series._get_value` (via .at) pass the EA directly here.
4633-
s = extract_array(series, extract_numpy=True)
4634-
if isinstance(s, ExtensionArray):
4629+
try:
46354630
# GH 20882, 21257
46364631
# First try to convert the key to a location
46374632
# If that fails, raise a KeyError if an integer
46384633
# index, otherwise, see if key is an integer, and
46394634
# try that
4640-
try:
4641-
iloc = self.get_loc(key)
4642-
return s[iloc]
4643-
except KeyError:
4644-
if len(self) > 0 and (self.holds_integer() or self.is_boolean()):
4645-
raise
4646-
elif is_integer(key):
4647-
return s[key]
4648-
4649-
k = self._convert_scalar_indexer(key, kind="getitem")
4650-
try:
4651-
loc = self._engine.get_loc(k)
4652-
4653-
except KeyError as e1:
4635+
loc = self._engine.get_loc(key)
4636+
except KeyError:
46544637
if len(self) > 0 and (self.holds_integer() or self.is_boolean()):
46554638
raise
4656-
4657-
try:
4658-
return libindex.get_value_at(s, key)
4659-
except IndexError:
4639+
elif is_integer(key):
4640+
# If the Index cannot hold integer, then this is unambiguously
4641+
# a locational lookup.
4642+
loc = key
4643+
else:
46604644
raise
4661-
except Exception:
4662-
raise e1
4663-
except TypeError:
4664-
# e.g. "[False] is an invalid key"
4665-
raise IndexError(key)
46664645

4667-
else:
4668-
if is_scalar(loc):
4669-
tz = getattr(series.dtype, "tz", None)
4670-
return libindex.get_value_at(s, loc, tz=tz)
4671-
return series.iloc[loc]
4646+
return self._get_values_for_loc(series, loc)
4647+
4648+
def _get_values_for_loc(self, series, loc):
4649+
"""
4650+
Do a positional lookup on the given Series, returning either a scalar
4651+
or a Series.
4652+
4653+
Assumes that `series.index is self`
4654+
"""
4655+
if is_integer(loc):
4656+
if isinstance(series._values, np.ndarray):
4657+
# Since we have an ndarray and not DatetimeArray, we dont
4658+
# have to worry about a tz.
4659+
return libindex.get_value_at(series._values, loc, tz=None)
4660+
return series._values[loc]
4661+
4662+
return series.iloc[loc]
46724663

46734664
def set_value(self, arr, key, value):
46744665
"""

pandas/core/indexes/datetimes.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -667,9 +667,8 @@ def get_value(self, series, key):
667667
return com.maybe_box(self, value, series, key)
668668

669669
def get_value_maybe_box(self, series, key):
670-
key = self._maybe_cast_for_get_loc(key)
671-
values = self._engine.get_value(com.values_from_object(series), key, tz=self.tz)
672-
return com.maybe_box(self, values, series, key)
670+
loc = self.get_loc(key)
671+
return self._get_values_for_loc(series, loc)
673672

674673
def get_loc(self, key, method=None, tolerance=None):
675674
"""

pandas/core/indexes/timedeltas.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,8 @@ def get_value(self, series, key):
259259
return com.maybe_box(self, value, series, key)
260260

261261
def get_value_maybe_box(self, series, key: Timedelta):
262-
values = self._engine.get_value(com.values_from_object(series), key)
263-
return com.maybe_box(self, values, series, key)
262+
loc = self.get_loc(key)
263+
return self._get_values_for_loc(series, loc)
264264

265265
def get_loc(self, key, method=None, tolerance=None):
266266
"""

pandas/tests/indexes/datetimes/test_indexing.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -621,17 +621,21 @@ def test_get_value(self):
621621
# specifically make sure we have test for np.datetime64 key
622622
dti = pd.date_range("2016-01-01", periods=3)
623623

624-
arr = np.arange(6, 8)
624+
arr = np.arange(6, 9)
625+
ser = pd.Series(arr, index=dti)
625626

626627
key = dti[1]
627628

628-
result = dti.get_value(arr, key)
629+
with pytest.raises(AttributeError, match="has no attribute '_values'"):
630+
dti.get_value(arr, key)
631+
632+
result = dti.get_value(ser, key)
629633
assert result == 7
630634

631-
result = dti.get_value(arr, key.to_pydatetime())
635+
result = dti.get_value(ser, key.to_pydatetime())
632636
assert result == 7
633637

634-
result = dti.get_value(arr, key.to_datetime64())
638+
result = dti.get_value(ser, key.to_datetime64())
635639
assert result == 7
636640

637641
def test_get_loc(self):

pandas/tests/indexes/test_base.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -1915,7 +1915,12 @@ def test_get_value(self, index):
19151915
values = np.random.randn(100)
19161916
value = index[67]
19171917

1918-
tm.assert_almost_equal(index.get_value(values, value), values[67])
1918+
with pytest.raises(AttributeError, match="has no attribute '_values'"):
1919+
# Index.get_value requires a Series, not an ndarray
1920+
index.get_value(values, value)
1921+
1922+
result = index.get_value(Series(values, index=values), value)
1923+
tm.assert_almost_equal(result, values[67])
19191924

19201925
@pytest.mark.parametrize("values", [["foo", "bar", "quux"], {"foo", "bar", "quux"}])
19211926
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)