You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by el...@apache.org on 2026/08/17 16:14:44 UTC
(superset) 01/01: fix(pandas_postprocessing): map bare numpy callable aggregators to string names for GroupBy.agg
This is an automated email from the ASF dual-hosted git repository.
eschutho pushed a commit to branch fix-groupby-agg-median-callable-warning
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 05bb34ae78ad02768053f44f57af90fbf6c2cc4c
Author: Elizabeth Thompson <es...@gmail.com>
AuthorDate: Mon Aug 17 16:10:50 2026 +0000
fix(pandas_postprocessing): map bare numpy callable aggregators to string names for GroupBy.agg
A bare numpy callable operator (e.g. np.median) passed through to
GroupBy.agg triggers a pandas FutureWarning:
FutureWarning: The provided callable <function median ...> is currently
using SeriesGroupBy.median. In a future version of pandas, the provided
callable will be used directly. To keep current behavior pass the string
"median" instead.
The existing _PANDAS_STRING_AGGREGATORS fix only covered string operators;
the callable-operator branch of _get_aggregate_funcs still forwarded the raw
numpy callable. Add a reverse lookup (reusing NUMPY_FUNCTIONS and
_PANDAS_STRING_AGGREGATORS) and swap such callables for their string name
before calling .agg(). Non-mapped callables, string operators, and
partial(func, **options) paths are unchanged, so results and dtypes are
identical.
Co-Authored-By: Claude Opus 4.8 <no...@anthropic.com>
---
superset/utils/pandas_postprocessing/utils.py | 15 ++++++++++++++-
.../pandas_postprocessing/test_aggregate.py | 21 +++++++++++++++++++++
2 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/superset/utils/pandas_postprocessing/utils.py b/superset/utils/pandas_postprocessing/utils.py
index aa2667ed9d5..3ec1e743749 100644
--- a/superset/utils/pandas_postprocessing/utils.py
+++ b/superset/utils/pandas_postprocessing/utils.py
@@ -61,6 +61,15 @@ _PANDAS_STRING_AGGREGATORS: frozenset[str] = frozenset(
{"max", "mean", "median", "min", "prod", "std", "sum", "var"}
)
+# Reverse lookup from the numpy callables above to their pandas string name, so a
+# bare callable operator (e.g. np.median) can be swapped for the string form before
+# reaching GroupBy.agg and avoid the same FutureWarning.
+_STRING_AGGREGATOR_BY_CALLABLE: dict[Callable[..., Any], str] = {
+ func: name
+ for name, func in NUMPY_FUNCTIONS.items()
+ if name in _PANDAS_STRING_AGGREGATORS
+}
+
DENYLIST_ROLLING_FUNCTIONS = (
"count",
"corr",
@@ -173,7 +182,11 @@ def _get_aggregate_funcs(
)
operator = agg_obj["operator"]
if callable(operator):
- aggfunc: str | Callable[..., Any] = operator
+ # A bare numpy callable (e.g. np.median) that pandas maps to its own
+ # GroupBy method triggers a FutureWarning; use the string name instead.
+ aggfunc: str | Callable[..., Any] = _STRING_AGGREGATOR_BY_CALLABLE.get(
+ operator, operator
+ )
else:
func = NUMPY_FUNCTIONS.get(operator)
if not func:
diff --git a/tests/unit_tests/pandas_postprocessing/test_aggregate.py b/tests/unit_tests/pandas_postprocessing/test_aggregate.py
index 10ac70f4349..7a715010b2a 100644
--- a/tests/unit_tests/pandas_postprocessing/test_aggregate.py
+++ b/tests/unit_tests/pandas_postprocessing/test_aggregate.py
@@ -14,6 +14,10 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
+import warnings
+
+import numpy as np
+
from superset.utils.pandas_postprocessing import aggregate
from tests.unit_tests.fixtures.dataframes import categories_df
from tests.unit_tests.pandas_postprocessing.utils import series_to_list
@@ -56,6 +60,23 @@ def test_aggregate_string_operators():
assert series_to_list(df["asc min"])[0] == 0
+def test_aggregate_callable_operator_avoids_future_warning():
+ """A bare numpy callable operator (e.g. np.median) that pandas maps to its own
+ GroupBy method must be swapped for the string form so GroupBy.agg does not raise
+ a FutureWarning, while producing the same result as the string operator."""
+ aggregates = {
+ "asc median": {"column": "asc_idx", "operator": np.median},
+ "asc mean": {"column": "asc_idx", "operator": np.mean},
+ "asc sum": {"column": "asc_idx", "operator": np.sum},
+ }
+ with warnings.catch_warnings():
+ warnings.simplefilter("error", FutureWarning)
+ df = aggregate(df=categories_df, groupby=["constant"], aggregates=aggregates)
+ assert series_to_list(df["asc median"])[0] == 50.0
+ assert series_to_list(df["asc mean"])[0] == 50.0
+ assert series_to_list(df["asc sum"])[0] == 5050
+
+
def test_aggregate_count_includes_nulls():
"""'count' operator uses np.ma.count, which counts all rows including NaN.
It is intentionally excluded from _PANDAS_STRING_AGGREGATORS to preserve this