Skip to content

Commit 1def29f

Browse files
rmhowe425punndcoder28
authored andcommitted
DEPR: Deprecate DataFrame.last and Series.last (pandas-dev#53710)
* Adding implementation for deprecation and entry in whatsnew file * Updating unit tests to account for deprecating of series.last() and DataFrame.last() * Added deprecation message in doc string * Adding PR number to new unit test * Removing duplicate "Parameters" docstring header * Adding doctest skip for call to last()
1 parent 1876e76 commit 1def29f

File tree

4 files changed

+51
-9
lines changed

4 files changed

+51
-9
lines changed

doc/source/whatsnew/v2.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ Deprecations
288288
- Deprecated :func:`value_counts`, use ``pd.Series(obj).value_counts()`` instead (:issue:`47862`)
289289
- Deprecated :meth:`Series.first` and :meth:`DataFrame.first` (please create a mask and filter using ``.loc`` instead) (:issue:`45908`)
290290
- Deprecated :meth:`Series.interpolate` and :meth:`DataFrame.interpolate` for object-dtype (:issue:`53631`)
291+
- Deprecated :meth:`Series.last` and :meth:`DataFrame.last` (please create a mask and filter using ``.loc`` instead) (:issue:`53692`)
291292
- Deprecated allowing ``downcast`` keyword other than ``None``, ``False``, "infer", or a dict with these as values in :meth:`Series.fillna`, :meth:`DataFrame.fillna` (:issue:`40988`)
292293
- Deprecated allowing arbitrary ``fill_value`` in :class:`SparseDtype`, in a future version the ``fill_value`` will need to be compatible with the ``dtype.subtype``, either a scalar that can be held by that subtype or ``NaN`` for integer or bool subtypes (:issue:`23124`)
293294
- Deprecated behavior of :func:`assert_series_equal` and :func:`assert_frame_equal` considering NA-like values (e.g. ``NaN`` vs ``None`` as equivalent) (:issue:`52081`)

pandas/core/generic.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -9321,6 +9321,11 @@ def last(self, offset) -> Self:
93219321
at_time : Select values at a particular time of the day.
93229322
between_time : Select values between particular times of the day.
93239323
9324+
Notes
9325+
-----
9326+
.. deprecated:: 2.1.0
9327+
Please create a mask and filter using `.loc` instead
9328+
93249329
Examples
93259330
--------
93269331
>>> i = pd.date_range('2018-04-09', periods=4, freq='2D')
@@ -9334,7 +9339,7 @@ def last(self, offset) -> Self:
93349339
93359340
Get the rows for the last 3 days:
93369341
9337-
>>> ts.last('3D')
9342+
>>> ts.last('3D') # doctest: +SKIP
93389343
A
93399344
2018-04-13 3
93409345
2018-04-15 4
@@ -9343,6 +9348,13 @@ def last(self, offset) -> Self:
93439348
3 observed days in the dataset, and therefore data for 2018-04-11 was
93449349
not returned.
93459350
"""
9351+
warnings.warn(
9352+
"last is deprecated and will be removed in a future version. "
9353+
"Please create a mask and filter using `.loc` instead",
9354+
FutureWarning,
9355+
stacklevel=find_stack_level(),
9356+
)
9357+
93469358
if not isinstance(self.index, DatetimeIndex):
93479359
raise TypeError("'last' only supports a DatetimeIndex index")
93489360

pandas/tests/frame/methods/test_first_and_last.py

+18-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import pandas._testing as tm
1212

1313
deprecated_msg = "first is deprecated"
14+
last_deprecated_msg = "last is deprecated"
1415

1516

1617
class TestFirst:
@@ -55,29 +56,38 @@ def test_first_last_raises(self, frame_or_series):
5556
obj.first("1D")
5657

5758
msg = "'last' only supports a DatetimeIndex index"
58-
with pytest.raises(TypeError, match=msg): # index is not a DatetimeIndex
59+
with tm.assert_produces_warning(
60+
FutureWarning, match=last_deprecated_msg
61+
), pytest.raises(
62+
TypeError, match=msg
63+
): # index is not a DatetimeIndex
5964
obj.last("1D")
6065

6166
def test_last_subset(self, frame_or_series):
6267
ts = tm.makeTimeDataFrame(freq="12h")
6368
ts = tm.get_obj(ts, frame_or_series)
64-
result = ts.last("10d")
69+
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
70+
result = ts.last("10d")
6571
assert len(result) == 20
6672

6773
ts = tm.makeTimeDataFrame(nper=30, freq="D")
6874
ts = tm.get_obj(ts, frame_or_series)
69-
result = ts.last("10d")
75+
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
76+
result = ts.last("10d")
7077
assert len(result) == 10
7178

72-
result = ts.last("21D")
79+
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
80+
result = ts.last("21D")
7381
expected = ts["2000-01-10":]
7482
tm.assert_equal(result, expected)
7583

76-
result = ts.last("21D")
84+
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
85+
result = ts.last("21D")
7786
expected = ts[-21:]
7887
tm.assert_equal(result, expected)
7988

80-
result = ts[:0].last("3M")
89+
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
90+
result = ts[:0].last("3M")
8191
tm.assert_equal(result, ts[:0])
8292

8393
@pytest.mark.parametrize("start, periods", [("2010-03-31", 1), ("2010-03-30", 2)])
@@ -104,7 +114,8 @@ def test_first_with_first_day_end_of_frq_n_greater_one(self, frame_or_series):
104114
def test_empty_not_input(self):
105115
# GH#51032
106116
df = DataFrame(index=pd.DatetimeIndex([]))
107-
result = df.last(offset=1)
117+
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
118+
result = df.last(offset=1)
108119

109120
with tm.assert_produces_warning(FutureWarning, match=deprecated_msg):
110121
result = df.first(offset=1)

pandas/tests/generic/test_finalize.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,8 @@ def ndframe_method(request):
395395

396396

397397
@pytest.mark.filterwarnings(
398-
"ignore:DataFrame.fillna with 'method' is deprecated:FutureWarning"
398+
"ignore:DataFrame.fillna with 'method' is deprecated:FutureWarning",
399+
"ignore:last is deprecated:FutureWarning",
399400
)
400401
def test_finalize_called(ndframe_method):
401402
cls, init_args, method = ndframe_method
@@ -423,6 +424,23 @@ def test_finalize_first(data):
423424
assert result.attrs == {"a": 1}
424425

425426

427+
@pytest.mark.parametrize(
428+
"data",
429+
[
430+
pd.Series(1, pd.date_range("2000", periods=4)),
431+
pd.DataFrame({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
432+
],
433+
)
434+
def test_finalize_last(data):
435+
# GH 53710
436+
deprecated_msg = "last is deprecated"
437+
438+
data.attrs = {"a": 1}
439+
with tm.assert_produces_warning(FutureWarning, match=deprecated_msg):
440+
result = data.last("3D")
441+
assert result.attrs == {"a": 1}
442+
443+
426444
@not_implemented_mark
427445
def test_finalize_called_eval_numexpr():
428446
pytest.importorskip("numexpr")

0 commit comments

Comments
 (0)