Skip to content
23 changes: 22 additions & 1 deletion python/cudf/cudf/core/groupby/groupby.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,28 @@ def _is_all_scan_aggregate(all_aggs: list[list[str]]) -> bool:
}

def get_name(agg):
return agg.__name__ if callable(agg) else agg
if not callable(agg):
return agg
if agg is not list:
# A ``lambda x: x.cumsum()``-style aggregation carries its
# scan-ness only in the aggregation name it resolves to
# (``Aggregation.cumsum`` is an alias of ``sum``; libcudf
# separates scan from reduction by the *call*, not the
# aggregation object). Probe the callable with a
# name-recording stand-in mirroring ``make_aggregation``'s
# ``op(Aggregation)`` protocol; true UDFs raise inside the
# probe and fall back to ``__name__``.
class _NameProbe:
def __getattr__(self, name):
return lambda *args, **kwargs: name

try:
name = agg(_NameProbe())
except Exception:
return agg.__name__
if isinstance(name, str):
return name
return agg.__name__

all_scan = all(
get_name(agg_name) in groupby_scans
Expand Down
2 changes: 0 additions & 2 deletions python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1921,8 +1921,6 @@ def pytest_unconfigure(config):
"tests/groupby/test_reductions.py::test_sum_skipna_object[False]": "Inherent cudf.pandas None-vs-NaN difference for object-dtype null (skipna logic is correct)",
"tests/groupby/test_timegrouper.py::TestGroupBy::test_groupby_with_timegrouper": "TODO: Add a reason for failure",
"tests/groupby/test_timegrouper.py::TestGroupBy::test_scalar_call_versus_list_call": "TODO: Add a reason for failure",
"tests/groupby/transform/test_transform.py::test_cython_transform_series[cumprod-args0-<lambda>]": "TODO: Add a reason for failure",
"tests/groupby/transform/test_transform.py::test_cython_transform_series[cumsum-args1-<lambda>]": "TODO: Add a reason for failure",
"tests/groupby/transform/test_transform.py::test_nan_in_cumsum_group_label": "AssertionError: Attributes of Series are different",
"tests/indexes/base_class/test_reshape.py::TestReshape::test_insert_missing[Decimal]": "TODO: Add a reason for failure",
"tests/indexes/categorical/test_astype.py::TestAstype::test_categorical_date_roundtrip[False]": "TODO: Add a reason for failure",
Expand Down
12 changes: 12 additions & 0 deletions python/cudf/cudf/tests/groupby/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,15 @@ def test_transform_cumcount_series(dropna):
expect = pdf.groupby("A", dropna=dropna).transform("cumcount")
got = gdf.groupby("A", dropna=dropna).transform("cumcount")
assert_eq(expect, got)


def test_transform_scan_lambda():
# a named-aggregation lambda resolving to a scan must scan per group,
# not broadcast the group total
pdf = pd.DataFrame({"key": [0, 0, 1, 1], "val": [1.0, 2.0, 3.0, 4.0]})
gdf = cudf.DataFrame(pdf)

expect = pdf.groupby("key")["val"].transform(lambda x: x.cumsum())
got = gdf.groupby("key")["val"].transform(lambda x: x.cumsum())

assert_eq(expect, got)
Comment on lines +124 to +133

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Expand scan-lambda regression coverage.

This test covers only cumsum on a simple non-null float input. Parameterize the regression for cumsum and cumprod, and add empty, all-null, single-element, and mixed-type cases. Add a unit benchmark for this bug fix as required by the repository guidelines.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cudf/cudf/tests/groupby/test_transform.py` around lines 82 - 91,
Expand test_transform_scan_lambda to parameterize both cumsum and cumprod across
empty, all-null, single-element, and mixed-type inputs, while retaining expected
pandas-versus-cuDF comparisons for each case. Add the repository-required unit
benchmark covering this scan-lambda regression.

Source: Coding guidelines

Loading