From d708aebac07af161dae527388267edcae1457369 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 18:35:19 +0100 Subject: [PATCH 01/14] refactor if-when-else --- narwhals/_arrow/namespace.py | 25 +++++++++++++++++-------- narwhals/_compliant/when_then.py | 7 ++++--- narwhals/_pandas_like/namespace.py | 14 ++++++++++---- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/narwhals/_arrow/namespace.py b/narwhals/_arrow/namespace.py index 2730ebaae9..b036f79ba9 100644 --- a/narwhals/_arrow/namespace.py +++ b/narwhals/_arrow/namespace.py @@ -24,7 +24,7 @@ from narwhals._utils import Implementation if TYPE_CHECKING: - from narwhals._arrow.typing import ArrayOrScalar, ChunkedArrayAny, Incomplete + from narwhals._arrow.typing import ChunkedArrayAny, Incomplete from narwhals._utils import Version from narwhals.dtypes import DType from narwhals.typing import NonNestedLiteral @@ -272,14 +272,23 @@ def _then(self) -> type[ArrowThen]: return ArrowThen def _if_then_else( - self, - when: ChunkedArrayAny, - then: ChunkedArrayAny, - otherwise: ArrayOrScalar | NonNestedLiteral, - /, + self, when: ArrowSeries, then: ArrowSeries, otherwise: ArrowSeries | None, / ) -> ChunkedArrayAny: - otherwise = pa.nulls(len(when), then.type) if otherwise is None else otherwise - return pc.if_else(when, then, otherwise) + from narwhals._arrow.utils import align_series_full_broadcast + + if otherwise is not None: + _when, _then, _otherwise = align_series_full_broadcast(when, then, otherwise) + _when = _when.native + _then = _then.native + _otherwise = _otherwise.native + else: + _when, _then = align_series_full_broadcast(when, then) + _when = _when.native + _then = _then.native + otherwise = ( + pa.nulls(len(when), _then.native.type) if otherwise is None else otherwise + ) + return pc.if_else(_when, _then, _otherwise) class ArrowThen(CompliantThen[ArrowDataFrame, ArrowSeries, ArrowExpr], ArrowExpr): ... diff --git a/narwhals/_compliant/when_then.py b/narwhals/_compliant/when_then.py index 37e70dcb55..99e350d122 100644 --- a/narwhals/_compliant/when_then.py +++ b/narwhals/_compliant/when_then.py @@ -165,10 +165,11 @@ def __call__(self, df: EagerDataFrameT, /) -> Sequence[EagerSeriesT]: then = when.alias("literal")._from_scalar(self._then_value) then._broadcast = True if is_expr(self._otherwise_value): - otherwise = df._extract_comparand(self._otherwise_value(df)[0]) + otherwise = self._otherwise_value(df)[0] else: - otherwise = self._otherwise_value - result = self._if_then_else(when.native, df._extract_comparand(then), otherwise) + otherwise = when._from_scalar(self._otherwise_value) + otherwise._broadcast = True + result = self._if_then_else(when, then, otherwise) return [then._with_native(result)] diff --git a/narwhals/_pandas_like/namespace.py b/narwhals/_pandas_like/namespace.py index bbff8bbc7e..ee4bfc0379 100644 --- a/narwhals/_pandas_like/namespace.py +++ b/narwhals/_pandas_like/namespace.py @@ -324,12 +324,18 @@ def _then(self) -> type[PandasThen]: def _if_then_else( self, - when: pd.Series[Any], - then: pd.Series[Any], - otherwise: pd.Series[Any] | NonNestedLiteral, + when: PandasLikeSeries, + then: PandasLikeSeries, + otherwise: PandasLikeSeries | None, /, ) -> pd.Series[Any]: - return then.where(when) if otherwise is None else then.where(when, otherwise) + from narwhals._pandas_like.utils import align_series_full_broadcast + + if otherwise is None: + when, then = align_series_full_broadcast(when, then) + return then.native.where(when.native) + when, then, otherwise = align_series_full_broadcast(when, then, otherwise) + return then.native.where(when.native, otherwise.native) class PandasThen( From 8dfc79aeab495953bd6d0918d3ced0e3b42a7aa7 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 18:36:17 +0100 Subject: [PATCH 02/14] refactor if-when-else --- narwhals/_arrow/namespace.py | 2 -- narwhals/_pandas_like/namespace.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/narwhals/_arrow/namespace.py b/narwhals/_arrow/namespace.py index b036f79ba9..8375ba3863 100644 --- a/narwhals/_arrow/namespace.py +++ b/narwhals/_arrow/namespace.py @@ -274,8 +274,6 @@ def _then(self) -> type[ArrowThen]: def _if_then_else( self, when: ArrowSeries, then: ArrowSeries, otherwise: ArrowSeries | None, / ) -> ChunkedArrayAny: - from narwhals._arrow.utils import align_series_full_broadcast - if otherwise is not None: _when, _then, _otherwise = align_series_full_broadcast(when, then, otherwise) _when = _when.native diff --git a/narwhals/_pandas_like/namespace.py b/narwhals/_pandas_like/namespace.py index ee4bfc0379..c9fe1a58c2 100644 --- a/narwhals/_pandas_like/namespace.py +++ b/narwhals/_pandas_like/namespace.py @@ -329,8 +329,6 @@ def _if_then_else( otherwise: PandasLikeSeries | None, /, ) -> pd.Series[Any]: - from narwhals._pandas_like.utils import align_series_full_broadcast - if otherwise is None: when, then = align_series_full_broadcast(when, then) return then.native.where(when.native) From bad8fed45766b350eb20389df51cd96f2ea0ff13 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 18:38:11 +0100 Subject: [PATCH 03/14] refactor if-when-else --- narwhals/_arrow/namespace.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/narwhals/_arrow/namespace.py b/narwhals/_arrow/namespace.py index 8375ba3863..bf5920f7be 100644 --- a/narwhals/_arrow/namespace.py +++ b/narwhals/_arrow/namespace.py @@ -274,19 +274,13 @@ def _then(self) -> type[ArrowThen]: def _if_then_else( self, when: ArrowSeries, then: ArrowSeries, otherwise: ArrowSeries | None, / ) -> ChunkedArrayAny: - if otherwise is not None: - _when, _then, _otherwise = align_series_full_broadcast(when, then, otherwise) - _when = _when.native - _then = _then.native - _otherwise = _otherwise.native - else: - _when, _then = align_series_full_broadcast(when, then) - _when = _when.native - _then = _then.native - otherwise = ( - pa.nulls(len(when), _then.native.type) if otherwise is None else otherwise + if otherwise is None: + when, then = align_series_full_broadcast(when, then) + return pc.if_else( + when.native, then.native, pa.nulls(len(when.native), then.native.type) ) - return pc.if_else(_when, _then, _otherwise) + when, then, otherwise = align_series_full_broadcast(when, then, otherwise) + return pc.if_else(when.native, then.native, otherwise.native) class ArrowThen(CompliantThen[ArrowDataFrame, ArrowSeries, ArrowExpr], ArrowExpr): ... From 29d625860570a16ee792cc21e727317446084ae8 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 18:53:05 +0100 Subject: [PATCH 04/14] try fixup --- narwhals/_compliant/when_then.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/narwhals/_compliant/when_then.py b/narwhals/_compliant/when_then.py index 99e350d122..7fcc3d9c2a 100644 --- a/narwhals/_compliant/when_then.py +++ b/narwhals/_compliant/when_then.py @@ -43,7 +43,7 @@ class CompliantWhen(Protocol38[FrameT, SeriesT, ExprT]): _condition: ExprT _then_value: IntoExpr[SeriesT, ExprT] - _otherwise_value: IntoExpr[SeriesT, ExprT] + _otherwise_value: IntoExpr[SeriesT, ExprT] | None _implementation: Implementation _backend_version: tuple[int, ...] _version: Version @@ -148,11 +148,7 @@ class EagerWhen( Protocol38[EagerDataFrameT, EagerSeriesT, EagerExprT, NativeSeriesT], ): def _if_then_else( - self, - when: NativeSeriesT, - then: NativeSeriesT, - otherwise: NativeSeriesT | NonNestedLiteral | Scalar, - /, + self, when: EagerSeriesT, then: EagerSeriesT, otherwise: EagerSeriesT | None, / ) -> NativeSeriesT: ... def __call__(self, df: EagerDataFrameT, /) -> Sequence[EagerSeriesT]: @@ -166,9 +162,11 @@ def __call__(self, df: EagerDataFrameT, /) -> Sequence[EagerSeriesT]: then._broadcast = True if is_expr(self._otherwise_value): otherwise = self._otherwise_value(df)[0] - else: + elif self._otherwise_value is not None: otherwise = when._from_scalar(self._otherwise_value) otherwise._broadcast = True + else: + otherwise = self._otherwise_value result = self._if_then_else(when, then, otherwise) return [then._with_native(result)] From aab3a7026a700e7f01ae1bb4e4049d1c219cb37f Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 19:07:50 +0100 Subject: [PATCH 05/14] try fixup --- narwhals/_arrow/namespace.py | 14 ++++++++------ narwhals/_compliant/namespace.py | 2 +- narwhals/_compliant/when_then.py | 8 +++----- narwhals/_pandas_like/namespace.py | 16 ++++++++-------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/narwhals/_arrow/namespace.py b/narwhals/_arrow/namespace.py index bf5920f7be..c0138d2775 100644 --- a/narwhals/_arrow/namespace.py +++ b/narwhals/_arrow/namespace.py @@ -24,7 +24,7 @@ from narwhals._utils import Implementation if TYPE_CHECKING: - from narwhals._arrow.typing import ChunkedArrayAny, Incomplete + from narwhals._arrow.typing import Incomplete from narwhals._utils import Version from narwhals.dtypes import DType from narwhals.typing import NonNestedLiteral @@ -266,21 +266,23 @@ def func(df: ArrowDataFrame) -> list[ArrowSeries]: ) -class ArrowWhen(EagerWhen[ArrowDataFrame, ArrowSeries, ArrowExpr, "ChunkedArrayAny"]): +class ArrowWhen(EagerWhen[ArrowDataFrame, ArrowSeries, ArrowExpr]): @property def _then(self) -> type[ArrowThen]: return ArrowThen def _if_then_else( self, when: ArrowSeries, then: ArrowSeries, otherwise: ArrowSeries | None, / - ) -> ChunkedArrayAny: + ) -> ArrowSeries: if otherwise is None: when, then = align_series_full_broadcast(when, then) - return pc.if_else( + res_native = pc.if_else( when.native, then.native, pa.nulls(len(when.native), then.native.type) ) - when, then, otherwise = align_series_full_broadcast(when, then, otherwise) - return pc.if_else(when.native, then.native, otherwise.native) + else: + when, then, otherwise = align_series_full_broadcast(when, then, otherwise) + res_native = pc.if_else(when.native, then.native, otherwise.native) + return then._with_native(res_native) class ArrowThen(CompliantThen[ArrowDataFrame, ArrowSeries, ArrowExpr], ArrowExpr): ... diff --git a/narwhals/_compliant/namespace.py b/narwhals/_compliant/namespace.py index d0440152a8..2a7188f741 100644 --- a/narwhals/_compliant/namespace.py +++ b/narwhals/_compliant/namespace.py @@ -140,7 +140,7 @@ def _dataframe(self) -> type[EagerDataFrameT]: ... def _series(self) -> type[EagerSeriesT]: ... def when( self, predicate: EagerExprT - ) -> EagerWhen[EagerDataFrameT, EagerSeriesT, EagerExprT, NativeSeriesT]: ... + ) -> EagerWhen[EagerDataFrameT, EagerSeriesT, EagerExprT]: ... @overload def from_native(self, data: NativeFrameT, /) -> EagerDataFrameT: ... diff --git a/narwhals/_compliant/when_then.py b/narwhals/_compliant/when_then.py index 7fcc3d9c2a..a2a2b4fe78 100644 --- a/narwhals/_compliant/when_then.py +++ b/narwhals/_compliant/when_then.py @@ -13,7 +13,6 @@ EagerSeriesT, LazyExprAny, NativeExprT, - NativeSeriesT, WindowFunction, ) from narwhals._typing_compat import Protocol38 @@ -145,11 +144,11 @@ def from_when( class EagerWhen( CompliantWhen[EagerDataFrameT, EagerSeriesT, EagerExprT], - Protocol38[EagerDataFrameT, EagerSeriesT, EagerExprT, NativeSeriesT], + Protocol38[EagerDataFrameT, EagerSeriesT, EagerExprT], ): def _if_then_else( self, when: EagerSeriesT, then: EagerSeriesT, otherwise: EagerSeriesT | None, / - ) -> NativeSeriesT: ... + ) -> EagerSeriesT: ... def __call__(self, df: EagerDataFrameT, /) -> Sequence[EagerSeriesT]: is_expr = self._condition._is_expr @@ -167,8 +166,7 @@ def __call__(self, df: EagerDataFrameT, /) -> Sequence[EagerSeriesT]: otherwise._broadcast = True else: otherwise = self._otherwise_value - result = self._if_then_else(when, then, otherwise) - return [then._with_native(result)] + return [self._if_then_else(when, then, otherwise)] class LazyWhen( diff --git a/narwhals/_pandas_like/namespace.py b/narwhals/_pandas_like/namespace.py index c9fe1a58c2..bfcf14acb9 100644 --- a/narwhals/_pandas_like/namespace.py +++ b/narwhals/_pandas_like/namespace.py @@ -3,7 +3,7 @@ import operator import warnings from functools import reduce -from typing import TYPE_CHECKING, Any, Literal, Sequence +from typing import TYPE_CHECKING, Literal, Sequence from narwhals._compliant import CompliantThen, EagerNamespace, EagerWhen from narwhals._expression_parsing import ( @@ -315,9 +315,7 @@ def func(df: PandasLikeDataFrame) -> list[PandasLikeSeries]: ) -class PandasWhen( - EagerWhen[PandasLikeDataFrame, PandasLikeSeries, PandasLikeExpr, "pd.Series[Any]"] -): +class PandasWhen(EagerWhen[PandasLikeDataFrame, PandasLikeSeries, PandasLikeExpr]): @property def _then(self) -> type[PandasThen]: return PandasThen @@ -328,12 +326,14 @@ def _if_then_else( then: PandasLikeSeries, otherwise: PandasLikeSeries | None, /, - ) -> pd.Series[Any]: + ) -> PandasLikeSeries: if otherwise is None: when, then = align_series_full_broadcast(when, then) - return then.native.where(when.native) - when, then, otherwise = align_series_full_broadcast(when, then, otherwise) - return then.native.where(when.native, otherwise.native) + res_native = then.native.where(when.native) + else: + when, then, otherwise = align_series_full_broadcast(when, then, otherwise) + res_native = then.native.where(when.native, otherwise.native) + return then._with_native(res_native) class PandasThen( From cdf57d9c2fc21e876309ef2b260645415a1feded Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 19:15:05 +0100 Subject: [PATCH 06/14] chunkedarrayany import --- narwhals/_arrow/namespace.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/narwhals/_arrow/namespace.py b/narwhals/_arrow/namespace.py index c0138d2775..2496a3d4c7 100644 --- a/narwhals/_arrow/namespace.py +++ b/narwhals/_arrow/namespace.py @@ -12,6 +12,7 @@ from narwhals._arrow.expr import ArrowExpr from narwhals._arrow.selectors import ArrowSelectorNamespace from narwhals._arrow.series import ArrowSeries +from narwhals._arrow.typing import ChunkedArrayAny from narwhals._arrow.utils import ( align_series_full_broadcast, cast_to_comparable_string_types, @@ -31,7 +32,7 @@ class ArrowNamespace( - EagerNamespace[ArrowDataFrame, ArrowSeries, ArrowExpr, "pa.Table", "ChunkedArrayAny"] + EagerNamespace[ArrowDataFrame, ArrowSeries, ArrowExpr, pa.Table, ChunkedArrayAny] ): @property def _dataframe(self) -> type[ArrowDataFrame]: From 3c7eb58ec846bd092cc1157b04d57a90941aa7df Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 19:16:37 +0100 Subject: [PATCH 07/14] any import --- narwhals/_pandas_like/namespace.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/narwhals/_pandas_like/namespace.py b/narwhals/_pandas_like/namespace.py index bfcf14acb9..d99fd99bfb 100644 --- a/narwhals/_pandas_like/namespace.py +++ b/narwhals/_pandas_like/namespace.py @@ -3,7 +3,9 @@ import operator import warnings from functools import reduce -from typing import TYPE_CHECKING, Literal, Sequence +from typing import TYPE_CHECKING, Any, Literal, Sequence + +import pandas as pd from narwhals._compliant import CompliantThen, EagerNamespace, EagerWhen from narwhals._expression_parsing import ( @@ -17,8 +19,6 @@ from narwhals._pandas_like.utils import align_series_full_broadcast if TYPE_CHECKING: - import pandas as pd - from narwhals._pandas_like.typing import NDFrameT from narwhals._utils import Implementation, Version from narwhals.dtypes import DType @@ -33,8 +33,8 @@ class PandasLikeNamespace( PandasLikeDataFrame, PandasLikeSeries, PandasLikeExpr, - "pd.DataFrame", - "pd.Series[Any]", + pd.DataFrame, + pd.Series[Any], ] ): @property From c8b4f0a3ebb08a92fd312ac27813f48e651e88ba Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 19:18:58 +0100 Subject: [PATCH 08/14] any import --- narwhals/_pandas_like/namespace.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/narwhals/_pandas_like/namespace.py b/narwhals/_pandas_like/namespace.py index d99fd99bfb..cffa0b916b 100644 --- a/narwhals/_pandas_like/namespace.py +++ b/narwhals/_pandas_like/namespace.py @@ -3,7 +3,7 @@ import operator import warnings from functools import reduce -from typing import TYPE_CHECKING, Any, Literal, Sequence +from typing import TYPE_CHECKING, Literal, Sequence import pandas as pd @@ -34,7 +34,7 @@ class PandasLikeNamespace( PandasLikeSeries, PandasLikeExpr, pd.DataFrame, - pd.Series[Any], + "pd.Series[Any]", ] ): @property From c4974f7ecb3aa08ae8873f02770d8bd299574471 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 19:19:18 +0100 Subject: [PATCH 09/14] any import --- narwhals/_pandas_like/namespace.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/narwhals/_pandas_like/namespace.py b/narwhals/_pandas_like/namespace.py index cffa0b916b..7d9df1e1ac 100644 --- a/narwhals/_pandas_like/namespace.py +++ b/narwhals/_pandas_like/namespace.py @@ -19,6 +19,8 @@ from narwhals._pandas_like.utils import align_series_full_broadcast if TYPE_CHECKING: + from typing import Any # noqa: F401 + from narwhals._pandas_like.typing import NDFrameT from narwhals._utils import Implementation, Version from narwhals.dtypes import DType From 5a5f7a7915e217e6169ac33e62a7a648a4b9442f Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 19:28:10 +0100 Subject: [PATCH 10/14] imports --- narwhals/_arrow/namespace.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/narwhals/_arrow/namespace.py b/narwhals/_arrow/namespace.py index 2496a3d4c7..fe50764997 100644 --- a/narwhals/_arrow/namespace.py +++ b/narwhals/_arrow/namespace.py @@ -12,7 +12,6 @@ from narwhals._arrow.expr import ArrowExpr from narwhals._arrow.selectors import ArrowSelectorNamespace from narwhals._arrow.series import ArrowSeries -from narwhals._arrow.typing import ChunkedArrayAny from narwhals._arrow.utils import ( align_series_full_broadcast, cast_to_comparable_string_types, @@ -25,14 +24,17 @@ from narwhals._utils import Implementation if TYPE_CHECKING: - from narwhals._arrow.typing import Incomplete + from narwhals._arrow.typing import ( + ChunkedArrayAny, # noqa: F401 + Incomplete, + ) from narwhals._utils import Version from narwhals.dtypes import DType from narwhals.typing import NonNestedLiteral class ArrowNamespace( - EagerNamespace[ArrowDataFrame, ArrowSeries, ArrowExpr, pa.Table, ChunkedArrayAny] + EagerNamespace[ArrowDataFrame, ArrowSeries, ArrowExpr, pa.Table, "ChunkedArrayAny"] ): @property def _dataframe(self) -> type[ArrowDataFrame]: From 20793f57a5004cb2c022f478c1436647eb9b32fa Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 10 Jun 2025 23:22:41 +0100 Subject: [PATCH 11/14] just silence type checkers --- narwhals/_compliant/namespace.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/narwhals/_compliant/namespace.py b/narwhals/_compliant/namespace.py index 2a7188f741..2d47baac31 100644 --- a/narwhals/_compliant/namespace.py +++ b/narwhals/_compliant/namespace.py @@ -130,7 +130,8 @@ def from_native(self, data: NativeFrameT_co | Any, /) -> CompliantLazyFrameT: raise TypeError(msg) -class EagerNamespace( +# Invariant type variable "NativeSeriesT" used in protocol where covariant one is expected +class EagerNamespace( # type: ignore[misc] DepthTrackingNamespace[EagerDataFrameT, EagerExprT], Protocol[EagerDataFrameT, EagerSeriesT, EagerExprT, NativeFrameT, NativeSeriesT], ): From e19d5e17ce089ecea4944eae6e2753832bb8c730 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Wed, 11 Jun 2025 10:49:59 +0100 Subject: [PATCH 12/14] remove NativeSeriesT from EagerDataFrame / EagerNamespace --- narwhals/_arrow/dataframe.py | 4 +--- narwhals/_arrow/namespace.py | 4 +--- narwhals/_compliant/dataframe.py | 15 +++++---------- narwhals/_compliant/expr.py | 2 +- narwhals/_compliant/namespace.py | 22 +++------------------- narwhals/_compliant/series.py | 4 +--- narwhals/_compliant/typing.py | 8 +++++--- narwhals/_pandas_like/dataframe.py | 4 +--- narwhals/_pandas_like/namespace.py | 8 +------- 9 files changed, 19 insertions(+), 52 deletions(-) diff --git a/narwhals/_arrow/dataframe.py b/narwhals/_arrow/dataframe.py index aef16939ca..e2168baa28 100644 --- a/narwhals/_arrow/dataframe.py +++ b/narwhals/_arrow/dataframe.py @@ -83,9 +83,7 @@ PromoteOptions: TypeAlias = Literal["none", "default", "permissive"] -class ArrowDataFrame( - EagerDataFrame["ArrowSeries", "ArrowExpr", "pa.Table", "ChunkedArrayAny"] -): +class ArrowDataFrame(EagerDataFrame["ArrowSeries", "ArrowExpr", "pa.Table"]): def __init__( self, native_dataframe: pa.Table, diff --git a/narwhals/_arrow/namespace.py b/narwhals/_arrow/namespace.py index fe50764997..a032c11d7a 100644 --- a/narwhals/_arrow/namespace.py +++ b/narwhals/_arrow/namespace.py @@ -33,9 +33,7 @@ from narwhals.typing import NonNestedLiteral -class ArrowNamespace( - EagerNamespace[ArrowDataFrame, ArrowSeries, ArrowExpr, pa.Table, "ChunkedArrayAny"] -): +class ArrowNamespace(EagerNamespace[ArrowDataFrame, ArrowSeries, ArrowExpr, pa.Table]): @property def _dataframe(self) -> type[ArrowDataFrame]: return ArrowDataFrame diff --git a/narwhals/_compliant/dataframe.py b/narwhals/_compliant/dataframe.py index 57226ff5b4..5f210550e6 100644 --- a/narwhals/_compliant/dataframe.py +++ b/narwhals/_compliant/dataframe.py @@ -23,7 +23,6 @@ EagerSeriesT, NativeExprT, NativeFrameT, - NativeSeriesT, ) from narwhals._translate import ( ArrowConvertible, @@ -402,11 +401,11 @@ def _check_columns_exist(self, subset: Sequence[str]) -> ColumnNotFoundError | N class EagerDataFrame( CompliantDataFrame[EagerSeriesT, EagerExprT, NativeFrameT, "DataFrame[NativeFrameT]"], CompliantLazyFrame[EagerExprT, NativeFrameT, "DataFrame[NativeFrameT]"], - Protocol[EagerSeriesT, EagerExprT, NativeFrameT, NativeSeriesT], + Protocol[EagerSeriesT, EagerExprT, NativeFrameT], ): def __narwhals_namespace__( self, - ) -> EagerNamespace[Self, EagerSeriesT, EagerExprT, NativeFrameT, NativeSeriesT]: ... + ) -> EagerNamespace[Self, EagerSeriesT, EagerExprT, NativeFrameT]: ... def to_narwhals(self) -> DataFrame[NativeFrameT]: return self._version.dataframe(self, level="full") @@ -450,14 +449,10 @@ def _numpy_column_names( ) -> list[str]: return list(columns or (f"column_{x}" for x in range(data.shape[1]))) - def _gather(self, rows: SizedMultiIndexSelector[NativeSeriesT]) -> Self: ... + def _gather(self, rows: SizedMultiIndexSelector[Any]) -> Self: ... def _gather_slice(self, rows: _SliceIndex | range) -> Self: ... - def _select_multi_index( - self, columns: SizedMultiIndexSelector[NativeSeriesT] - ) -> Self: ... - def _select_multi_name( - self, columns: SizedMultiNameSelector[NativeSeriesT] - ) -> Self: ... + def _select_multi_index(self, columns: SizedMultiIndexSelector[Any]) -> Self: ... + def _select_multi_name(self, columns: SizedMultiNameSelector[Any]) -> Self: ... def _select_slice_index(self, columns: _SliceIndex | range) -> Self: ... def _select_slice_name(self, columns: _SliceName) -> Self: ... def __getitem__( # noqa: C901, PLR0912 diff --git a/narwhals/_compliant/expr.py b/narwhals/_compliant/expr.py index bb783398bf..9490bc8b89 100644 --- a/narwhals/_compliant/expr.py +++ b/narwhals/_compliant/expr.py @@ -337,7 +337,7 @@ def __call__(self, df: EagerDataFrameT) -> Sequence[EagerSeriesT]: def __narwhals_namespace__( self, - ) -> EagerNamespace[EagerDataFrameT, EagerSeriesT, Self, Any, Any]: ... + ) -> EagerNamespace[EagerDataFrameT, EagerSeriesT, Self, Any]: ... def __narwhals_expr__(self) -> None: ... @classmethod diff --git a/narwhals/_compliant/namespace.py b/narwhals/_compliant/namespace.py index 2d47baac31..7371232336 100644 --- a/narwhals/_compliant/namespace.py +++ b/narwhals/_compliant/namespace.py @@ -23,7 +23,6 @@ LazyExprT, NativeFrameT, NativeFrameT_co, - NativeSeriesT, ) from narwhals._utils import ( exclude_column_names, @@ -130,10 +129,9 @@ def from_native(self, data: NativeFrameT_co | Any, /) -> CompliantLazyFrameT: raise TypeError(msg) -# Invariant type variable "NativeSeriesT" used in protocol where covariant one is expected -class EagerNamespace( # type: ignore[misc] +class EagerNamespace( DepthTrackingNamespace[EagerDataFrameT, EagerExprT], - Protocol[EagerDataFrameT, EagerSeriesT, EagerExprT, NativeFrameT, NativeSeriesT], + Protocol[EagerDataFrameT, EagerSeriesT, EagerExprT, NativeFrameT], ): @property def _dataframe(self) -> type[EagerDataFrameT]: ... @@ -143,21 +141,7 @@ def when( self, predicate: EagerExprT ) -> EagerWhen[EagerDataFrameT, EagerSeriesT, EagerExprT]: ... - @overload - def from_native(self, data: NativeFrameT, /) -> EagerDataFrameT: ... - @overload - def from_native(self, data: NativeSeriesT, /) -> EagerSeriesT: ... - # TODO @dangotbanned: Align `PandasLike` typing with `_namespace`, then drop this `@overload` - # - Using the guards there introduces `_NativeModin`, `_NativeCuDF` - # - These types haven't been integrated into the backend - # - Most of the `pandas` stuff is still untyped - @overload - def from_native( - self, data: NativeFrameT | NativeSeriesT | Any, / - ) -> EagerDataFrameT | EagerSeriesT: ... - def from_native( - self, data: NativeFrameT | NativeSeriesT | Any, / - ) -> EagerDataFrameT | EagerSeriesT: + def from_native(self, data: Any, /) -> EagerDataFrameT | EagerSeriesT: if self._dataframe._is_native(data): return self._dataframe.from_native(data, context=self) elif self._series._is_native(data): diff --git a/narwhals/_compliant/series.py b/narwhals/_compliant/series.py index cc194af4ca..fb0cb98ca7 100644 --- a/narwhals/_compliant/series.py +++ b/narwhals/_compliant/series.py @@ -300,9 +300,7 @@ def _with_native( """ ... - def __narwhals_namespace__( - self, - ) -> EagerNamespace[Any, Self, Any, Any, NativeSeriesT]: ... + def __narwhals_namespace__(self) -> EagerNamespace[Any, Self, Any, Any]: ... def _to_expr(self) -> EagerExpr[Any, Any]: return self.__narwhals_namespace__()._expr._from_series(self) # type: ignore[no-any-return] diff --git a/narwhals/_compliant/typing.py b/narwhals/_compliant/typing.py index 457d71d6b5..4c3685b728 100644 --- a/narwhals/_compliant/typing.py +++ b/narwhals/_compliant/typing.py @@ -60,10 +60,12 @@ class ScalarKwargs(TypedDict, total=False): DepthTrackingExprAny: TypeAlias = "DepthTrackingExpr[Any, Any]" -EagerDataFrameAny: TypeAlias = "EagerDataFrame[Any, Any, Any, Any]" +EagerDataFrameAny: TypeAlias = "EagerDataFrame[Any, Any, Any]" EagerSeriesAny: TypeAlias = "EagerSeries[Any]" EagerExprAny: TypeAlias = "EagerExpr[Any, Any]" -EagerNamespaceAny: TypeAlias = "EagerNamespace[EagerDataFrameAny, EagerSeriesAny, EagerExprAny, NativeFrame, NativeSeries]" +EagerNamespaceAny: TypeAlias = ( + "EagerNamespace[EagerDataFrameAny, EagerSeriesAny, EagerExprAny, NativeFrame]" +) LazyExprAny: TypeAlias = "LazyExpr[Any, Any]" @@ -124,7 +126,7 @@ class ScalarKwargs(TypedDict, total=False): EagerSeriesT_co = TypeVar("EagerSeriesT_co", bound=EagerSeriesAny, covariant=True) # NOTE: `pyright` gives false (8) positives if this uses `EagerDataFrameAny`? -EagerDataFrameT = TypeVar("EagerDataFrameT", bound="EagerDataFrame[Any, Any, Any, Any]") +EagerDataFrameT = TypeVar("EagerDataFrameT", bound="EagerDataFrame[Any, Any, Any]") LazyExprT = TypeVar("LazyExprT", bound=LazyExprAny) LazyExprT_contra = TypeVar("LazyExprT_contra", bound=LazyExprAny, contravariant=True) diff --git a/narwhals/_pandas_like/dataframe.py b/narwhals/_pandas_like/dataframe.py index c23748d016..bf5287fbad 100644 --- a/narwhals/_pandas_like/dataframe.py +++ b/narwhals/_pandas_like/dataframe.py @@ -103,9 +103,7 @@ ) -class PandasLikeDataFrame( - EagerDataFrame["PandasLikeSeries", "PandasLikeExpr", "Any", "pd.Series[Any]"] -): +class PandasLikeDataFrame(EagerDataFrame["PandasLikeSeries", "PandasLikeExpr", "Any"]): def __init__( self, native_dataframe: Any, diff --git a/narwhals/_pandas_like/namespace.py b/narwhals/_pandas_like/namespace.py index 7d9df1e1ac..f1c89c0bec 100644 --- a/narwhals/_pandas_like/namespace.py +++ b/narwhals/_pandas_like/namespace.py @@ -31,13 +31,7 @@ class PandasLikeNamespace( - EagerNamespace[ - PandasLikeDataFrame, - PandasLikeSeries, - PandasLikeExpr, - pd.DataFrame, - "pd.Series[Any]", - ] + EagerNamespace[PandasLikeDataFrame, PandasLikeSeries, PandasLikeExpr, pd.DataFrame] ): @property def _dataframe(self) -> type[PandasLikeDataFrame]: From e7787bd6bc28f8c245ad26c69fb8b68b72be7351 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Wed, 11 Jun 2025 10:53:00 +0100 Subject: [PATCH 13/14] :art: --- narwhals/_arrow/namespace.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/narwhals/_arrow/namespace.py b/narwhals/_arrow/namespace.py index a032c11d7a..42a01924fb 100644 --- a/narwhals/_arrow/namespace.py +++ b/narwhals/_arrow/namespace.py @@ -24,10 +24,7 @@ from narwhals._utils import Implementation if TYPE_CHECKING: - from narwhals._arrow.typing import ( - ChunkedArrayAny, # noqa: F401 - Incomplete, - ) + from narwhals._arrow.typing import Incomplete from narwhals._utils import Version from narwhals.dtypes import DType from narwhals.typing import NonNestedLiteral From 1d36fbc1d71c2502aa635659a378ccb07d6ac7e3 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Wed, 11 Jun 2025 10:53:30 +0100 Subject: [PATCH 14/14] :art: --- narwhals/_pandas_like/namespace.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/narwhals/_pandas_like/namespace.py b/narwhals/_pandas_like/namespace.py index f1c89c0bec..7d149e4c60 100644 --- a/narwhals/_pandas_like/namespace.py +++ b/narwhals/_pandas_like/namespace.py @@ -19,8 +19,6 @@ from narwhals._pandas_like.utils import align_series_full_broadcast if TYPE_CHECKING: - from typing import Any # noqa: F401 - from narwhals._pandas_like.typing import NDFrameT from narwhals._utils import Implementation, Version from narwhals.dtypes import DType