Skip to content

Commit bc987e7

Browse files
authored
DEPR: Remove method and tolerance in Index.get_loc, bump xarray (pandas-dev#49630)
* DEPR: Remove method and tolerance in Index.get_loc * note xarray bump * Fix tests * Fix refactor in period * Lighter parameterization * xfail xarray test * Just use get_indexer
1 parent 078c024 commit bc987e7

File tree

18 files changed

+80
-403
lines changed

18 files changed

+80
-403
lines changed

ci/deps/actions-38-minimum_versions.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ dependencies:
5454
- sqlalchemy=1.4.16
5555
- tabulate=0.8.9
5656
- tzdata=2022a
57-
- xarray=0.19.0
57+
- xarray=0.21.0
5858
- xlrd=2.0.1
5959
- xlsxwriter=1.4.3
6060
- zstandard=0.15.2

doc/source/getting_started/install.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ Installable with ``pip install "pandas[computation]"``.
333333
Dependency Minimum Version pip extra Notes
334334
========================= ================== =============== =============================================================
335335
SciPy 1.7.1 computation Miscellaneous statistical functions
336-
xarray 0.19.0 computation pandas-like API for N-dimensional data
336+
xarray 0.21.0 computation pandas-like API for N-dimensional data
337337
========================= ================== =============== =============================================================
338338

339339
Excel files

doc/source/whatsnew/v2.0.0.rst

+3
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ Optional libraries below the lowest tested version may still work, but are not c
339339
+-----------------+-----------------+---------+
340340
| fastparquet | 0.6.3 | X |
341341
+-----------------+-----------------+---------+
342+
| xarray | 0.21.0 | X |
343+
+-----------------+-----------------+---------+
342344

343345
See :ref:`install.dependencies` and :ref:`install.optional_dependencies` for more.
344346

@@ -521,6 +523,7 @@ Removal of prior version deprecations/changes
521523
- Removed the ``closed`` argument in :meth:`date_range` and :meth:`bdate_range` in favor of ``inclusive`` argument (:issue:`40245`)
522524
- Removed the ``center`` keyword in :meth:`DataFrame.expanding` (:issue:`20647`)
523525
- Removed the ``truediv`` keyword from :func:`eval` (:issue:`29812`)
526+
- Removed the ``method`` and ``tolerance`` arguments in :meth:`Index.get_loc`. Use ``index.get_indexer([label], method=..., tolerance=...)`` instead (:issue:`42269`)
524527
- Removed the ``pandas.datetime`` submodule (:issue:`30489`)
525528
- Removed the ``pandas.np`` submodule (:issue:`30296`)
526529
- Removed ``pandas.util.testing`` in favor of ``pandas.testing`` (:issue:`30745`)

pandas/compat/_optional.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"sqlalchemy": "1.4.16",
4242
"tables": "3.6.1",
4343
"tabulate": "0.8.9",
44-
"xarray": "0.19.0",
44+
"xarray": "0.21.0",
4545
"xlrd": "2.0.1",
4646
"xlsxwriter": "1.4.3",
4747
"zstandard": "0.15.2",

pandas/core/indexes/base.py

+12-55
Original file line numberDiff line numberDiff line change
@@ -3429,27 +3429,13 @@ def _convert_can_do_setop(self, other) -> tuple[Index, Hashable]:
34293429
# --------------------------------------------------------------------
34303430
# Indexing Methods
34313431

3432-
def get_loc(self, key, method=None, tolerance=None):
3432+
def get_loc(self, key):
34333433
"""
34343434
Get integer location, slice or boolean mask for requested label.
34353435
34363436
Parameters
34373437
----------
34383438
key : label
3439-
method : {None, 'pad'/'ffill', 'backfill'/'bfill', 'nearest'}, optional
3440-
* default: exact matches only.
3441-
* pad / ffill: find the PREVIOUS index value if no exact match.
3442-
* backfill / bfill: use NEXT index value if no exact match
3443-
* nearest: use the NEAREST index value if no exact match. Tied
3444-
distances are broken by preferring the larger index value.
3445-
3446-
.. deprecated:: 1.4
3447-
Use index.get_indexer([item], method=...) instead.
3448-
3449-
tolerance : int or float, optional
3450-
Maximum distance from index value for inexact matches. The value of
3451-
the index at the matching location must satisfy the equation
3452-
``abs(index[loc] - key) <= tolerance``.
34533439
34543440
Returns
34553441
-------
@@ -3469,46 +3455,17 @@ def get_loc(self, key, method=None, tolerance=None):
34693455
>>> non_monotonic_index.get_loc('b')
34703456
array([False, True, False, True])
34713457
"""
3472-
if method is None:
3473-
if tolerance is not None:
3474-
raise ValueError(
3475-
"tolerance argument only valid if using pad, "
3476-
"backfill or nearest lookups"
3477-
)
3478-
casted_key = self._maybe_cast_indexer(key)
3479-
try:
3480-
return self._engine.get_loc(casted_key)
3481-
except KeyError as err:
3482-
raise KeyError(key) from err
3483-
except TypeError:
3484-
# If we have a listlike key, _check_indexing_error will raise
3485-
# InvalidIndexError. Otherwise we fall through and re-raise
3486-
# the TypeError.
3487-
self._check_indexing_error(key)
3488-
raise
3489-
3490-
# GH#42269
3491-
warnings.warn(
3492-
f"Passing method to {type(self).__name__}.get_loc is deprecated "
3493-
"and will raise in a future version. Use "
3494-
"index.get_indexer([item], method=...) instead.",
3495-
FutureWarning,
3496-
stacklevel=find_stack_level(),
3497-
)
3498-
3499-
if is_scalar(key) and isna(key) and not self.hasnans:
3500-
raise KeyError(key)
3501-
3502-
if tolerance is not None:
3503-
tolerance = self._convert_tolerance(tolerance, np.asarray(key))
3504-
3505-
indexer = self.get_indexer([key], method=method, tolerance=tolerance)
3506-
if indexer.ndim > 1 or indexer.size > 1:
3507-
raise TypeError("get_loc requires scalar valued input")
3508-
loc = indexer.item()
3509-
if loc == -1:
3510-
raise KeyError(key)
3511-
return loc
3458+
casted_key = self._maybe_cast_indexer(key)
3459+
try:
3460+
return self._engine.get_loc(casted_key)
3461+
except KeyError as err:
3462+
raise KeyError(key) from err
3463+
except TypeError:
3464+
# If we have a listlike key, _check_indexing_error will raise
3465+
# InvalidIndexError. Otherwise we fall through and re-raise
3466+
# the TypeError.
3467+
self._check_indexing_error(key)
3468+
raise
35123469

35133470
_index_shared_docs[
35143471
"get_indexer"

pandas/core/indexes/datetimes.py

+3-8
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ def _disallow_mismatched_indexing(self, key) -> None:
556556
except TypeError as err:
557557
raise KeyError(key) from err
558558

559-
def get_loc(self, key, method=None, tolerance=None):
559+
def get_loc(self, key):
560560
"""
561561
Get integer location for requested label
562562
@@ -587,8 +587,7 @@ def get_loc(self, key, method=None, tolerance=None):
587587
try:
588588
return self._partial_date_slice(reso, parsed)
589589
except KeyError as err:
590-
if method is None:
591-
raise KeyError(key) from err
590+
raise KeyError(key) from err
592591

593592
key = parsed
594593

@@ -599,18 +598,14 @@ def get_loc(self, key, method=None, tolerance=None):
599598
)
600599

601600
elif isinstance(key, dt.time):
602-
if method is not None:
603-
raise NotImplementedError(
604-
"cannot yet lookup inexact labels when key is a time object"
605-
)
606601
return self.indexer_at_time(key)
607602

608603
else:
609604
# unrecognized type
610605
raise KeyError(key)
611606

612607
try:
613-
return Index.get_loc(self, key, method, tolerance)
608+
return Index.get_loc(self, key)
614609
except KeyError as err:
615610
raise KeyError(orig_key) from err
616611

pandas/core/indexes/multi.py

+1-8
Original file line numberDiff line numberDiff line change
@@ -2730,7 +2730,7 @@ def _get_loc_single_level_index(self, level_index: Index, key: Hashable) -> int:
27302730
else:
27312731
return level_index.get_loc(key)
27322732

2733-
def get_loc(self, key, method=None):
2733+
def get_loc(self, key):
27342734
"""
27352735
Get location for a label or a tuple of labels.
27362736
@@ -2740,7 +2740,6 @@ def get_loc(self, key, method=None):
27402740
Parameters
27412741
----------
27422742
key : label or tuple of labels (one for each level)
2743-
method : None
27442743
27452744
Returns
27462745
-------
@@ -2772,12 +2771,6 @@ def get_loc(self, key, method=None):
27722771
>>> mi.get_loc(('b', 'e'))
27732772
1
27742773
"""
2775-
if method is not None:
2776-
raise NotImplementedError(
2777-
"only the default get_loc method is "
2778-
"currently supported for MultiIndex"
2779-
)
2780-
27812774
self._check_indexing_error(key)
27822775

27832776
def _maybe_to_slice(loc):

pandas/core/indexes/period.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ def _convert_tolerance(self, tolerance, target):
375375

376376
return tolerance
377377

378-
def get_loc(self, key, method=None, tolerance=None):
378+
def get_loc(self, key):
379379
"""
380380
Get integer location for requested label.
381381
@@ -421,10 +421,8 @@ def get_loc(self, key, method=None, tolerance=None):
421421
# the reso < self._resolution_obj case goes
422422
# through _get_string_slice
423423
key = self._cast_partial_indexing_scalar(parsed)
424-
elif method is None:
425-
raise KeyError(key)
426424
else:
427-
key = self._cast_partial_indexing_scalar(parsed)
425+
raise KeyError(key)
428426

429427
elif isinstance(key, Period):
430428
self._disallow_mismatched_indexing(key)
@@ -437,7 +435,7 @@ def get_loc(self, key, method=None, tolerance=None):
437435
raise KeyError(key)
438436

439437
try:
440-
return Index.get_loc(self, key, method, tolerance)
438+
return Index.get_loc(self, key)
441439
except KeyError as err:
442440
raise KeyError(orig_key) from err
443441

pandas/core/indexes/range.py

+9-11
Original file line numberDiff line numberDiff line change
@@ -328,17 +328,15 @@ def inferred_type(self) -> str:
328328
# Indexing Methods
329329

330330
@doc(Int64Index.get_loc)
331-
def get_loc(self, key, method=None, tolerance=None):
332-
if method is None and tolerance is None:
333-
if is_integer(key) or (is_float(key) and key.is_integer()):
334-
new_key = int(key)
335-
try:
336-
return self._range.index(new_key)
337-
except ValueError as err:
338-
raise KeyError(key) from err
339-
self._check_indexing_error(key)
340-
raise KeyError(key)
341-
return super().get_loc(key, method=method, tolerance=tolerance)
331+
def get_loc(self, key):
332+
if is_integer(key) or (is_float(key) and key.is_integer()):
333+
new_key = int(key)
334+
try:
335+
return self._range.index(new_key)
336+
except ValueError as err:
337+
raise KeyError(key) from err
338+
self._check_indexing_error(key)
339+
raise KeyError(key)
342340

343341
def _get_indexer(
344342
self,

pandas/core/indexes/timedeltas.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def _is_comparable_dtype(self, dtype: DtypeObj) -> bool:
174174
# -------------------------------------------------------------------
175175
# Indexing Methods
176176

177-
def get_loc(self, key, method=None, tolerance=None):
177+
def get_loc(self, key):
178178
"""
179179
Get integer location for requested label
180180
@@ -189,7 +189,7 @@ def get_loc(self, key, method=None, tolerance=None):
189189
except TypeError as err:
190190
raise KeyError(key) from err
191191

192-
return Index.get_loc(self, key, method, tolerance)
192+
return Index.get_loc(self, key)
193193

194194
def _parse_with_reso(self, label: str):
195195
# the "with_reso" is a no-op for TimedeltaIndex

pandas/tests/indexes/datetimes/test_indexing.py

-88
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
import numpy as np
99
import pytest
1010

11-
from pandas.errors import InvalidIndexError
12-
1311
import pandas as pd
1412
from pandas import (
1513
DatetimeIndex,
@@ -405,75 +403,6 @@ def test_get_loc_key_unit_mismatch_not_castable(self):
405403

406404
assert key not in dti
407405

408-
@pytest.mark.parametrize("method", [None, "pad", "backfill", "nearest"])
409-
@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
410-
def test_get_loc_method_exact_match(self, method):
411-
idx = date_range("2000-01-01", periods=3)
412-
assert idx.get_loc(idx[1], method) == 1
413-
assert idx.get_loc(idx[1].to_pydatetime(), method) == 1
414-
assert idx.get_loc(str(idx[1]), method) == 1
415-
416-
if method is not None:
417-
assert idx.get_loc(idx[1], method, tolerance=pd.Timedelta("0 days")) == 1
418-
419-
@pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
420-
def test_get_loc(self):
421-
idx = date_range("2000-01-01", periods=3)
422-
423-
assert idx.get_loc("2000-01-01", method="nearest") == 0
424-
assert idx.get_loc("2000-01-01T12", method="nearest") == 1
425-
426-
assert idx.get_loc("2000-01-01T12", method="nearest", tolerance="1 day") == 1
427-
assert (
428-
idx.get_loc("2000-01-01T12", method="nearest", tolerance=pd.Timedelta("1D"))
429-
== 1
430-
)
431-
assert (
432-
idx.get_loc(
433-
"2000-01-01T12", method="nearest", tolerance=np.timedelta64(1, "D")
434-
)
435-
== 1
436-
)
437-
assert (
438-
idx.get_loc("2000-01-01T12", method="nearest", tolerance=timedelta(1)) == 1
439-
)
440-
with pytest.raises(ValueError, match="unit abbreviation w/o a number"):
441-
idx.get_loc("2000-01-01T12", method="nearest", tolerance="foo")
442-
with pytest.raises(KeyError, match="'2000-01-01T03'"):
443-
idx.get_loc("2000-01-01T03", method="nearest", tolerance="2 hours")
444-
with pytest.raises(
445-
ValueError, match="tolerance size must match target index size"
446-
):
447-
idx.get_loc(
448-
"2000-01-01",
449-
method="nearest",
450-
tolerance=[
451-
pd.Timedelta("1day").to_timedelta64(),
452-
pd.Timedelta("1day").to_timedelta64(),
453-
],
454-
)
455-
456-
assert idx.get_loc("2000", method="nearest") == slice(0, 3)
457-
assert idx.get_loc("2000-01", method="nearest") == slice(0, 3)
458-
459-
assert idx.get_loc("1999", method="nearest") == 0
460-
assert idx.get_loc("2001", method="nearest") == 2
461-
462-
with pytest.raises(KeyError, match="'1999'"):
463-
idx.get_loc("1999", method="pad")
464-
with pytest.raises(KeyError, match="'2001'"):
465-
idx.get_loc("2001", method="backfill")
466-
467-
with pytest.raises(KeyError, match="'foobar'"):
468-
idx.get_loc("foobar")
469-
with pytest.raises(InvalidIndexError, match=r"slice\(None, 2, None\)"):
470-
idx.get_loc(slice(2))
471-
472-
idx = DatetimeIndex(["2000-01-01", "2000-01-04"])
473-
assert idx.get_loc("2000-01-02", method="nearest") == 0
474-
assert idx.get_loc("2000-01-03", method="nearest") == 1
475-
assert idx.get_loc("2000-01", method="nearest") == slice(0, 2)
476-
477406
def test_get_loc_time_obj(self):
478407
# time indexing
479408
idx = date_range("2000-01-01", periods=24, freq="H")
@@ -486,11 +415,6 @@ def test_get_loc_time_obj(self):
486415
expected = np.array([])
487416
tm.assert_numpy_array_equal(result, expected, check_dtype=False)
488417

489-
msg = "cannot yet lookup inexact labels when key is a time object"
490-
with pytest.raises(NotImplementedError, match=msg):
491-
with tm.assert_produces_warning(FutureWarning, match="deprecated"):
492-
idx.get_loc(time(12, 30), method="pad")
493-
494418
def test_get_loc_time_obj2(self):
495419
# GH#8667
496420

@@ -525,18 +449,6 @@ def test_get_loc_time_nat(self):
525449
expected = np.array([], dtype=np.intp)
526450
tm.assert_numpy_array_equal(loc, expected)
527451

528-
def test_get_loc_tz_aware(self):
529-
# https://github.com/pandas-dev/pandas/issues/32140
530-
dti = date_range(
531-
Timestamp("2019-12-12 00:00:00", tz="US/Eastern"),
532-
Timestamp("2019-12-13 00:00:00", tz="US/Eastern"),
533-
freq="5s",
534-
)
535-
key = Timestamp("2019-12-12 10:19:25", tz="US/Eastern")
536-
with tm.assert_produces_warning(FutureWarning, match="deprecated"):
537-
result = dti.get_loc(key, method="nearest")
538-
assert result == 7433
539-
540452
def test_get_loc_nat(self):
541453
# GH#20464
542454
index = DatetimeIndex(["1/3/2000", "NaT"])

0 commit comments

Comments
 (0)