Skip to content

Commit a59582d

Browse files
DEPR: non-keyword arguments in any (#44896)
* tighten return type in any * correct overload definitions * add overload def for NDFrame input * remove overload defs and define function any in sub-classes * add overload defs for level * correct default val in overload defs * deprecate non-keyword args * add whatsnew note * modify return types and add tests * move non-keyword deprecation to generic * correct deprecation decorators * remove imports in test assertions * place deprecate_nonkeyword at correct place * remove changes from frame.py, series.py * readd changes in frame, series without actual implementations * place deprecate_nonkeyword at other place * add name argument to deprecate_non_keyword_args decorator * add test for name in deprecate_nonkeyword_args * remove changes from frame.py, series.py * correct stacklevel in warning * correct stacklevel * set stacklevel to default * move deprecation message to whatsnew v1.5.0.rst * add name parameter in deprecate_non_keyword_args docstring * correct whitespace in deprecate_nonkeyword_args docstring * update any non-keyword args in other tests * update any in doc * update remaining any() calls in pandas/core * correct docstring of isocalendar in pandas/core/indexes/accessors.py Co-authored-by: Marco Edward Gorelli <[email protected]>
1 parent eab2cfa commit a59582d

File tree

8 files changed

+59
-9
lines changed

8 files changed

+59
-9
lines changed

doc/source/whatsnew/v0.13.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ Enhancements
664664
other = pd.DataFrame({'A': [1, 3, 3, 7], 'B': ['e', 'f', 'f', 'e']})
665665
mask = dfi.isin(other)
666666
mask
667-
dfi[mask.any(1)]
667+
dfi[mask.any(axis=1)]
668668
669669
- ``Series`` now supports a ``to_frame`` method to convert it to a single-column DataFrame (:issue:`5164`)
670670

doc/source/whatsnew/v1.5.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ Other Deprecations
429429
- Deprecated behavior of method :meth:`DataFrame.quantile`, attribute ``numeric_only`` will default False. Including datetime/timedelta columns in the result (:issue:`7308`).
430430
- Deprecated :attr:`Timedelta.freq` and :attr:`Timedelta.is_populated` (:issue:`46430`)
431431
- Deprecated :attr:`Timedelta.delta` (:issue:`46476`)
432+
- Deprecated passing arguments as positional in :meth:`DataFrame.any` and :meth:`Series.any` (:issue:`44802`)
432433
- Deprecated the ``closed`` argument in :meth:`interval_range` in favor of ``inclusive`` argument; In a future version passing ``closed`` will raise (:issue:`40245`)
433434
- Deprecated the methods :meth:`DataFrame.mad`, :meth:`Series.mad`, and the corresponding groupby methods (:issue:`11787`)
434435

pandas/core/generic.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -7224,7 +7224,7 @@ def asof(self, where, subset=None):
72247224
if not isinstance(where, Index):
72257225
where = Index(where) if is_list else Index([where])
72267226

7227-
nulls = self.isna() if is_series else self[subset].isna().any(1)
7227+
nulls = self.isna() if is_series else self[subset].isna().any(axis=1)
72287228
if nulls.all():
72297229
if is_series:
72307230
self = cast("Series", self)
@@ -10517,7 +10517,7 @@ def any(
1051710517
skipna: bool_t = True,
1051810518
level: Level | None = None,
1051910519
**kwargs,
10520-
) -> Series | bool_t:
10520+
) -> DataFrame | Series | bool_t:
1052110521
return self._logical_func(
1052210522
"any", nanops.nanany, axis, bool_only, skipna, level, **kwargs
1052310523
)
@@ -10941,6 +10941,12 @@ def _add_numeric_operations(cls):
1094110941
"""
1094210942
axis_descr, name1, name2 = _doc_params(cls)
1094310943

10944+
@deprecate_nonkeyword_arguments(
10945+
version=None,
10946+
allowed_args=["self"],
10947+
stacklevel=find_stack_level() - 1,
10948+
name="DataFrame.any and Series.any",
10949+
)
1094410950
@doc(
1094510951
_bool_doc,
1094610952
desc=_any_desc,

pandas/core/missing.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def find_valid_index(values, *, how: str) -> int | None:
191191
is_valid = ~isna(values)
192192

193193
if values.ndim == 2:
194-
is_valid = is_valid.any(1) # reduce axis 1
194+
is_valid = is_valid.any(axis=1) # reduce axis 1
195195

196196
if how == "first":
197197
idxpos = is_valid[::].argmax()

pandas/tests/frame/test_reductions.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1066,11 +1066,11 @@ def test_any_all_extra(self):
10661066
},
10671067
index=["a", "b", "c"],
10681068
)
1069-
result = df[["A", "B"]].any(1)
1069+
result = df[["A", "B"]].any(axis=1)
10701070
expected = Series([True, True, False], index=["a", "b", "c"])
10711071
tm.assert_series_equal(result, expected)
10721072

1073-
result = df[["A", "B"]].any(1, bool_only=True)
1073+
result = df[["A", "B"]].any(axis=1, bool_only=True)
10741074
tm.assert_series_equal(result, expected)
10751075

10761076
result = df.all(1)
@@ -1119,7 +1119,7 @@ def test_any_datetime(self):
11191119
]
11201120
df = DataFrame({"A": float_data, "B": datetime_data})
11211121

1122-
result = df.any(1)
1122+
result = df.any(axis=1)
11231123
expected = Series([True, True, True, False])
11241124
tm.assert_series_equal(result, expected)
11251125

pandas/tests/groupby/test_any_all.py

+22
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,28 @@ def test_any():
6161
tm.assert_frame_equal(result, expected)
6262

6363

64+
def test_any_non_keyword_deprecation():
65+
df = DataFrame({"A": [1, 2], "B": [0, 2], "C": [0, 0]})
66+
msg = (
67+
"In a future version of pandas all arguments of "
68+
"DataFrame.any and Series.any will be keyword-only."
69+
)
70+
with tm.assert_produces_warning(FutureWarning, match=msg):
71+
result = df.any("index", None)
72+
expected = Series({"A": True, "B": True, "C": False})
73+
tm.assert_series_equal(result, expected)
74+
75+
s = Series([False, False, False])
76+
msg = (
77+
"In a future version of pandas all arguments of "
78+
"DataFrame.any and Series.any will be keyword-only."
79+
)
80+
with tm.assert_produces_warning(FutureWarning, match=msg):
81+
result = s.any("index")
82+
expected = False
83+
tm.assert_equal(result, expected)
84+
85+
6486
@pytest.mark.parametrize("bool_agg_func", ["any", "all"])
6587
def test_bool_aggs_dup_column_labels(bool_agg_func):
6688
# 21668

pandas/tests/util/test_deprecate_nonkeyword_arguments.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import pandas._testing as tm
1010

1111

12-
@deprecate_nonkeyword_arguments(version="1.1", allowed_args=["a", "b"])
12+
@deprecate_nonkeyword_arguments(
13+
version="1.1", allowed_args=["a", "b"], name="f_add_inputs"
14+
)
1315
def f(a, b=0, c=0, d=0):
1416
return a + b + c + d
1517

@@ -44,6 +46,19 @@ def test_four_arguments():
4446
assert f(1, 2, 3, 4) == 10
4547

4648

49+
def test_three_arguments_with_name_in_warning():
50+
with warnings.catch_warnings(record=True) as w:
51+
warnings.simplefilter("always")
52+
assert f(6, 3, 3) == 12
53+
assert len(w) == 1
54+
for actual_warning in w:
55+
assert actual_warning.category == FutureWarning
56+
assert str(actual_warning.message) == (
57+
"Starting with pandas version 1.1 all arguments of f_add_inputs "
58+
"except for the arguments 'a' and 'b' will be keyword-only."
59+
)
60+
61+
4762
@deprecate_nonkeyword_arguments(version="1.1")
4863
def g(a, b=0, c=0, d=0):
4964
with tm.assert_produces_warning(None):

pandas/util/_decorators.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ def deprecate_nonkeyword_arguments(
261261
version: str | None,
262262
allowed_args: list[str] | None = None,
263263
stacklevel: int = 2,
264+
name: str | None = None,
264265
) -> Callable[[F], F]:
265266
"""
266267
Decorator to deprecate a use of non-keyword arguments of a function.
@@ -281,6 +282,11 @@ def deprecate_nonkeyword_arguments(
281282
282283
stacklevel : int, default=2
283284
The stack level for warnings.warn
285+
286+
name : str, optional
287+
The specific name of the function to show in the warning
288+
message. If None, then the Qualified name of the function
289+
is used.
284290
"""
285291

286292
def decorate(func):
@@ -296,7 +302,7 @@ def decorate(func):
296302
num_allow_args = len(allow_args)
297303
msg = (
298304
f"{future_version_msg(version)} all arguments of "
299-
f"{func.__qualname__}{{arguments}} will be keyword-only."
305+
f"{name or func.__qualname__}{{arguments}} will be keyword-only."
300306
)
301307

302308
@wraps(func)

0 commit comments

Comments
 (0)