Skip to content

Commit

Permalink
DEPR: Index.get_loc with method (#42269)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored Jul 1, 2021
1 parent 0469d1e commit 4dc6785
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 16 deletions.
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 @@ -3358,6 +3358,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 @@ -4948,14 +4957,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

0 comments on commit 4dc6785

Please sign in to comment.