From 13100254a7a44dc5402ba3661c0b72aabd2c4730 Mon Sep 17 00:00:00 2001 From: Richard Howe Date: Sat, 17 Jun 2023 10:54:23 -0400 Subject: [PATCH 1/6] Adding implementation for deprecation and entry in whatsnew file --- doc/source/whatsnew/v2.1.0.rst | 1 + pandas/core/generic.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index e2f0904a78cf9..7f3594d7ca769 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -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`) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index d112f5aa7d671..36422d3bed22a 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -9313,6 +9313,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") From da1371fc6d3705e9b488b63ac44de220c6279d40 Mon Sep 17 00:00:00 2001 From: Richard Howe Date: Sat, 17 Jun 2023 11:49:31 -0400 Subject: [PATCH 2/6] Updating unit tests to account for deprecating of series.last() and DataFrame.last() --- .../frame/methods/test_first_and_last.py | 25 +++++++++++++------ pandas/tests/generic/test_finalize.py | 19 +++++++++++++- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/pandas/tests/frame/methods/test_first_and_last.py b/pandas/tests/frame/methods/test_first_and_last.py index 18173f7c66198..2e85edc7ed0ea 100644 --- a/pandas/tests/frame/methods/test_first_and_last.py +++ b/pandas/tests/frame/methods/test_first_and_last.py @@ -11,6 +11,7 @@ import pandas._testing as tm deprecated_msg = "first is deprecated" +last_deprecated_msg = "last is deprecated" class TestFirst: @@ -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)]) @@ -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) diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index 22460b1ea9dfe..abaf025d9fef1 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -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 @@ -423,6 +424,22 @@ 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): + 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") From 1819438cece8bc7a9cd0e03192a4b3afc4d607a8 Mon Sep 17 00:00:00 2001 From: Richard Howe Date: Sat, 17 Jun 2023 12:38:45 -0400 Subject: [PATCH 3/6] Added deprecation message in doc string --- pandas/core/generic.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 36422d3bed22a..0db8c0d351a8f 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -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 ---------- data : BlockManager @@ -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') From 00df53324f624452821bba0d56166acd9b3a12cc Mon Sep 17 00:00:00 2001 From: Richard Howe Date: Sat, 17 Jun 2023 16:56:14 -0400 Subject: [PATCH 4/6] Adding PR number to new unit test --- pandas/tests/generic/test_finalize.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index abaf025d9fef1..f827eaf63a342 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -432,6 +432,7 @@ def test_finalize_first(data): ], ) def test_finalize_last(data): + # GH 53710 deprecated_msg = "last is deprecated" data.attrs = {"a": 1} From 3d24b1a3e162aef5ec492582bdb049f23a4aea84 Mon Sep 17 00:00:00 2001 From: rmhowe425 <45905457+rmhowe425@users.noreply.github.com> Date: Mon, 19 Jun 2023 08:10:30 -0400 Subject: [PATCH 5/6] Removing duplicate "Parameters" docstring header --- pandas/core/generic.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 0db8c0d351a8f..00d226a0336e8 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -228,7 +228,6 @@ class NDFrame(PandasObject, indexing.IndexingMixin): N-dimensional analogue of DataFrame. Store multi-dimensional in a size-mutable, labeled data structure - Parameters Parameters ---------- data : BlockManager From ab8ec915c78179adc5b06059677e97d75d20a9d1 Mon Sep 17 00:00:00 2001 From: Richard Howe Date: Wed, 21 Jun 2023 08:20:37 -0400 Subject: [PATCH 6/6] Adding doctest skip for call to last() --- pandas/core/generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 00d226a0336e8..585635bc1cade 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -9309,7 +9309,7 @@ def last(self, offset) -> Self: Get the rows for the last 3 days: - >>> ts.last('3D') + >>> ts.last('3D') # doctest: +SKIP A 2018-04-13 3 2018-04-15 4