Skip to content

Commit

Permalink
Deprecate partial slicing of unordered DatetimeIndex when both keys a…
Browse files Browse the repository at this point in the history
…re not present (#37819)
  • Loading branch information
phofl committed Nov 15, 2020
1 parent d85e9a2 commit f34fe62
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 7 deletions.
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ Deprecations
- :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`)
- :meth:`Categorical.is_dtype_equal` and :meth:`CategoricalIndex.is_dtype_equal` are deprecated, will be removed in a future version (:issue:`37545`)
- :meth:`Series.slice_shift` and :meth:`DataFrame.slice_shift` are deprecated, use :meth:`Series.shift` or :meth:`DataFrame.shift` instead (:issue:`37601`)

- 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`)

.. ---------------------------------------------------------------------------
Expand Down
13 changes: 12 additions & 1 deletion pandas/core/indexes/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,14 +803,25 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None):
end is None or isinstance(end, str)
):
mask = np.array(True)
deprecation_mask = np.array(True)
if start is not None:
start_casted = self._maybe_cast_slice_bound(start, "left", kind)
mask = start_casted <= self
deprecation_mask = start_casted == self

if end is not None:
end_casted = self._maybe_cast_slice_bound(end, "right", kind)
mask = (self <= end_casted) & mask

deprecation_mask = (end_casted == self) | deprecation_mask

if not deprecation_mask.any():
warnings.warn(
"Value based partial slicing on non-monotonic DatetimeIndexes "
"with non-existing keys is deprecated and will raise a "
"KeyError in a future Version.",
FutureWarning,
stacklevel=5,
)
indexer = mask.nonzero()[0][::step]
if len(indexer) == len(self):
return slice(None)
Expand Down
13 changes: 9 additions & 4 deletions pandas/tests/indexes/datetimes/test_partial_slicing.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,17 +312,22 @@ def test_partial_slicing_with_multiindex(self):

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

nonmonotonic = s[[3, 5, 4]]
nonmonotonic = ser[[3, 5, 4]]
expected = nonmonotonic.iloc[:0]
timestamp = Timestamp("2014-01-10")
with tm.assert_produces_warning(FutureWarning):
result = nonmonotonic["2014-01-10":]
tm.assert_series_equal(result, expected)

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

tm.assert_series_equal(nonmonotonic.loc["2014-01-10":], expected)
with tm.assert_produces_warning(FutureWarning):
result = nonmonotonic.loc["2014-01-10":]
tm.assert_series_equal(result, expected)

with pytest.raises(KeyError, match=r"Timestamp\('2014-01-10 00:00:00'\)"):
nonmonotonic.loc[timestamp:]

Expand Down
9 changes: 9 additions & 0 deletions pandas/tests/indexing/test_loc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1564,6 +1564,15 @@ def test_loc_getitem_slice_label_td64obj(self, start, stop, expected_slice):
expected = ser.iloc[expected_slice]
tm.assert_series_equal(result, expected)

@pytest.mark.parametrize("start", ["2018", "2020"])
def test_loc_getitem_slice_unordered_dt_index(self, frame_or_series, start):
obj = frame_or_series(
[1, 2, 3],
index=[Timestamp("2016"), Timestamp("2019"), Timestamp("2017")],
)
with tm.assert_produces_warning(FutureWarning):
obj.loc[start:"2022"]


class TestLocBooleanMask:
def test_loc_setitem_bool_mask_timedeltaindex(self):
Expand Down
3 changes: 2 additions & 1 deletion pandas/tests/series/indexing/test_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,8 @@ def compare(slobj):
tm.assert_series_equal(result, expected)

compare(slice("2011-01-01", "2011-01-15"))
compare(slice("2010-12-30", "2011-01-15"))
with tm.assert_produces_warning(FutureWarning):
compare(slice("2010-12-30", "2011-01-15"))
compare(slice("2011-01-01", "2011-01-16"))

# partial ranges
Expand Down

0 comments on commit f34fe62

Please sign in to comment.