Skip to content

Commit ea30f26

Browse files
committed
fix: Update IbisExpr.first
2/3 for #2528 (comment)
1 parent ecaca9a commit ea30f26

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

narwhals/_ibis/expr.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
from narwhals._utils import Implementation, not_implemented
2626

2727
if TYPE_CHECKING:
28+
from typing import Union
29+
2830
import ibis.expr.types as ir
29-
from typing_extensions import Self
31+
from typing_extensions import Self, TypeAlias
3032

3133
from narwhals._compliant.typing import (
3234
AliasNames,
@@ -44,6 +46,10 @@
4446
IbisWindowFunction = WindowFunction[IbisLazyFrame, ir.Value]
4547
IbisWindowInputs = WindowInputs[ir.Value]
4648

49+
# NOTE: Needed to avoid `ibis` metaclass shenanigans breaking `__or__`
50+
# > Expected class but received "UnionType` Pylance(reportGeneralTypeIssues)
51+
LegacyWindow: TypeAlias = Union[ir.bl.LegacyWindowBuilder, None]
52+
4753

4854
class IbisExpr(LazyExpr["IbisLazyFrame", "ir.Column"]):
4955
_implementation = Implementation.IBIS
@@ -374,15 +380,22 @@ def sum(self) -> Self:
374380
return self._with_callable(lambda expr: expr.sum().fill_null(lit(0)))
375381

376382
def first(self) -> Self:
377-
def fn(inputs: IbisWindowInputs) -> ir.Value:
378-
order_by = [ibis.asc(by, nulls_first=True) for by in inputs.order_by]
379-
expr = cast("ir.Column", inputs.expr)
380-
if partition_by := inputs.partition_by: # pragma: no cover
381-
window = ibis.window(group_by=list(partition_by), order_by=order_by)
382-
return expr.first(include_null=True).over(window)
383+
def window(
384+
expr: ir.Value, order_by: Sequence[ir.Column], legacy: LegacyWindow
385+
) -> ir.Value:
386+
expr = cast("ir.Column", expr)
387+
if legacy: # pragma: no cover
388+
return expr.first(include_null=True).over(legacy)
383389
else:
384390
return expr.first(order_by=order_by, include_null=True)
385391

392+
def fn(df: IbisLazyFrame, inputs: IbisWindowInputs) -> Sequence[ir.Value]:
393+
legacy: LegacyWindow = None
394+
order_by = list(self._sort(*inputs.order_by))
395+
if group_by := inputs.partition_by: # pragma: no cover
396+
legacy = ibis.window(group_by=list(group_by), order_by=order_by)
397+
return [window(expr, order_by, legacy) for expr in self(df)]
398+
386399
return self._with_window_function(fn)
387400

388401
def n_unique(self) -> Self:

0 commit comments

Comments
 (0)