Skip to content

DEPR: Index.get_loc with method #42269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Other API changes
Deprecations
~~~~~~~~~~~~
- Deprecated :meth:`Index.is_type_compatible` (:issue:`42113`)
-
- Deprecated ``method`` argument in :meth:`Index.get_loc`, use ``index.get_indexer([label], method=...)`` instead (:issue:`42269`)

.. ---------------------------------------------------------------------------

Expand Down
27 changes: 23 additions & 4 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3328,6 +3328,15 @@ def get_loc(self, key, method=None, tolerance=None):
except KeyError as err:
raise KeyError(key) from err

# GH#42269
warnings.warn(
f"Passing method to {type(self).__name__}.get_loc is deprecated "
"and will raise in a future version. Use "
"index.get_indexer([item], method=...) instead",
FutureWarning,
stacklevel=2,
)

if is_scalar(key) and isna(key) and not self.hasnans:
raise KeyError(key)

Expand Down Expand Up @@ -4896,14 +4905,24 @@ def asof(self, label):
Traceback (most recent call last):
ValueError: index must be monotonic increasing or decreasing
"""
self._searchsorted_monotonic(label) # validate sortedness
try:
loc = self.get_loc(label, method="pad")
except KeyError:
return self._na_value
loc = self.get_loc(label)
except (KeyError, TypeError):
# KeyError -> No exact match, try for padded
# TypeError -> passed e.g. non-hashable, fall through to get
# the tested exception message
indexer = self.get_indexer([label], method="pad")
if indexer.ndim > 1 or indexer.size > 1:
raise TypeError("asof requires scalar valued input")
loc = indexer.item()
if loc == -1:
return self._na_value
else:
if isinstance(loc, slice):
loc = loc.indices(len(self))[-1]
return self[loc]

return self[loc]

def asof_locs(self, where: Index, mask: np.ndarray) -> np.ndarray:
"""
Expand Down
10 changes: 8 additions & 2 deletions pandas/tests/indexes/datetimes/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ def test_take_fill_value_with_timezone(self):

class TestGetLoc:
@pytest.mark.parametrize("method", [None, "pad", "backfill", "nearest"])
@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
def test_get_loc_method_exact_match(self, method):
idx = date_range("2000-01-01", periods=3)
assert idx.get_loc(idx[1], method) == 1
Expand All @@ -431,6 +432,7 @@ def test_get_loc_method_exact_match(self, method):
if method is not None:
assert idx.get_loc(idx[1], method, tolerance=pd.Timedelta("0 days")) == 1

@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
def test_get_loc(self):
idx = date_range("2000-01-01", periods=3)

Expand Down Expand Up @@ -498,7 +500,8 @@ def test_get_loc(self):
)
msg = "cannot yet lookup inexact labels when key is a time object"
with pytest.raises(NotImplementedError, match=msg):
idx.get_loc(time(12, 30), method="pad")
with tm.assert_produces_warning(FutureWarning, match="deprecated"):
idx.get_loc(time(12, 30), method="pad")

def test_get_loc_time_nat(self):
# GH#35114
Expand All @@ -518,7 +521,10 @@ def test_get_loc_tz_aware(self):
freq="5s",
)
key = Timestamp("2019-12-12 10:19:25", tz="US/Eastern")
result = dti.get_loc(key, method="nearest")
with tm.assert_produces_warning(
FutureWarning, match="deprecated", check_stacklevel=False
):
result = dti.get_loc(key, method="nearest")
assert result == 7433

def test_get_loc_nat(self):
Expand Down
23 changes: 17 additions & 6 deletions pandas/tests/indexes/numeric/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ class TestGetLoc:
@pytest.mark.parametrize("method", [None, "pad", "backfill", "nearest"])
def test_get_loc(self, method):
index = Index([0, 1, 2])
assert index.get_loc(1, method=method) == 1
warn = None if method is None else FutureWarning

with tm.assert_produces_warning(warn, match="deprecated"):
assert index.get_loc(1, method=method) == 1

if method:
assert index.get_loc(1, method=method, tolerance=0) == 1
with tm.assert_produces_warning(warn, match="deprecated"):
assert index.get_loc(1, method=method, tolerance=0) == 1

@pytest.mark.parametrize("method", [None, "pad", "backfill", "nearest"])
@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
def test_get_loc_raises_bad_label(self, method):
index = Index([0, 1, 2])
if method:
Expand All @@ -43,6 +48,7 @@ def test_get_loc_raises_bad_label(self, method):
@pytest.mark.parametrize(
"method,loc", [("pad", 1), ("backfill", 2), ("nearest", 1)]
)
@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
def test_get_loc_tolerance(self, method, loc):
index = Index([0, 1, 2])
assert index.get_loc(1.1, method) == loc
Expand All @@ -52,12 +58,14 @@ def test_get_loc_tolerance(self, method, loc):
def test_get_loc_outside_tolerance_raises(self, method):
index = Index([0, 1, 2])
with pytest.raises(KeyError, match="1.1"):
index.get_loc(1.1, method, tolerance=0.05)
with tm.assert_produces_warning(FutureWarning, match="deprecated"):
index.get_loc(1.1, method, tolerance=0.05)

def test_get_loc_bad_tolerance_raises(self):
index = Index([0, 1, 2])
with pytest.raises(ValueError, match="must be numeric"):
index.get_loc(1.1, "nearest", tolerance="invalid")
with tm.assert_produces_warning(FutureWarning, match="deprecated"):
index.get_loc(1.1, "nearest", tolerance="invalid")

def test_get_loc_tolerance_no_method_raises(self):
index = Index([0, 1, 2])
Expand All @@ -67,8 +75,10 @@ def test_get_loc_tolerance_no_method_raises(self):
def test_get_loc_raises_missized_tolerance(self):
index = Index([0, 1, 2])
with pytest.raises(ValueError, match="tolerance size must match"):
index.get_loc(1.1, "nearest", tolerance=[1, 1])
with tm.assert_produces_warning(FutureWarning, match="deprecated"):
index.get_loc(1.1, "nearest", tolerance=[1, 1])

@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
def test_get_loc_float64(self):
idx = Float64Index([0.0, 1.0, 2.0])
for method in [None, "pad", "backfill", "nearest"]:
Expand Down Expand Up @@ -139,7 +149,8 @@ def test_get_loc_float_index_nan_with_method(self, vals, method):
# GH#39382
idx = Index(vals)
with pytest.raises(KeyError, match="nan"):
idx.get_loc(np.nan, method=method)
with tm.assert_produces_warning(FutureWarning, match="deprecated"):
idx.get_loc(np.nan, method=method)


class TestGetIndexer:
Expand Down
6 changes: 4 additions & 2 deletions pandas/tests/indexes/object/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ class TestGetLoc:
def test_get_loc_raises_object_nearest(self):
index = Index(["a", "c"])
with pytest.raises(TypeError, match="unsupported operand type"):
index.get_loc("a", method="nearest")
with tm.assert_produces_warning(FutureWarning, match="deprecated"):
index.get_loc("a", method="nearest")

def test_get_loc_raises_object_tolerance(self):
index = Index(["a", "c"])
with pytest.raises(TypeError, match="unsupported operand type"):
index.get_loc("a", method="pad", tolerance="invalid")
with tm.assert_produces_warning(FutureWarning, match="deprecated"):
index.get_loc("a", method="pad", tolerance="invalid")


class TestGetIndexer:
Expand Down
2 changes: 2 additions & 0 deletions pandas/tests/indexes/period/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ def test_get_loc_integer(self):

# TODO: This method came from test_period; de-dup with version above
@pytest.mark.parametrize("method", [None, "pad", "backfill", "nearest"])
@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
def test_get_loc_method(self, method):
idx = period_range("2000-01-01", periods=3)

Expand All @@ -352,6 +353,7 @@ def test_get_loc_method(self, method):
idx.get_loc(key, method=method)

# TODO: This method came from test_period; de-dup with version above
@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
def test_get_loc3(self):

idx = period_range("2000-01-01", periods=5)[::2]
Expand Down
1 change: 1 addition & 0 deletions pandas/tests/indexes/timedeltas/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def test_timestamp_invalid_key(self, key):


class TestGetLoc:
@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
def test_get_loc(self):
idx = to_timedelta(["0 days", "1 days", "2 days"])

Expand Down
6 changes: 5 additions & 1 deletion pandas/tests/test_downstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ def test_xarray_cftimeindex_nearest():
import xarray

times = xarray.cftime_range("0001", periods=2)
result = times.get_loc(cftime.DatetimeGregorian(2000, 1, 1), method="nearest")
key = cftime.DatetimeGregorian(2000, 1, 1)
with tm.assert_produces_warning(
FutureWarning, match="deprecated", check_stacklevel=False
):
result = times.get_loc(key, method="nearest")
expected = 1
assert result == expected

Expand Down