Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 47 additions & 13 deletions narwhals/_compliant/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
from narwhals._compliant.typing import EagerDataFrameT
from narwhals._compliant.typing import EagerExprT
from narwhals._compliant.typing import EagerSeriesT
from narwhals._compliant.typing import NativeExprT_co
from narwhals._compliant.typing import LazyExprT
from narwhals._compliant.typing import NativeExprT
from narwhals._expression_parsing import evaluate_output_names_and_aliases
from narwhals.dependencies import get_numpy
from narwhals.dependencies import is_numpy_array
Expand Down Expand Up @@ -868,9 +869,9 @@ def struct(self) -> EagerExprStructNamespace[Self]:
return EagerExprStructNamespace(self)


class LazyExpr(
CompliantExpr[CompliantLazyFrameT, NativeExprT_co],
Protocol38[CompliantLazyFrameT, NativeExprT_co],
class LazyExpr( # type: ignore[misc]
CompliantExpr[CompliantLazyFrameT, NativeExprT],
Protocol38[CompliantLazyFrameT, NativeExprT],
Comment on lines +872 to +874
Copy link
Member Author

Choose a reason for hiding this comment

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

mypy and pyright disagreeing on variance - nothing to be alarmed at here πŸ™‚

):
arg_min: not_implemented = not_implemented()
arg_max: not_implemented = not_implemented()
Expand All @@ -891,7 +892,12 @@ class LazyExpr(
def _is_expr(cls, obj: Self | Any) -> TypeIs[Self]:
return hasattr(obj, "__narwhals_expr__")

def _with_callable(self: Self, call: Callable[..., Any], /) -> Self: ...
def _with_callable(self, call: Callable[..., Any], /) -> Self: ...
def _with_alias_output_names(self, func: AliasNames | None, /) -> Self: ...

@property
def name(self) -> LazyExprNameNamespace[Self]:
return LazyExprNameNamespace(self)


class _ExprNamespace( # type: ignore[misc]
Expand All @@ -909,6 +915,11 @@ def __init__(self, expr: EagerExprT, /) -> None:
self._compliant_expr = expr


class LazyExprNamespace(_ExprNamespace[LazyExprT], Generic[LazyExprT]):
def __init__(self, expr: LazyExprT, /) -> None:
self._compliant_expr = expr


class EagerExprCatNamespace(
EagerExprNamespace[EagerExprT], CatNamespace[EagerExprT], Generic[EagerExprT]
):
Expand Down Expand Up @@ -996,25 +1007,27 @@ def len(self) -> EagerExprT:
return self.compliant._reuse_series_namespace("list", "len")


class EagerExprNameNamespace(
EagerExprNamespace[EagerExprT], NameNamespace[EagerExprT], Generic[EagerExprT]
class CompliantExprNameNamespace( # type: ignore[misc]
_ExprNamespace[CompliantExprT_co],
NameNamespace[CompliantExprT_co],
Protocol[CompliantExprT_co],
):
def keep(self) -> EagerExprT:
def keep(self) -> CompliantExprT_co:
return self._from_callable(lambda name: name, alias=False)

def map(self, function: AliasName) -> EagerExprT:
def map(self, function: AliasName) -> CompliantExprT_co:
return self._from_callable(function)

def prefix(self, prefix: str) -> EagerExprT:
def prefix(self, prefix: str) -> CompliantExprT_co:
return self._from_callable(lambda name: f"{prefix}{name}")

def suffix(self, suffix: str) -> EagerExprT:
def suffix(self, suffix: str) -> CompliantExprT_co:
return self._from_callable(lambda name: f"{name}{suffix}")

def to_lowercase(self) -> EagerExprT:
def to_lowercase(self) -> CompliantExprT_co:
return self._from_callable(str.lower)

def to_uppercase(self) -> EagerExprT:
def to_uppercase(self) -> CompliantExprT_co:
return self._from_callable(str.upper)

@staticmethod
Expand All @@ -1024,6 +1037,16 @@ def fn(output_names: Sequence[str], /) -> Sequence[str]:

return fn

def _from_callable(
self, func: AliasName, /, *, alias: bool = True
) -> CompliantExprT_co: ...


class EagerExprNameNamespace(
EagerExprNamespace[EagerExprT],
CompliantExprNameNamespace[EagerExprT],
Generic[EagerExprT],
):
def _from_callable(self, func: AliasName, /, *, alias: bool = True) -> EagerExprT:
expr = self.compliant
return type(expr)(
Expand All @@ -1042,6 +1065,17 @@ def _from_callable(self, func: AliasName, /, *, alias: bool = True) -> EagerExpr
)


class LazyExprNameNamespace(
LazyExprNamespace[LazyExprT],
CompliantExprNameNamespace[LazyExprT],
Generic[LazyExprT],
):
def _from_callable(self, func: AliasName, /, *, alias: bool = True) -> LazyExprT:
expr = self.compliant
output_names = self._alias_output_names(func) if alias else None
return expr._with_alias_output_names(output_names)


class EagerExprStringNamespace(
EagerExprNamespace[EagerExprT], StringNamespace[EagerExprT], Generic[EagerExprT]
):
Expand Down
1 change: 1 addition & 0 deletions narwhals/_compliant/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
# NOTE: `pyright` gives false (8) positives if this uses `EagerDataFrameAny`?
EagerDataFrameT = TypeVar("EagerDataFrameT", bound="EagerDataFrame[Any, Any, Any]")

LazyExprT = TypeVar("LazyExprT", bound=LazyExprAny)
LazyExprT_contra = TypeVar("LazyExprT_contra", bound=LazyExprAny, contravariant=True)

AliasNames: TypeAlias = Callable[[Sequence[str]], Sequence[str]]
Expand Down
18 changes: 13 additions & 5 deletions narwhals/_dask/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from narwhals._compliant import LazyExpr
from narwhals._compliant.expr import DepthTrackingExpr
from narwhals._dask.expr_dt import DaskExprDateTimeNamespace
from narwhals._dask.expr_name import DaskExprNameNamespace
from narwhals._dask.expr_str import DaskExprStringNamespace
from narwhals._dask.utils import add_row_index
from narwhals._dask.utils import maybe_evaluate_expr
Expand All @@ -25,6 +24,7 @@
from narwhals.utils import not_implemented

if TYPE_CHECKING:
from narwhals._compliant.typing import AliasNames
from narwhals._expression_parsing import ExprKind

try:
Expand Down Expand Up @@ -183,6 +183,18 @@ def func(df: DaskLazyFrame) -> list[dx.Series]:
call_kwargs=call_kwargs,
)

def _with_alias_output_names(self, func: AliasNames | None, /) -> Self:
return type(self)(
call=self._call,
depth=self._depth,
function_name=self._function_name,
evaluate_output_names=self._evaluate_output_names,
alias_output_names=func,
backend_version=self._backend_version,
version=self._version,
call_kwargs=self._call_kwargs,
)

def alias(self: Self, name: str) -> Self:
def alias_output_names(names: Sequence[str]) -> Sequence[str]:
if len(names) != 1:
Expand Down Expand Up @@ -668,9 +680,5 @@ def str(self: Self) -> DaskExprStringNamespace:
def dt(self: Self) -> DaskExprDateTimeNamespace:
return DaskExprDateTimeNamespace(self)

@property
def name(self: Self) -> DaskExprNameNamespace:
return DaskExprNameNamespace(self)

list = not_implemented() # pyright: ignore[reportAssignmentType]
struct = not_implemented() # pyright: ignore[reportAssignmentType]
68 changes: 0 additions & 68 deletions narwhals/_dask/expr_name.py

This file was deleted.

15 changes: 10 additions & 5 deletions narwhals/_duckdb/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from narwhals._compliant import LazyExpr
from narwhals._duckdb.expr_dt import DuckDBExprDateTimeNamespace
from narwhals._duckdb.expr_list import DuckDBExprListNamespace
from narwhals._duckdb.expr_name import DuckDBExprNameNamespace
from narwhals._duckdb.expr_str import DuckDBExprStringNamespace
from narwhals._duckdb.expr_struct import DuckDBExprStructNamespace
from narwhals._duckdb.utils import WindowInputs
Expand All @@ -34,6 +33,7 @@
import duckdb
from typing_extensions import Self

from narwhals._compliant.typing import AliasNames
from narwhals._duckdb.dataframe import DuckDBLazyFrame
from narwhals._duckdb.namespace import DuckDBNamespace
from narwhals._duckdb.typing import WindowFunction
Expand Down Expand Up @@ -235,6 +235,15 @@ def func(df: DuckDBLazyFrame) -> list[duckdb.Expression]:
version=self._version,
)

def _with_alias_output_names(self, func: AliasNames | None, /) -> Self:
return type(self)(
call=self._call,
evaluate_output_names=self._evaluate_output_names,
alias_output_names=func,
backend_version=self._backend_version,
version=self._version,
)

def _with_window_function(
self: Self,
window_function: WindowFunction,
Expand Down Expand Up @@ -691,10 +700,6 @@ def str(self: Self) -> DuckDBExprStringNamespace:
def dt(self: Self) -> DuckDBExprDateTimeNamespace:
return DuckDBExprDateTimeNamespace(self)

@property
def name(self: Self) -> DuckDBExprNameNamespace:
return DuckDBExprNameNamespace(self)

@property
def list(self: Self) -> DuckDBExprListNamespace:
return DuckDBExprListNamespace(self)
Expand Down
65 changes: 0 additions & 65 deletions narwhals/_duckdb/expr_name.py

This file was deleted.

16 changes: 11 additions & 5 deletions narwhals/_spark_like/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from narwhals._expression_parsing import ExprKind
from narwhals._spark_like.expr_dt import SparkLikeExprDateTimeNamespace
from narwhals._spark_like.expr_list import SparkLikeExprListNamespace
from narwhals._spark_like.expr_name import SparkLikeExprNameNamespace
from narwhals._spark_like.expr_str import SparkLikeExprStringNamespace
from narwhals._spark_like.expr_struct import SparkLikeExprStructNamespace
from narwhals._spark_like.utils import WindowInputs
Expand All @@ -30,6 +29,7 @@
from sqlframe.base.window import Window
from typing_extensions import Self

from narwhals._compliant.typing import AliasNames
from narwhals._expression_parsing import ExprMetadata
from narwhals._spark_like.dataframe import SparkLikeLazyFrame
from narwhals._spark_like.namespace import SparkLikeNamespace
Expand Down Expand Up @@ -274,6 +274,16 @@ def func(df: SparkLikeLazyFrame) -> list[Column]:
implementation=self._implementation,
)

def _with_alias_output_names(self, func: AliasNames | None, /) -> Self:
return type(self)(
call=self._call,
evaluate_output_names=self._evaluate_output_names,
alias_output_names=func,
backend_version=self._backend_version,
version=self._version,
implementation=self._implementation,
)

def __eq__(self: Self, other: SparkLikeExpr) -> Self: # type: ignore[override]
return self._with_callable(
lambda _input, other: _input.__eq__(other), other=other
Expand Down Expand Up @@ -750,10 +760,6 @@ def rolling_std(
def str(self: Self) -> SparkLikeExprStringNamespace:
return SparkLikeExprStringNamespace(self)

@property
def name(self: Self) -> SparkLikeExprNameNamespace:
return SparkLikeExprNameNamespace(self)

@property
def dt(self: Self) -> SparkLikeExprDateTimeNamespace:
return SparkLikeExprDateTimeNamespace(self)
Expand Down
Loading
Loading