Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@ repos:
language: python
entry: python scripts/validate_unwanted_patterns.py --validation-type="nodefault_used_not_only_for_typing"
types: [python]
- id: unwanted-patterns-doesnt-use-pandas-warnings
name: Check that warning classes for deprecations use pandas' warning classes
language: python
entry: python scripts/validate_unwanted_patterns.py --validation-type="doesnt_use_pandas_warnings"
types: [ python ]
- id: no-return-exception
name: Use raise instead of return for exceptions
language: pygrep
Expand Down
14 changes: 11 additions & 3 deletions pandas/_config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@

class DeprecatedOption(NamedTuple):
key: str
category: type[Warning]
msg: str | None
rkey: str | None
removal_ver: str | None
Expand Down Expand Up @@ -589,6 +590,7 @@ def register_option(

def deprecate_option(
key: str,
category: type[Warning],
msg: str | None = None,
rkey: str | None = None,
removal_ver: str | None = None,
Expand All @@ -608,6 +610,8 @@ def deprecate_option(
key : str
Name of the option to be deprecated.
must be a fully-qualified option name (e.g "x.y.z.rkey").
category : Warning
Warning class for the deprecation.
msg : str, optional
Warning message to output when the key is referenced.
if no message is given a default message will be emitted.
Expand All @@ -631,7 +635,7 @@ def deprecate_option(
if key in _deprecated_options:
raise OptionError(f"Option '{key}' has already been defined as deprecated.")

_deprecated_options[key] = DeprecatedOption(key, msg, rkey, removal_ver)
_deprecated_options[key] = DeprecatedOption(key, category, msg, rkey, removal_ver)


#
Expand Down Expand Up @@ -716,7 +720,7 @@ def _warn_if_deprecated(key: str) -> bool:
if d.msg:
warnings.warn(
d.msg,
FutureWarning,
d.category,
stacklevel=find_stack_level(),
)
else:
Expand All @@ -728,7 +732,11 @@ def _warn_if_deprecated(key: str) -> bool:
else:
msg += ", please refrain from using it."

warnings.warn(msg, FutureWarning, stacklevel=find_stack_level())
warnings.warn(
msg,
d.category,
stacklevel=find_stack_level(),
)
return True
return False

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/arrays/string_.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def __init__(
"'pd.options.future.infer_string = True' option globally and use "
'the "str" alias as a shorthand notation to specify a dtype '
'(instead of "string[pyarrow_numpy]").',
FutureWarning,
FutureWarning, # pdlint: ignore[warning_class]
stacklevel=find_stack_level(),
)
storage = "pyarrow"
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/arrays/string_arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def _convert_bool_result(self, values, na=lib.no_default, method_name=None):
warnings.warn(
f"Allowing a non-bool 'na' in obj.str.{method_name} is deprecated "
"and will raise in a future version.",
FutureWarning,
FutureWarning, # pdlint: ignore[warning_class]
stacklevel=find_stack_level(),
)
na = bool(na)
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/dtypes/dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@ def __new__(cls, freq) -> PeriodDtype: # noqa: PYI034
warnings.warn(
"PeriodDtype[B] is deprecated and will be removed in a future "
"version. Use a DatetimeIndex with freq='B' instead",
FutureWarning,
FutureWarning, # pdlint: ignore[warning_class]
stacklevel=find_stack_level(),
)

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -9139,7 +9139,7 @@ def resample(
"deprecated and will be removed in a future version. "
"Explicitly cast PeriodIndex to DatetimeIndex before resampling "
"instead.",
FutureWarning,
FutureWarning, # pdlint: ignore[warning_class]
stacklevel=find_stack_level(),
)
else:
Expand Down
3 changes: 2 additions & 1 deletion pandas/core/groupby/groupby.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class providing the base-class of operations.
from pandas.errors import (
AbstractMethodError,
DataError,
Pandas4Warning,
)
from pandas.util._decorators import (
Appender,
Expand Down Expand Up @@ -557,7 +558,7 @@ def groups(self) -> dict[Hashable, Index]:
"and will be removed. In a future version `groups` by one element "
"list will return tuple. Use ``df.groupby(by='a').groups`` "
"instead of ``df.groupby(by=['a']).groups`` to avoid this warning",
FutureWarning,
Pandas4Warning,
stacklevel=find_stack_level(),
)
return self._grouper.groups
Expand Down
5 changes: 3 additions & 2 deletions pandas/core/resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -1949,7 +1949,7 @@ def _resampler_for_grouping(self):
warnings.warn(
"Resampling a groupby with a PeriodIndex is deprecated. "
"Cast to DatetimeIndex before resampling instead.",
FutureWarning,
FutureWarning, # pdlint: ignore[warning_class]
stacklevel=find_stack_level(),
)
return PeriodIndexResamplerGroupby
Expand Down Expand Up @@ -2293,11 +2293,12 @@ def _get_resampler(self, obj: NDFrame) -> Resampler:
)
elif isinstance(ax, PeriodIndex):
if isinstance(ax, PeriodIndex):
# TODO: Enforce in 3.0 (#53481)
# GH#53481
warnings.warn(
"Resampling with a PeriodIndex is deprecated. "
"Cast index to DatetimeIndex before resampling instead.",
FutureWarning,
FutureWarning, # pdlint: ignore[warning_class]
stacklevel=find_stack_level(),
)
return PeriodIndexResampler(
Expand Down
9 changes: 6 additions & 3 deletions pandas/core/strings/object_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,35 +159,38 @@ def _str_contains(
upper_pat = pat.upper()
f = lambda x: upper_pat in x.upper()
if na is not lib.no_default and not isna(na) and not isinstance(na, bool):
# TODO: Enforce in 3.0 (#59615)
# GH#59561
warnings.warn(
"Allowing a non-bool 'na' in obj.str.contains is deprecated "
"and will raise in a future version.",
FutureWarning,
FutureWarning, # pdlint: ignore[warning_class]
stacklevel=find_stack_level(),
)
return self._str_map(f, na, dtype=np.dtype("bool"))

def _str_startswith(self, pat, na=lib.no_default):
f = lambda x: x.startswith(pat)
if na is not lib.no_default and not isna(na) and not isinstance(na, bool):
# TODO: Enforce in 3.0 (#59615)
# GH#59561
warnings.warn(
"Allowing a non-bool 'na' in obj.str.startswith is deprecated "
"and will raise in a future version.",
FutureWarning,
FutureWarning, # pdlint: ignore[warning_class]
stacklevel=find_stack_level(),
)
return self._str_map(f, na_value=na, dtype=np.dtype(bool))

def _str_endswith(self, pat, na=lib.no_default):
f = lambda x: x.endswith(pat)
if na is not lib.no_default and not isna(na) and not isinstance(na, bool):
# TODO: Enforce in 3.0 (#59615)
# GH#59561
warnings.warn(
"Allowing a non-bool 'na' in obj.str.endswith is deprecated "
"and will raise in a future version.",
FutureWarning,
FutureWarning, # pdlint: ignore[warning_class]
stacklevel=find_stack_level(),
)
return self._str_map(f, na_value=na, dtype=np.dtype(bool))
Expand Down
21 changes: 11 additions & 10 deletions pandas/tests/config/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ def test_register_option(self):
def test_describe_option(self):
cf.register_option("a", 1, "doc")
cf.register_option("b", 1, "doc2")
cf.deprecate_option("b")
cf.deprecate_option("b", FutureWarning)

cf.register_option("c.d.e1", 1, "doc3")
cf.register_option("c.d.e2", 1, "doc4")
cf.register_option("f", 1)
cf.register_option("g.h", 1)
cf.register_option("k", 2)
cf.deprecate_option("g.h", rkey="k")
cf.deprecate_option("g.h", FutureWarning, rkey="k")
cf.register_option("l", "foo")

# non-existent keys raise KeyError
Expand Down Expand Up @@ -111,7 +111,8 @@ def test_describe_option(self):
cf.set_option("l", "bar")
assert "bar" in cf.describe_option("l", _print_desc=False)

def test_case_insensitive(self):
@pytest.mark.parametrize("category", [DeprecationWarning, FutureWarning])
def test_case_insensitive(self, category):
cf.register_option("KanBAN", 1, "doc")

assert "doc" in cf.describe_option("kanbaN", _print_desc=False)
Expand All @@ -124,9 +125,9 @@ def test_case_insensitive(self):
with pytest.raises(OptionError, match=msg):
cf.get_option("no_such_option")

cf.deprecate_option("KanBan")
cf.deprecate_option("KanBan", category)
msg = "'kanban' is deprecated, please refrain from using it."
with pytest.raises(FutureWarning, match=msg):
with pytest.raises(category, match=msg):
cf.get_option("kAnBaN")

def test_get_option(self):
Expand Down Expand Up @@ -285,7 +286,7 @@ def test_reset_option_all(self):

def test_deprecate_option(self):
# we can deprecate non-existent options
cf.deprecate_option("foo")
cf.deprecate_option("foo", FutureWarning)

with tm.assert_produces_warning(FutureWarning, match="deprecated"):
with pytest.raises(KeyError, match="No such keys.s.: 'foo'"):
Expand All @@ -295,15 +296,15 @@ def test_deprecate_option(self):
cf.register_option("b.c", "hullo", "doc2")
cf.register_option("foo", "hullo", "doc2")

cf.deprecate_option("a", removal_ver="nifty_ver")
cf.deprecate_option("a", FutureWarning, removal_ver="nifty_ver")
with tm.assert_produces_warning(FutureWarning, match="eprecated.*nifty_ver"):
cf.get_option("a")

msg = "Option 'a' has already been defined as deprecated"
with pytest.raises(OptionError, match=msg):
cf.deprecate_option("a")
cf.deprecate_option("a", FutureWarning)

cf.deprecate_option("b.c", "zounds!")
cf.deprecate_option("b.c", FutureWarning, "zounds!")
with tm.assert_produces_warning(FutureWarning, match="zounds!"):
cf.get_option("b.c")

Expand All @@ -313,7 +314,7 @@ def test_deprecate_option(self):
assert cf.get_option("d.a") == "foo"
assert cf.get_option("d.dep") == "bar"

cf.deprecate_option("d.dep", rkey="d.a") # reroute d.dep to d.a
cf.deprecate_option("d.dep", FutureWarning, rkey="d.a") # reroute d.dep to d.a
with tm.assert_produces_warning(FutureWarning, match="eprecated"):
assert cf.get_option("d.dep") == "foo"

Expand Down
23 changes: 13 additions & 10 deletions pandas/tests/groupby/test_grouping.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import numpy as np
import pytest

from pandas.errors import SpecificationError
from pandas.errors import (
Pandas4Warning,
SpecificationError,
)

import pandas as pd
from pandas import (
Expand Down Expand Up @@ -545,21 +548,21 @@ def test_multiindex_columns_empty_level(self):
grouped = df.groupby("to filter").groups
assert grouped["A"] == [0]

with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas4Warning, match=msg):
grouped = df.groupby([("to filter", "")]).groups
assert grouped["A"] == [0]

df = DataFrame([[1, "A"], [2, "B"]], columns=midx)

expected = df.groupby("to filter").groups
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas4Warning, match=msg):
result = df.groupby([("to filter", "")]).groups
assert result == expected

df = DataFrame([[1, "A"], [2, "A"]], columns=midx)

expected = df.groupby("to filter").groups
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas4Warning, match=msg):
result = df.groupby([("to filter", "")]).groups
tm.assert_dict_equal(result, expected)

Expand All @@ -571,7 +574,7 @@ def test_groupby_multiindex_tuple(self):
)

msg = "`groups` by one element list returns scalar is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas4Warning, match=msg):
expected = df.groupby([("b", 1)]).groups
result = df.groupby(("b", 1)).groups
tm.assert_dict_equal(expected, result)
Expand All @@ -583,14 +586,14 @@ def test_groupby_multiindex_tuple(self):
),
)

with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas4Warning, match=msg):
expected = df2.groupby([("b", "d")]).groups
result = df.groupby(("b", 1)).groups
tm.assert_dict_equal(expected, result)

df3 = DataFrame(df.values, columns=[("a", "d"), ("b", "d"), ("b", "e"), "c"])

with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas4Warning, match=msg):
expected = df3.groupby([("b", "d")]).groups
result = df.groupby(("b", 1)).groups
tm.assert_dict_equal(expected, result)
Expand Down Expand Up @@ -623,7 +626,7 @@ def test_groupby_multiindex_partial_indexing_equivalence(self):
tm.assert_frame_equal(expected_max, result_max)

msg = "`groups` by one element list returns scalar is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas4Warning, match=msg):
expected_groups = df.groupby([("a", 1)])[[("b", 1), ("b", 2)]].groups
result_groups = df.groupby([("a", 1)])["b"].groups
tm.assert_dict_equal(expected_groups, result_groups)
Expand Down Expand Up @@ -737,7 +740,7 @@ def test_list_grouper_with_nat(self):
# Grouper in a list grouping
gb = df.groupby([grouper])
expected = {Timestamp("2011-01-01"): Index(list(range(364)))}
with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas4Warning, match=msg):
result = gb.groups
tm.assert_dict_equal(result, expected)

Expand Down Expand Up @@ -1019,7 +1022,7 @@ def test_groups(self, df):
grouped = df.groupby(["A"])
msg = "`groups` by one element list returns scalar is deprecated"

with tm.assert_produces_warning(FutureWarning, match=msg):
with tm.assert_produces_warning(Pandas4Warning, match=msg):
groups = grouped.groups
assert groups is grouped.groups # caching works

Expand Down
Loading
Loading