Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ Deprecations
- Deprecated :func:`value_counts`, use ``pd.Series(obj).value_counts()`` instead (:issue:`47862`)
- Deprecated :meth:`Series.first` and :meth:`DataFrame.first` (please create a mask and filter using ``.loc`` instead) (:issue:`45908`)
- Deprecated :meth:`Series.interpolate` and :meth:`DataFrame.interpolate` for object-dtype (:issue:`53631`)
- Deprecated :meth:`Series.last` and :meth:`DataFrame.last` (please create a mask and filter using ``.loc`` instead) (:issue:`53692`)
- 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`)
- 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`)
- 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`)
Expand Down
13 changes: 13 additions & 0 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class NDFrame(PandasObject, indexing.IndexingMixin):
N-dimensional analogue of DataFrame. Store multi-dimensional in a
size-mutable, labeled data structure

Parameters
Parameters
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to duplicate this

----------
data : BlockManager
Expand Down Expand Up @@ -9291,6 +9292,11 @@ def last(self, offset) -> Self:
at_time : Select values at a particular time of the day.
between_time : Select values between particular times of the day.

Notes
-----
.. deprecated:: 2.1.0
Please create a mask and filter using `.loc` instead

Examples
--------
>>> i = pd.date_range('2018-04-09', periods=4, freq='2D')
Expand All @@ -9313,6 +9319,13 @@ def last(self, offset) -> Self:
3 observed days in the dataset, and therefore data for 2018-04-11 was
not returned.
"""
warnings.warn(
"last is deprecated and will be removed in a future version. "
"Please create a mask and filter using `.loc` instead",
FutureWarning,
stacklevel=find_stack_level(),
)

if not isinstance(self.index, DatetimeIndex):
raise TypeError("'last' only supports a DatetimeIndex index")

Expand Down
25 changes: 18 additions & 7 deletions pandas/tests/frame/methods/test_first_and_last.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import pandas._testing as tm

deprecated_msg = "first is deprecated"
last_deprecated_msg = "last is deprecated"


class TestFirst:
Expand Down Expand Up @@ -55,29 +56,38 @@ def test_first_last_raises(self, frame_or_series):
obj.first("1D")

msg = "'last' only supports a DatetimeIndex index"
with pytest.raises(TypeError, match=msg): # index is not a DatetimeIndex
with tm.assert_produces_warning(
FutureWarning, match=last_deprecated_msg
), pytest.raises(
TypeError, match=msg
): # index is not a DatetimeIndex
obj.last("1D")

def test_last_subset(self, frame_or_series):
ts = tm.makeTimeDataFrame(freq="12h")
ts = tm.get_obj(ts, frame_or_series)
result = ts.last("10d")
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
result = ts.last("10d")
assert len(result) == 20

ts = tm.makeTimeDataFrame(nper=30, freq="D")
ts = tm.get_obj(ts, frame_or_series)
result = ts.last("10d")
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
result = ts.last("10d")
assert len(result) == 10

result = ts.last("21D")
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
result = ts.last("21D")
expected = ts["2000-01-10":]
tm.assert_equal(result, expected)

result = ts.last("21D")
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
result = ts.last("21D")
expected = ts[-21:]
tm.assert_equal(result, expected)

result = ts[:0].last("3M")
with tm.assert_produces_warning(FutureWarning, match=last_deprecated_msg):
result = ts[:0].last("3M")
tm.assert_equal(result, ts[:0])

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

with tm.assert_produces_warning(FutureWarning, match=deprecated_msg):
result = df.first(offset=1)
Expand Down
20 changes: 19 additions & 1 deletion pandas/tests/generic/test_finalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,8 @@ def ndframe_method(request):


@pytest.mark.filterwarnings(
"ignore:DataFrame.fillna with 'method' is deprecated:FutureWarning"
"ignore:DataFrame.fillna with 'method' is deprecated:FutureWarning",
"ignore:last is deprecated:FutureWarning",
)
def test_finalize_called(ndframe_method):
cls, init_args, method = ndframe_method
Expand Down Expand Up @@ -423,6 +424,23 @@ def test_finalize_first(data):
assert result.attrs == {"a": 1}


@pytest.mark.parametrize(
"data",
[
pd.Series(1, pd.date_range("2000", periods=4)),
pd.DataFrame({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
],
)
def test_finalize_last(data):
# GH 53710
deprecated_msg = "last is deprecated"

data.attrs = {"a": 1}
with tm.assert_produces_warning(FutureWarning, match=deprecated_msg):
result = data.last("3D")
assert result.attrs == {"a": 1}


@not_implemented_mark
def test_finalize_called_eval_numexpr():
pytest.importorskip("numexpr")
Expand Down