Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: New proposed deprecation policy #58169

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 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
5 changes: 5 additions & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ enhancement1
enhancement2
^^^^^^^^^^^^

New Deprecation Policy
^^^^^^^^^^^^^^^^^^^^^^
pandas 3.0.0 introduces a new 3-stage deprecation policy: using ``DeprecationWarning`` initially, then switching to ``FutureWarning`` for broader visibility in the last minor version before the next major release, and then removal of the deprecated functionality in the major release.
Copy link
Member

Choose a reason for hiding this comment

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

It might be good to add some reasoning to this
(e.g. This was done to give downstream packages more time to adjust to pandas deprecations, which should reducing the amount of warnings that an user gets from code that isn't theirs.)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we'd have to also say that there would always be a minimal amount of time (6 months, maybe more??) between the last minor version before the next major release.

Copy link
Member Author

Choose a reason for hiding this comment

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

a minimal amount of time (6 months, maybe more??) between the last minor version before the next major release.

Is this consistent? 3.0 was planned to be released within 6 months of releasing 2.2.0 (#57064)

Copy link
Contributor

Choose a reason for hiding this comment

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

a minimal amount of time (6 months, maybe more??) between the last minor version before the next major release.

Is this consistent? 3.0 was planned to be released within 6 months of releasing 2.2.0 (#57064)

In your last commit, you wrote "This was done to give downstream packages more time to adjust to pandas deprecations". So if we are going to have a policy about this, then we have to decide how much time is sufficient for "more time".


.. _whatsnew_300.enhancements.other:

Other enhancements
Expand Down Expand Up @@ -159,6 +163,7 @@ Other API changes
Deprecations
~~~~~~~~~~~~


Copy keyword
^^^^^^^^^^^^

Expand Down
9 changes: 6 additions & 3 deletions pandas/_libs/tslibs/timestamps.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ import datetime as dt
from pandas._libs.tslibs cimport ccalendar
from pandas._libs.tslibs.base cimport ABCTimestamp

from pandas.util._exceptions import find_stack_level
from pandas.util._exceptions import (
Pandas40DeprecationWarning,
find_stack_level,
)

from pandas._libs.tslibs.conversion cimport (
_TSObject,
Expand Down Expand Up @@ -1423,7 +1426,7 @@ class Timestamp(_Timestamp):
# GH#56680
"Timestamp.utcnow is deprecated and will be removed in a future "
"version. Use Timestamp.now('UTC') instead.",
FutureWarning,
Pandas40DeprecationWarning,
stacklevel=find_stack_level(),
)
return cls.now(UTC)
Expand Down Expand Up @@ -1451,7 +1454,7 @@ class Timestamp(_Timestamp):
# to match. GH#56680
"Timestamp.utcfromtimestamp is deprecated and will be removed in a "
"future version. Use Timestamp.fromtimestamp(ts, 'UTC') instead.",
FutureWarning,
Pandas40DeprecationWarning,
stacklevel=find_stack_level(),
)
return cls.fromtimestamp(ts, tz="UTC")
Expand Down
7 changes: 5 additions & 2 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@
)
from pandas.errors.cow import _chained_assignment_method_msg
from pandas.util._decorators import doc
from pandas.util._exceptions import find_stack_level
from pandas.util._exceptions import (
Pandas40DeprecationWarning,
find_stack_level,
)
from pandas.util._validators import (
check_dtype_backend,
validate_ascending,
Expand Down Expand Up @@ -4255,7 +4258,7 @@ def _check_copy_deprecation(copy):
"version. Copy-on-Write is active in pandas since 3.0 which utilizes "
"a lazy copy mechanism that defers copies until necessary. Use "
".copy() to make an eager copy if necessary.",
DeprecationWarning,
Pandas40DeprecationWarning,
stacklevel=find_stack_level(),
)

Expand Down
7 changes: 5 additions & 2 deletions pandas/core/reshape/concat.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

from pandas._libs import lib
from pandas.util._decorators import cache_readonly
from pandas.util._exceptions import find_stack_level
from pandas.util._exceptions import (
Pandas40DeprecationWarning,
find_stack_level,
)

from pandas.core.dtypes.common import is_bool
from pandas.core.dtypes.concat import concat_compat
Expand Down Expand Up @@ -382,7 +385,7 @@ def concat(
"version. Copy-on-Write is active in pandas since 3.0 which utilizes "
"a lazy copy mechanism that defers copies until necessary. Use "
".copy() to make an eager copy if necessary.",
DeprecationWarning,
Pandas40DeprecationWarning,
stacklevel=find_stack_level(),
)

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/window/expanding.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ def kurt(self, numeric_only: bool = False):
aggregation_description="quantile",
agg_method="quantile",
)
@deprecate_kwarg(old_arg_name="quantile", new_arg_name="q")
@deprecate_kwarg(old_arg_name="quantile", new_arg_name="q", klass=FutureWarning)
def quantile(
self,
q: float,
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/window/rolling.py
Original file line number Diff line number Diff line change
Expand Up @@ -2556,7 +2556,7 @@ def kurt(self, numeric_only: bool = False):
aggregation_description="quantile",
agg_method="quantile",
)
@deprecate_kwarg(old_arg_name="quantile", new_arg_name="q")
@deprecate_kwarg(old_arg_name="quantile", new_arg_name="q", klass=FutureWarning)
def quantile(
self,
q: float,
Expand Down
20 changes: 11 additions & 9 deletions pandas/tests/copy_view/test_copy_deprecation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import pytest

from pandas.util._exceptions import Pandas40DeprecationWarning

import pandas as pd
from pandas import (
concat,
Expand Down Expand Up @@ -38,34 +40,34 @@ def test_copy_deprecation(meth, kwargs):
df = df.set_index(["b", "c"])

if meth != "swaplevel":
with tm.assert_produces_warning(DeprecationWarning, match="copy"):
with tm.assert_produces_warning(Pandas40DeprecationWarning, match="copy"):
getattr(df, meth)(copy=False, **kwargs)

if meth != "transpose":
with tm.assert_produces_warning(DeprecationWarning, match="copy"):
with tm.assert_produces_warning(Pandas40DeprecationWarning, match="copy"):
getattr(df.a, meth)(copy=False, **kwargs)


def test_copy_deprecation_reindex_like_align():
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
# Somehow the stack level check is incorrect here
with tm.assert_produces_warning(
DeprecationWarning, match="copy", check_stacklevel=False
Pandas40DeprecationWarning, match="copy", check_stacklevel=False
):
df.reindex_like(df, copy=False)

with tm.assert_produces_warning(
DeprecationWarning, match="copy", check_stacklevel=False
Pandas40DeprecationWarning, match="copy", check_stacklevel=False
):
df.a.reindex_like(df.a, copy=False)

with tm.assert_produces_warning(
DeprecationWarning, match="copy", check_stacklevel=False
Pandas40DeprecationWarning, match="copy", check_stacklevel=False
):
df.align(df, copy=False)

with tm.assert_produces_warning(
DeprecationWarning, match="copy", check_stacklevel=False
Pandas40DeprecationWarning, match="copy", check_stacklevel=False
):
df.a.align(df.a, copy=False)

Expand All @@ -74,16 +76,16 @@ def test_copy_deprecation_merge_concat():
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})

with tm.assert_produces_warning(
DeprecationWarning, match="copy", check_stacklevel=False
Pandas40DeprecationWarning, match="copy", check_stacklevel=False
):
df.merge(df, copy=False)

with tm.assert_produces_warning(
DeprecationWarning, match="copy", check_stacklevel=False
Pandas40DeprecationWarning, match="copy", check_stacklevel=False
):
merge(df, df, copy=False)

with tm.assert_produces_warning(
DeprecationWarning, match="copy", check_stacklevel=False
Pandas40DeprecationWarning, match="copy", check_stacklevel=False
):
concat([df, df], copy=False)
4 changes: 3 additions & 1 deletion pandas/tests/io/formats/test_to_markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import pytest

from pandas.util._exceptions import Pandas40DeprecationWarning

import pandas as pd
import pandas._testing as tm

Expand All @@ -15,7 +17,7 @@ def test_keyword_deprecation():
"except for the argument 'buf' will be keyword-only."
)
s = pd.Series()
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas40DeprecationWarning, match=msg):
s.to_markdown(None, "wt")


Expand Down
4 changes: 3 additions & 1 deletion pandas/tests/io/formats/test_to_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

from pandas._config import using_pyarrow_string_dtype

from pandas.util._exceptions import Pandas40DeprecationWarning

from pandas import (
CategoricalIndex,
DataFrame,
Expand Down Expand Up @@ -42,7 +44,7 @@ def test_keyword_deprecation(self):
"except for the argument 'buf' will be keyword-only."
)
s = Series(["a", "b"])
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas40DeprecationWarning, match=msg):
s.to_string(None, "NaN")

def test_to_string_masked_ea_with_formatter(self):
Expand Down
5 changes: 3 additions & 2 deletions pandas/tests/scalar/timestamp/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
from pandas.compat import PY310
from pandas.errors import OutOfBoundsDatetime
from pandas.util._exceptions import Pandas40DeprecationWarning

from pandas import (
NA,
Expand Down Expand Up @@ -332,13 +333,13 @@ class TestTimestampClassMethodConstructors:
def test_utcnow_deprecated(self):
# GH#56680
msg = "Timestamp.utcnow is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas40DeprecationWarning, match=msg):
Timestamp.utcnow()

def test_utcfromtimestamp_deprecated(self):
# GH#56680
msg = "Timestamp.utcfromtimestamp is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas40DeprecationWarning, match=msg):
Timestamp.utcfromtimestamp(43)

def test_constructor_strptime(self):
Expand Down
7 changes: 4 additions & 3 deletions pandas/tests/scalar/timestamp/test_timestamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
tz_compare,
)
from pandas.compat import IS64
from pandas.util._exceptions import Pandas40DeprecationWarning

from pandas import (
NaT,
Expand Down Expand Up @@ -269,7 +270,7 @@ def test_disallow_setting_tz(self, tz):

def test_default_to_stdlib_utc(self):
msg = "Timestamp.utcnow is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas40DeprecationWarning, match=msg):
assert Timestamp.utcnow().tz is timezone.utc
assert Timestamp.now("UTC").tz is timezone.utc
assert Timestamp("2016-01-01", tz="UTC").tz is timezone.utc
Expand Down Expand Up @@ -314,13 +315,13 @@ def compare(x, y):
compare(Timestamp.now("UTC"), datetime.now(pytz.timezone("UTC")))
compare(Timestamp.now("UTC"), datetime.now(tzutc()))
msg = "Timestamp.utcnow is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas40DeprecationWarning, match=msg):
compare(Timestamp.utcnow(), datetime.now(timezone.utc))
compare(Timestamp.today(), datetime.today())
current_time = calendar.timegm(datetime.now().utctimetuple())

msg = "Timestamp.utcfromtimestamp is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas40DeprecationWarning, match=msg):
ts_utc = Timestamp.utcfromtimestamp(current_time)
assert ts_utc.timestamp() == current_time
compare(
Expand Down
4 changes: 3 additions & 1 deletion pandas/tests/tools/test_to_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,9 @@ def test_to_datetime_today(self, tz):
def test_to_datetime_today_now_unicode_bytes(self, arg):
to_datetime([arg])

@pytest.mark.filterwarnings("ignore:Timestamp.utcnow is deprecated:FutureWarning")
@pytest.mark.filterwarnings(
"ignore:Timestamp.utcnow is deprecated:DeprecationWarning"
)
@pytest.mark.parametrize(
"format, expected_ds",
[
Expand Down
10 changes: 8 additions & 2 deletions pandas/tests/util/test_deprecate.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ def new_func_with_deprecation():


def test_deprecate_ok():
depr_func = deprecate("depr_func", new_func, "1.0", msg="Use new_func instead.")
depr_func = deprecate(
"depr_func", new_func, "1.0", msg="Use new_func instead.", klass=FutureWarning
)

with tm.assert_produces_warning(FutureWarning):
result = depr_func()
Expand All @@ -48,7 +50,11 @@ def test_deprecate_ok():

def test_deprecate_no_docstring():
depr_func = deprecate(
"depr_func", new_func_no_docstring, "1.0", msg="Use new_func instead."
"depr_func",
new_func_no_docstring,
"1.0",
msg="Use new_func instead.",
klass=FutureWarning,
)
with tm.assert_produces_warning(FutureWarning):
result = depr_func()
Expand Down
8 changes: 4 additions & 4 deletions pandas/tests/util/test_deprecate_kwarg.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
import pandas._testing as tm


@deprecate_kwarg("old", "new")
@deprecate_kwarg("old", "new", klass=FutureWarning)
def _f1(new=False):
return new


_f2_mappings = {"yes": True, "no": False}


@deprecate_kwarg("old", "new", _f2_mappings)
@deprecate_kwarg("old", "new", _f2_mappings, klass=FutureWarning)
def _f2(new=False):
return new

Expand All @@ -22,7 +22,7 @@ def _f3_mapping(x):
return x + 1


@deprecate_kwarg("old", "new", _f3_mapping)
@deprecate_kwarg("old", "new", _f3_mapping, klass=FutureWarning)
def _f3(new=0):
return new

Expand Down Expand Up @@ -70,7 +70,7 @@ def f4(new=None):
return new


@deprecate_kwarg("old", None)
@deprecate_kwarg("old", None, klass=FutureWarning)
def _f4(old=True, unchanged=True):
return old, unchanged

Expand Down
12 changes: 7 additions & 5 deletions pandas/tests/util/test_deprecate_nonkeyword_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@


@deprecate_nonkeyword_arguments(
version="1.1", allowed_args=["a", "b"], name="f_add_inputs"
version="1.1", allowed_args=["a", "b"], name="f_add_inputs", klass=FutureWarning
)
def f(a, b=0, c=0, d=0):
return a + b + c + d
Expand Down Expand Up @@ -59,7 +59,7 @@ def test_three_arguments_with_name_in_warning():
assert f(6, 3, 3) == 12


@deprecate_nonkeyword_arguments(version="1.1")
@deprecate_nonkeyword_arguments(version="1.1", klass=FutureWarning)
def g(a, b=0, c=0, d=0):
with tm.assert_produces_warning(None):
return a + b + c + d
Expand Down Expand Up @@ -88,7 +88,7 @@ def test_three_positional_argument_with_warning_message_analysis():
assert g(6, 3, 3) == 12


@deprecate_nonkeyword_arguments(version="1.1")
@deprecate_nonkeyword_arguments(version="1.1", klass=FutureWarning)
def h(a=0, b=0, c=0, d=0):
return a + b + c + d

Expand All @@ -113,7 +113,7 @@ def test_one_positional_argument_with_warning_message_analysis():
assert h(19) == 19


@deprecate_nonkeyword_arguments(version="1.1")
@deprecate_nonkeyword_arguments(version="1.1", klass=FutureWarning)
def i(a=0, /, b=0, *, c=0, d=0):
return a + b + c + d

Expand All @@ -123,7 +123,9 @@ def test_i_signature():


class Foo:
@deprecate_nonkeyword_arguments(version=None, allowed_args=["self", "bar"])
@deprecate_nonkeyword_arguments(
version=None, allowed_args=["self", "bar"], klass=FutureWarning
)
def baz(self, bar=None, foobar=None): # pylint: disable=disallowed-name
...

Expand Down
Loading