Skip to content

Commit f34fe62

Browse files
authored
Deprecate partial slicing of unordered DatetimeIndex when both keys are not present (#37819)
1 parent d85e9a2 commit f34fe62

File tree

5 files changed

+33
-7
lines changed

5 files changed

+33
-7
lines changed

doc/source/whatsnew/v1.2.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ Deprecations
457457
- :class:`Index` methods ``&``, ``|``, and ``^`` behaving as the set operations :meth:`Index.intersection`, :meth:`Index.union`, and :meth:`Index.symmetric_difference`, respectively, are deprecated and in the future will behave as pointwise boolean operations matching :class:`Series` behavior. Use the named set methods instead (:issue:`36758`)
458458
- :meth:`Categorical.is_dtype_equal` and :meth:`CategoricalIndex.is_dtype_equal` are deprecated, will be removed in a future version (:issue:`37545`)
459459
- :meth:`Series.slice_shift` and :meth:`DataFrame.slice_shift` are deprecated, use :meth:`Series.shift` or :meth:`DataFrame.shift` instead (:issue:`37601`)
460-
460+
- Partial slicing on unordered :class:`DatetimeIndexes` with keys, which are not in Index is deprecated and will be removed in a future version (:issue:`18531`)
461461

462462
.. ---------------------------------------------------------------------------
463463

pandas/core/indexes/datetimes.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -803,14 +803,25 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None):
803803
end is None or isinstance(end, str)
804804
):
805805
mask = np.array(True)
806+
deprecation_mask = np.array(True)
806807
if start is not None:
807808
start_casted = self._maybe_cast_slice_bound(start, "left", kind)
808809
mask = start_casted <= self
810+
deprecation_mask = start_casted == self
809811

810812
if end is not None:
811813
end_casted = self._maybe_cast_slice_bound(end, "right", kind)
812814
mask = (self <= end_casted) & mask
813-
815+
deprecation_mask = (end_casted == self) | deprecation_mask
816+
817+
if not deprecation_mask.any():
818+
warnings.warn(
819+
"Value based partial slicing on non-monotonic DatetimeIndexes "
820+
"with non-existing keys is deprecated and will raise a "
821+
"KeyError in a future Version.",
822+
FutureWarning,
823+
stacklevel=5,
824+
)
814825
indexer = mask.nonzero()[0][::step]
815826
if len(indexer) == len(self):
816827
return slice(None)

pandas/tests/indexes/datetimes/test_partial_slicing.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -312,17 +312,22 @@ def test_partial_slicing_with_multiindex(self):
312312

313313
def test_partial_slice_doesnt_require_monotonicity(self):
314314
# For historical reasons.
315-
s = Series(np.arange(10), date_range("2014-01-01", periods=10))
315+
ser = Series(np.arange(10), date_range("2014-01-01", periods=10))
316316

317-
nonmonotonic = s[[3, 5, 4]]
317+
nonmonotonic = ser[[3, 5, 4]]
318318
expected = nonmonotonic.iloc[:0]
319319
timestamp = Timestamp("2014-01-10")
320+
with tm.assert_produces_warning(FutureWarning):
321+
result = nonmonotonic["2014-01-10":]
322+
tm.assert_series_equal(result, expected)
320323

321-
tm.assert_series_equal(nonmonotonic["2014-01-10":], expected)
322324
with pytest.raises(KeyError, match=r"Timestamp\('2014-01-10 00:00:00'\)"):
323325
nonmonotonic[timestamp:]
324326

325-
tm.assert_series_equal(nonmonotonic.loc["2014-01-10":], expected)
327+
with tm.assert_produces_warning(FutureWarning):
328+
result = nonmonotonic.loc["2014-01-10":]
329+
tm.assert_series_equal(result, expected)
330+
326331
with pytest.raises(KeyError, match=r"Timestamp\('2014-01-10 00:00:00'\)"):
327332
nonmonotonic.loc[timestamp:]
328333

pandas/tests/indexing/test_loc.py

+9
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,15 @@ def test_loc_getitem_slice_label_td64obj(self, start, stop, expected_slice):
15641564
expected = ser.iloc[expected_slice]
15651565
tm.assert_series_equal(result, expected)
15661566

1567+
@pytest.mark.parametrize("start", ["2018", "2020"])
1568+
def test_loc_getitem_slice_unordered_dt_index(self, frame_or_series, start):
1569+
obj = frame_or_series(
1570+
[1, 2, 3],
1571+
index=[Timestamp("2016"), Timestamp("2019"), Timestamp("2017")],
1572+
)
1573+
with tm.assert_produces_warning(FutureWarning):
1574+
obj.loc[start:"2022"]
1575+
15671576

15681577
class TestLocBooleanMask:
15691578
def test_loc_setitem_bool_mask_timedeltaindex(self):

pandas/tests/series/indexing/test_datetime.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,8 @@ def compare(slobj):
526526
tm.assert_series_equal(result, expected)
527527

528528
compare(slice("2011-01-01", "2011-01-15"))
529-
compare(slice("2010-12-30", "2011-01-15"))
529+
with tm.assert_produces_warning(FutureWarning):
530+
compare(slice("2010-12-30", "2011-01-15"))
530531
compare(slice("2011-01-01", "2011-01-16"))
531532

532533
# partial ranges

0 commit comments

Comments
 (0)