fix(checker): compute aggregation of column groupby

This commit is contained in:
2026-07-07 17:07:20 +02:00
parent f3dec414cc
commit 25c11c3a53
2 changed files with 30 additions and 12 deletions

View File

@@ -12,8 +12,8 @@ from midas.checker.types import (
ColumnType, ColumnType,
Function, Function,
ParamSpec, ParamSpec,
TopType,
Type, Type,
UnknownType,
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -49,9 +49,8 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
def _aggregate( def _aggregate(
self, self,
call: Call, call: Call,
method: str,
params: list[str | tuple[str, str, bool]] = [], params: list[str | tuple[str, str, bool]] = [],
*,
preserve_inner_type: bool = False,
) -> Type: ) -> Type:
"""Compute the result type of an aggregate method call """Compute the result type of an aggregate method call
@@ -87,13 +86,21 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
) )
real_params.append(param) real_params.append(param)
# TODO: maybe better to filter arguments and pass some, in case the
# return type depends on them
returns: Type = self.typer.call_method(
location=call.location,
call_expr=call.call_expr,
obj=(call.groupby_expr, call.groupby.column),
method_name=method,
positional=[],
keywords={},
)
if not isinstance(returns, ColumnType):
returns = ColumnType(type=UnknownType())
signature = Function( signature = Function(
params=ParamSpec(mixed=real_params), params=ParamSpec(mixed=real_params),
returns=( returns=returns,
call.groupby.column
if preserve_inner_type
else ColumnType(type=TopType())
),
) )
result: CallResult = self.dispatcher.get_result( result: CallResult = self.dispatcher.get_result(
@@ -108,6 +115,7 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
def kurt(self, call: Call) -> Type: def kurt(self, call: Call) -> Type:
return self._aggregate( return self._aggregate(
call, call,
"kurt",
["skipna", "numeric_only"], ["skipna", "numeric_only"],
) )
@@ -115,6 +123,7 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
def max(self, call: Call) -> Type: def max(self, call: Call) -> Type:
return self._aggregate( return self._aggregate(
call, call,
"max",
[ [
"numeric_only", "numeric_only",
( (
@@ -126,13 +135,13 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
"engine", "engine",
"engine_kwargs", "engine_kwargs",
], ],
preserve_inner_type=True,
) )
@method() @method()
def mean(self, call: Call) -> Type: def mean(self, call: Call) -> Type:
return self._aggregate( return self._aggregate(
call, call,
"mean",
["numeric_only", "skipna", "engine", "engine_kwargs"], ["numeric_only", "skipna", "engine", "engine_kwargs"],
) )
@@ -140,14 +149,15 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
def median(self, call: Call) -> Type: def median(self, call: Call) -> Type:
return self._aggregate( return self._aggregate(
call, call,
"median",
["numeric_only", "skipna"], ["numeric_only", "skipna"],
preserve_inner_type=True,
) )
@method() @method()
def min(self, call: Call) -> Type: def min(self, call: Call) -> Type:
return self._aggregate( return self._aggregate(
call, call,
"min",
[ [
"numeric_only", "numeric_only",
( (
@@ -159,13 +169,13 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
"engine", "engine",
"engine_kwargs", "engine_kwargs",
], ],
preserve_inner_type=True,
) )
@method() @method()
def prod(self, call: Call) -> Type: def prod(self, call: Call) -> Type:
return self._aggregate( return self._aggregate(
call, call,
"prod",
[ [
"numeric_only", "numeric_only",
( (
@@ -181,6 +191,7 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
def std(self, call: Call) -> Type: def std(self, call: Call) -> Type:
return self._aggregate( return self._aggregate(
call, call,
"std",
[ [
( (
"ddof", "ddof",
@@ -198,6 +209,7 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
def sum(self, call: Call) -> Type: def sum(self, call: Call) -> Type:
return self._aggregate( return self._aggregate(
call, call,
"sum",
[ [
"numeric_only", "numeric_only",
( (
@@ -215,6 +227,7 @@ class ColumnGroupByMethodRegistry(MethodRegistry[Call]):
def var(self, call: Call) -> Type: def var(self, call: Call) -> Type:
return self._aggregate( return self._aggregate(
call, call,
"var",
[ [
( (
"var", "var",

View File

@@ -318,7 +318,12 @@ class ColumnMethodRegistry(MethodRegistry[Call]):
returns: Type = ColumnType(type=TopType()) returns: Type = ColumnType(type=TopType())
if formula: if formula:
returns = self._resolve_formula_type(call, formula(call.column.type)) returns = ColumnType(
type=self._resolve_formula_type(
call,
formula(call.column.type),
)
)
signature = Function( signature = Function(
params=ParamSpec( params=ParamSpec(
kw=[ kw=[