Skip to content

Commit 4bacee5

Browse files
authored
REF: share _reduce method (#44737)
1 parent 5302d1b commit 4bacee5

File tree

12 files changed

+27
-46
lines changed

12 files changed

+27
-46
lines changed

pandas/core/arrays/_mixins.py

-8
Original file line numberDiff line numberDiff line change
@@ -339,14 +339,6 @@ def fillna(
339339
# ------------------------------------------------------------------------
340340
# Reductions
341341

342-
def _reduce(self, name: str, *, skipna: bool = True, **kwargs):
343-
meth = getattr(self, name, None)
344-
if meth:
345-
return meth(skipna=skipna, **kwargs)
346-
else:
347-
msg = f"'{type(self).__name__}' does not implement reduction '{name}'"
348-
raise TypeError(msg)
349-
350342
def _wrap_reduction_result(self, axis: int | None, result):
351343
if axis is None or self.ndim == 1:
352344
return self._box_func(result)

pandas/core/arrays/base.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1352,7 +1352,13 @@ def _reduce(self, name: str, *, skipna: bool = True, **kwargs):
13521352
------
13531353
TypeError : subclass does not define reductions
13541354
"""
1355-
raise TypeError(f"cannot perform {name} with type {self.dtype}")
1355+
meth = getattr(self, name, None)
1356+
if meth is None:
1357+
raise TypeError(
1358+
f"'{type(self).__name__}' with dtype {self.dtype} "
1359+
f"does not support reduction '{name}'"
1360+
)
1361+
return meth(skipna=skipna, **kwargs)
13561362

13571363
# https://github.com/python/typeshed/issues/2148#issuecomment-520783318
13581364
# Incompatible types in assignment (expression has type "None", base class

pandas/core/arrays/sparse/array.py

-7
Original file line numberDiff line numberDiff line change
@@ -1363,13 +1363,6 @@ def _reduce(self, name: str, *, skipna: bool = True, **kwargs):
13631363
else:
13641364
arr = self.dropna()
13651365

1366-
# we don't support these kwargs.
1367-
# They should only be present when called via pandas, so do it here.
1368-
# instead of in `any` / `all` (which will raise if they're present,
1369-
# thanks to nv.validate
1370-
kwargs.pop("filter_type", None)
1371-
kwargs.pop("numeric_only", None)
1372-
kwargs.pop("op", None)
13731366
return getattr(arr, name)(**kwargs)
13741367

13751368
def all(self, axis=None, *args, **kwargs):

pandas/core/arrays/string_arrow.py

-6
Original file line numberDiff line numberDiff line change
@@ -335,12 +335,6 @@ def _as_pandas_scalar(self, arrow_scalar: pa.Scalar):
335335
else:
336336
return scalar
337337

338-
def _reduce(self, name: str, skipna: bool = True, **kwargs):
339-
if name in ["min", "max"]:
340-
return getattr(self, name)(skipna=skipna)
341-
342-
raise TypeError(f"Cannot perform reduction '{name}' with string dtype")
343-
344338
@property
345339
def nbytes(self) -> int:
346340
"""

pandas/tests/arrays/categorical/test_operators.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -371,17 +371,15 @@ def test_numeric_like_ops(self):
371371
# min/max)
372372
s = df["value_group"]
373373
for op in ["kurt", "skew", "var", "std", "mean", "sum", "median"]:
374-
msg = f"'Categorical' does not implement reduction '{op}'"
374+
msg = f"does not support reduction '{op}'"
375375
with pytest.raises(TypeError, match=msg):
376376
getattr(s, op)(numeric_only=False)
377377

378378
# mad technically works because it takes always the numeric data
379379

380380
# numpy ops
381381
s = Series(Categorical([1, 2, 3, 4]))
382-
with pytest.raises(
383-
TypeError, match="'Categorical' does not implement reduction 'sum'"
384-
):
382+
with pytest.raises(TypeError, match="does not support reduction 'sum'"):
385383
np.sum(s)
386384

387385
# numeric ops on a Series

pandas/tests/arrays/string_/test_string.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ def test_reduce(skipna, dtype):
345345
def test_min_max(method, skipna, dtype, request):
346346
if dtype.storage == "pyarrow":
347347
reason = "'ArrowStringArray' object has no attribute 'max'"
348-
mark = pytest.mark.xfail(raises=AttributeError, reason=reason)
348+
mark = pytest.mark.xfail(raises=TypeError, reason=reason)
349349
request.node.add_marker(mark)
350350

351351
arr = pd.Series(["a", "b", "c", None], dtype=dtype)
@@ -362,12 +362,10 @@ def test_min_max(method, skipna, dtype, request):
362362
def test_min_max_numpy(method, box, dtype, request):
363363
if dtype.storage == "pyarrow":
364364
if box is pd.array:
365-
raises = TypeError
366365
reason = "'<=' not supported between instances of 'str' and 'NoneType'"
367366
else:
368-
raises = AttributeError
369367
reason = "'ArrowStringArray' object has no attribute 'max'"
370-
mark = pytest.mark.xfail(raises=raises, reason=reason)
368+
mark = pytest.mark.xfail(raises=TypeError, reason=reason)
371369
request.node.add_marker(mark)
372370

373371
arr = box(["a", "b", "c", None], dtype=dtype)

pandas/tests/arrays/test_datetimelike.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ def test_reduce_invalid(self):
246246
data = np.arange(10, dtype="i8") * 24 * 3600 * 10 ** 9
247247
arr = self.array_cls(data, freq="D")
248248

249-
msg = f"'{type(arr).__name__}' does not implement reduction 'not a method'"
249+
msg = "does not support reduction 'not a method'"
250250
with pytest.raises(TypeError, match=msg):
251251
arr._reduce("not a method")
252252

pandas/tests/extension/base/reduce.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_reduce_series_numeric(self, data, all_numeric_reductions, skipna):
2929

3030
msg = (
3131
"[Cc]annot perform|Categorical is not ordered for operation|"
32-
"'Categorical' does not implement reduction|"
32+
"does not support reduction|"
3333
)
3434

3535
with pytest.raises(TypeError, match=msg):
@@ -42,7 +42,7 @@ def test_reduce_series_boolean(self, data, all_boolean_reductions, skipna):
4242

4343
msg = (
4444
"[Cc]annot perform|Categorical is not ordered for operation|"
45-
"'Categorical' does not implement reduction|"
45+
"does not support reduction|"
4646
)
4747

4848
with pytest.raises(TypeError, match=msg):

pandas/tests/frame/test_reductions.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1507,13 +1507,13 @@ def test_any_all_categorical_dtype_nuisance_column(self, method):
15071507
df = ser.to_frame()
15081508

15091509
# Double-check the Series behavior is to raise
1510-
with pytest.raises(TypeError, match="does not implement reduction"):
1510+
with pytest.raises(TypeError, match="does not support reduction"):
15111511
getattr(ser, method)()
15121512

1513-
with pytest.raises(TypeError, match="does not implement reduction"):
1513+
with pytest.raises(TypeError, match="does not support reduction"):
15141514
getattr(np, method)(ser)
15151515

1516-
with pytest.raises(TypeError, match="does not implement reduction"):
1516+
with pytest.raises(TypeError, match="does not support reduction"):
15171517
getattr(df, method)(bool_only=False)
15181518

15191519
# With bool_only=None, operating on this column raises and is ignored,
@@ -1537,10 +1537,10 @@ def test_median_categorical_dtype_nuisance_column(self):
15371537
ser = df["A"]
15381538

15391539
# Double-check the Series behavior is to raise
1540-
with pytest.raises(TypeError, match="does not implement reduction"):
1540+
with pytest.raises(TypeError, match="does not support reduction"):
15411541
ser.median()
15421542

1543-
with pytest.raises(TypeError, match="does not implement reduction"):
1543+
with pytest.raises(TypeError, match="does not support reduction"):
15441544
df.median(numeric_only=False)
15451545

15461546
with tm.assert_produces_warning(
@@ -1553,7 +1553,7 @@ def test_median_categorical_dtype_nuisance_column(self):
15531553
# same thing, but with an additional non-categorical column
15541554
df["B"] = df["A"].astype(int)
15551555

1556-
with pytest.raises(TypeError, match="does not implement reduction"):
1556+
with pytest.raises(TypeError, match="does not support reduction"):
15571557
df.median(numeric_only=False)
15581558

15591559
with tm.assert_produces_warning(

pandas/tests/groupby/test_groupby.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,7 @@ def test_omit_nuisance(df):
869869

870870
# won't work with axis = 1
871871
grouped = df.groupby({"A": 0, "C": 0, "D": 1, "E": 1}, axis=1)
872-
msg = "'DatetimeArray' does not implement reduction 'sum'"
872+
msg = "does not support reduction 'sum'"
873873
with pytest.raises(TypeError, match=msg):
874874
grouped.agg(lambda x: x.sum(0, numeric_only=False))
875875

@@ -1931,7 +1931,7 @@ def get_result():
19311931
# GH#41291
19321932
# datetime64 -> prod and sum are invalid
19331933
if op == "skew":
1934-
msg = "'DatetimeArray' does not implement reduction 'skew'"
1934+
msg = "does not support reduction 'skew'"
19351935
else:
19361936
msg = "datetime64 type does not support"
19371937
with pytest.raises(TypeError, match=msg):
@@ -1943,9 +1943,9 @@ def get_result():
19431943
# GH#41291
19441944
if op == "mad":
19451945
# mad calls mean, which Categorical doesn't implement
1946-
msg = "'Categorical' does not implement reduction 'mean'"
1946+
msg = "does not support reduction 'mean'"
19471947
elif op == "skew":
1948-
msg = f"'Categorical' does not implement reduction '{op}'"
1948+
msg = f"does not support reduction '{op}'"
19491949
else:
19501950
msg = "category type does not support"
19511951
with pytest.raises(TypeError, match=msg):

pandas/tests/reductions/test_reductions.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ def test_invalid_td64_reductions(self, opname):
356356
[
357357
f"reduction operation '{opname}' not allowed for this dtype",
358358
rf"cannot perform {opname} with type timedelta64\[ns\]",
359-
f"'TimedeltaArray' does not implement reduction '{opname}'",
359+
f"does not support reduction '{opname}'",
360360
]
361361
)
362362

@@ -727,7 +727,7 @@ def test_ops_consistency_on_empty(self, method):
727727
[
728728
"operation 'var' not allowed",
729729
r"cannot perform var with type timedelta64\[ns\]",
730-
"'TimedeltaArray' does not implement reduction 'var'",
730+
"does not support reduction 'var'",
731731
]
732732
)
733733
with pytest.raises(TypeError, match=msg):

pandas/tests/reductions/test_stat_reductions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def _check_stat_op(
105105
# mean, idxmax, idxmin, min, and max are valid for dates
106106
if name not in ["max", "min", "mean", "median", "std"]:
107107
ds = Series(pd.date_range("1/1/2001", periods=10))
108-
msg = f"'DatetimeArray' does not implement reduction '{name}'"
108+
msg = f"does not support reduction '{name}'"
109109
with pytest.raises(TypeError, match=msg):
110110
f(ds)
111111

0 commit comments

Comments
 (0)