Skip to content
Merged
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)