Skip to content

DEPR: Remove *args and **kwargs on resample methods #51042

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

Merged
merged 9 commits into from
Feb 5, 2023
1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ Deprecations
- :meth:`Index.is_object` has been deprecated. Use :func:`pandas.api.types.is_object_dtype` instead (:issue:`50042`)
- :meth:`Index.is_interval` has been deprecated. Use :func:`pandas.api.types.is_intterval_dtype` instead (:issue:`50042`)
- Deprecated ``all`` and ``any`` reductions with ``datetime64`` and :class:`DatetimeTZDtype` dtypes, use e.g. ``(obj != pd.Timestamp(0), tz=obj.tz).all()`` instead (:issue:`34479`)
- Deprecated unused arguments ``*args`` and ``**kwargs`` in :class:`Resampler` (:issue:`50977`)
- Deprecated calling ``float`` or ``int`` on a single element :class:`Series` to return a ``float`` or ``int`` respectively. Extract the element before calling ``float`` or ``int`` instead (:issue:`51101`)

.. ---------------------------------------------------------------------------
Expand Down
49 changes: 49 additions & 0 deletions pandas/core/resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
final,
no_type_check,
)
import warnings

import numpy as np

Expand Down Expand Up @@ -47,6 +48,7 @@
Substitution,
doc,
)
from pandas.util._exceptions import find_stack_level

from pandas.core.dtypes.generic import (
ABCDataFrame,
Expand Down Expand Up @@ -892,6 +894,7 @@ def sum(
*args,
**kwargs,
):
maybe_warn_args_and_kwargs(type(self), "sum", args, kwargs)
nv.validate_resampler_func("sum", args, kwargs)
return self._downsample("sum", numeric_only=numeric_only, min_count=min_count)

Expand All @@ -903,6 +906,7 @@ def prod(
*args,
**kwargs,
):
maybe_warn_args_and_kwargs(type(self), "prod", args, kwargs)
nv.validate_resampler_func("prod", args, kwargs)
return self._downsample("prod", numeric_only=numeric_only, min_count=min_count)

Expand All @@ -913,6 +917,7 @@ def min(
*args,
**kwargs,
):
maybe_warn_args_and_kwargs(type(self), "min", args, kwargs)
nv.validate_resampler_func("min", args, kwargs)
return self._downsample("min", numeric_only=numeric_only, min_count=min_count)

Expand All @@ -923,6 +928,7 @@ def max(
*args,
**kwargs,
):
maybe_warn_args_and_kwargs(type(self), "max", args, kwargs)
nv.validate_resampler_func("max", args, kwargs)
return self._downsample("max", numeric_only=numeric_only, min_count=min_count)

Expand All @@ -934,6 +940,7 @@ def first(
*args,
**kwargs,
):
maybe_warn_args_and_kwargs(type(self), "first", args, kwargs)
nv.validate_resampler_func("first", args, kwargs)
return self._downsample("first", numeric_only=numeric_only, min_count=min_count)

Expand All @@ -945,11 +952,13 @@ def last(
*args,
**kwargs,
):
maybe_warn_args_and_kwargs(type(self), "last", args, kwargs)
nv.validate_resampler_func("last", args, kwargs)
return self._downsample("last", numeric_only=numeric_only, min_count=min_count)

@doc(GroupBy.median)
def median(self, numeric_only: bool = False, *args, **kwargs):
maybe_warn_args_and_kwargs(type(self), "median", args, kwargs)
nv.validate_resampler_func("median", args, kwargs)
return self._downsample("median", numeric_only=numeric_only)

Expand All @@ -976,6 +985,7 @@ def mean(
DataFrame or Series
Mean of values within each group.
"""
maybe_warn_args_and_kwargs(type(self), "mean", args, kwargs)
nv.validate_resampler_func("mean", args, kwargs)
return self._downsample("mean", numeric_only=numeric_only)

Expand Down Expand Up @@ -1007,6 +1017,7 @@ def std(
DataFrame or Series
Standard deviation of values within each group.
"""
maybe_warn_args_and_kwargs(type(self), "std", args, kwargs)
nv.validate_resampler_func("std", args, kwargs)
return self._downsample("std", ddof=ddof, numeric_only=numeric_only)

Expand Down Expand Up @@ -1039,6 +1050,7 @@ def var(
DataFrame or Series
Variance of values within each group.
"""
maybe_warn_args_and_kwargs(type(self), "var", args, kwargs)
nv.validate_resampler_func("var", args, kwargs)
return self._downsample("var", ddof=ddof, numeric_only=numeric_only)

Expand All @@ -1050,6 +1062,7 @@ def sem(
*args,
**kwargs,
):
maybe_warn_args_and_kwargs(type(self), "sem", args, kwargs)
nv.validate_resampler_func("sem", args, kwargs)
return self._downsample("sem", ddof=ddof, numeric_only=numeric_only)

Expand All @@ -1059,6 +1072,7 @@ def ohlc(
*args,
**kwargs,
):
maybe_warn_args_and_kwargs(type(self), "ohlc", args, kwargs)
nv.validate_resampler_func("ohlc", args, kwargs)
return self._downsample("ohlc")

Expand All @@ -1068,6 +1082,7 @@ def nunique(
*args,
**kwargs,
):
maybe_warn_args_and_kwargs(type(self), "nunique", args, kwargs)
nv.validate_resampler_func("nunique", args, kwargs)
return self._downsample("nunique")

Expand Down Expand Up @@ -2219,3 +2234,37 @@ def _asfreq_compat(index: DatetimeIndex | PeriodIndex | TimedeltaIndex, freq):
else: # pragma: no cover
raise TypeError(type(index))
return new_index


def maybe_warn_args_and_kwargs(cls, kernel: str, args, kwargs) -> None:
"""
Warn for deprecation of args and kwargs in resample functions.

Parameters
----------
cls : type
Class to warn about.
kernel : str
Operation name.
args : tuple or None
args passed by user. Will be None if and only if kernel does not have args.
kwargs : dict or None
kwargs passed by user. Will be None if and only if kernel does not have kwargs.
"""
warn_args = args is not None and len(args) > 0
warn_kwargs = kwargs is not None and len(kwargs) > 0
if warn_args and warn_kwargs:
msg = "args and kwargs"
elif warn_args:
msg = "args"
elif warn_kwargs:
msg = "kwargs"
else:
return
warnings.warn(
f"Passing additional {msg} to {cls.__name__}.{kernel} has "
"no impact on the result and is deprecated. This will "
"raise a TypeError in a future version of pandas.",
category=FutureWarning,
stacklevel=find_stack_level(),
)
17 changes: 0 additions & 17 deletions pandas/tests/resample/test_datetime_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from pandas._libs import lib
from pandas._typing import DatetimeNaTType
from pandas.errors import UnsupportedFunctionCall

import pandas as pd
from pandas import (
Expand Down Expand Up @@ -243,22 +242,6 @@ def _ohlc(group):
tm.assert_frame_equal(result, expected)


@pytest.mark.parametrize("func", ["min", "max", "sum", "prod", "mean", "var", "std"])
def test_numpy_compat(func, unit):
# see gh-12811
s = Series(
[1, 2, 3, 4, 5], index=date_range("20130101", periods=5, freq="s").as_unit(unit)
)
r = s.resample("2s")

msg = "numpy operations are not valid with resample"

with pytest.raises(UnsupportedFunctionCall, match=msg):
getattr(r, func)(func, 1, 2, 3)
with pytest.raises(UnsupportedFunctionCall, match=msg):
getattr(r, func)(axis=1)


def test_resample_how_callables(unit):
# GH#7929
data = np.arange(5, dtype=np.int64)
Expand Down
41 changes: 41 additions & 0 deletions pandas/tests/resample/test_resample_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest

from pandas._libs import lib
from pandas.errors import UnsupportedFunctionCall

import pandas as pd
from pandas import (
Expand Down Expand Up @@ -916,3 +917,43 @@ def test_series_downsample_method(method, numeric_only, expected_data):
result = func(**kwargs)
expected = Series(expected_data, index=expected_index)
tm.assert_series_equal(result, expected)


@pytest.mark.parametrize(
"method, raises",
[
("sum", True),
("prod", True),
("min", True),
("max", True),
("first", False),
("last", False),
("median", False),
("mean", True),
("std", True),
("var", True),
("sem", False),
("ohlc", False),
("nunique", False),
],
)
def test_args_kwargs_depr(method, raises):
index = date_range("20180101", periods=3, freq="h")
df = Series([2, 4, 6], index=index)
resampled = df.resample("30min")
args = ()

func = getattr(resampled, method)

error_msg = "numpy operations are not valid with resample."
error_msg_type = "too many arguments passed in"
warn_msg = f"Passing additional args to DatetimeIndexResampler.{method}"

if raises:
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
with pytest.raises(UnsupportedFunctionCall, match=error_msg):
func(*args, 1, 2, 3)
else:
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
with pytest.raises(TypeError, match=error_msg_type):
func(*args, 1, 2, 3)