From 5923b7eeb609cf1f764af66b0d685b3e07ed4af9 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 29 Aug 2025 14:36:49 +0000 Subject: [PATCH 1/8] refactor: Add `CompliantFrame` protocol --- narwhals/_compliant/dataframe.py | 238 ++++++++++++------------------- 1 file changed, 91 insertions(+), 147 deletions(-) diff --git a/narwhals/_compliant/dataframe.py b/narwhals/_compliant/dataframe.py index a3e34bbebf..eceb9edfab 100644 --- a/narwhals/_compliant/dataframe.py +++ b/narwhals/_compliant/dataframe.py @@ -83,23 +83,105 @@ _ToDict: TypeAlias = "dict[str, CompliantSeriesT] | dict[str, list[Any]]" # noqa: PYI047 +_NativeFrameT = TypeVar("_NativeFrameT") + + +class CompliantFrame( + _StoresNative[_NativeFrameT], + FromNative[_NativeFrameT], + ToNarwhals[ToNarwhalsT_co], + Protocol[CompliantExprT_contra, _NativeFrameT, ToNarwhalsT_co], +): + _native_frame: _NativeFrameT + _implementation: Implementation + _version: Version + + def __native_namespace__(self) -> Any: ... + def __narwhals_namespace__(self) -> Any: ... + def _with_version(self, version: Version) -> Self: ... + @classmethod + def from_native(cls, data: _NativeFrameT, /, *, context: _LimitedContext) -> Self: ... + @property + def columns(self) -> Sequence[str]: ... + @property + def native(self) -> _NativeFrameT: + return self._native_frame + + @property + def schema(self) -> Mapping[str, DType]: ... + def aggregate(self, *exprs: CompliantExprT_contra) -> Self: + """`select` where all args are aggregations or literals. + + (so, no broadcasting is necessary). + """ + ... + + def collect_schema(self) -> Mapping[str, DType]: ... + def drop(self, columns: Sequence[str], *, strict: bool) -> Self: ... + def drop_nulls(self, subset: Sequence[str] | None) -> Self: ... + def explode(self, columns: Sequence[str]) -> Self: ... + def filter(self, predicate: CompliantExprT_contra | Incomplete) -> Self: ... + def group_by( + self, + keys: Sequence[str] | Sequence[CompliantExprT_contra], + *, + drop_null_keys: bool, + # TODO @dangotbanned: Update typing for `CompliantGroupBy` to support `Self` + ) -> CompliantGroupBy[Incomplete, CompliantExprT_contra]: ... + def head(self, n: int) -> Self: ... + def join( + self, + other: Self, + *, + how: JoinStrategy, + left_on: Sequence[str] | None, + right_on: Sequence[str] | None, + suffix: str, + ) -> Self: ... + def join_asof( + self, + other: Self, + *, + left_on: str, + right_on: str, + by_left: Sequence[str] | None, + by_right: Sequence[str] | None, + strategy: AsofJoinStrategy, + suffix: str, + ) -> Self: ... + def rename(self, mapping: Mapping[str, str]) -> Self: ... + def select(self, *exprs: CompliantExprT_contra) -> Self: ... + def simple_select(self, *column_names: str) -> Self: + """`select` where all args are column names.""" + ... + + def sort( + self, *by: str, descending: bool | Sequence[bool], nulls_last: bool + ) -> Self: ... + def tail(self, n: int) -> Self: ... + def unique( + self, subset: Sequence[str] | None, *, keep: LazyUniqueKeepStrategy + ) -> Self: ... + def unpivot( + self, + on: Sequence[str] | None, + index: Sequence[str] | None, + variable_name: str, + value_name: str, + ) -> Self: ... + def with_columns(self, *exprs: CompliantExprT_contra) -> Self: ... + def with_row_index(self, name: str, order_by: Sequence[str]) -> Self: ... + class CompliantDataFrame( NumpyConvertible["_2DArray", "_2DArray"], DictConvertible["_ToDict[CompliantSeriesT]", Mapping[str, Any]], ArrowConvertible["pa.Table", "IntoArrowTable"], - _StoresNative[NativeFrameT], - FromNative[NativeFrameT], - ToNarwhals[ToNarwhalsT_co], Sized, + CompliantFrame[CompliantExprT_contra, NativeFrameT, ToNarwhalsT_co], Protocol[CompliantSeriesT, CompliantExprT_contra, NativeFrameT, ToNarwhalsT_co], ): - _native_frame: NativeFrameT - _implementation: Implementation - _version: Version - def __narwhals_dataframe__(self) -> Self: ... - def __narwhals_namespace__(self) -> Any: ... @classmethod def from_arrow(cls, data: IntoArrowTable, /, *, context: _LimitedContext) -> Self: ... @classmethod @@ -112,8 +194,6 @@ def from_dict( schema: IntoSchema | None, ) -> Self: ... @classmethod - def from_native(cls, data: NativeFrameT, /, *, context: _LimitedContext) -> Self: ... - @classmethod def from_numpy( cls, data: _2DArray, @@ -122,7 +202,6 @@ def from_numpy( context: _LimitedContext, schema: IntoSchema | Sequence[str] | None, ) -> Self: ... - def __array__(self, dtype: Any, *, copy: bool | None) -> _2DArray: ... def __getitem__( self, @@ -131,37 +210,14 @@ def __getitem__( MultiColSelector[CompliantSeriesT], ], ) -> Self: ... - def simple_select(self, *column_names: str) -> Self: - """`select` where all args are column names.""" - ... - def aggregate(self, *exprs: CompliantExprT_contra) -> Self: - """`select` where all args are aggregations or literals. - - (so, no broadcasting is necessary). - """ # NOTE: Ignore is to avoid an intermittent false positive return self.select(*exprs) # pyright: ignore[reportArgumentType] - def _with_version(self, version: Version) -> Self: ... - - @property - def native(self) -> NativeFrameT: - return self._native_frame - - @property - def columns(self) -> Sequence[str]: ... - @property - def schema(self) -> Mapping[str, DType]: ... @property def shape(self) -> tuple[int, int]: ... def clone(self) -> Self: ... - def collect_schema(self) -> Mapping[str, DType]: ... - def drop(self, columns: Sequence[str], *, strict: bool) -> Self: ... - def drop_nulls(self, subset: Sequence[str] | None) -> Self: ... def estimated_size(self, unit: SizeUnit) -> int | float: ... - def explode(self, columns: Sequence[str]) -> Self: ... - def filter(self, predicate: CompliantExprT_contra | Incomplete) -> Self: ... def gather_every(self, n: int, offset: int) -> Self: ... def get_column(self, name: str) -> CompliantSeriesT: ... def group_by( @@ -170,33 +226,12 @@ def group_by( *, drop_null_keys: bool, ) -> DataFrameGroupBy[Self, Any]: ... - def head(self, n: int) -> Self: ... def item(self, row: int | None, column: int | str | None) -> Any: ... def iter_columns(self) -> Iterator[CompliantSeriesT]: ... def iter_rows( self, *, named: bool, buffer_size: int ) -> Iterator[tuple[Any, ...]] | Iterator[Mapping[str, Any]]: ... def is_unique(self) -> CompliantSeriesT: ... - def join( - self, - other: Self, - *, - how: JoinStrategy, - left_on: Sequence[str] | None, - right_on: Sequence[str] | None, - suffix: str, - ) -> Self: ... - def join_asof( - self, - other: Self, - *, - left_on: str, - right_on: str, - by_left: Sequence[str] | None, - by_right: Sequence[str] | None, - strategy: AsofJoinStrategy, - suffix: str, - ) -> Self: ... def lazy( self, backend: _LazyAllowedImpl | None, *, session: SparkSession | None ) -> CompliantLazyFrameAny: ... @@ -210,7 +245,6 @@ def pivot( sort_columns: bool, separator: str, ) -> Self: ... - def rename(self, mapping: Mapping[str, str]) -> Self: ... def row(self, index: int) -> tuple[Any, ...]: ... def rows( self, *, named: bool @@ -223,11 +257,6 @@ def sample( with_replacement: bool, seed: int | None, ) -> Self: ... - def select(self, *exprs: CompliantExprT_contra) -> Self: ... - def sort( - self, *by: str, descending: bool | Sequence[bool], nulls_last: bool - ) -> Self: ... - def tail(self, n: int) -> Self: ... def to_arrow(self) -> pa.Table: ... def to_pandas(self) -> pd.DataFrame: ... def to_polars(self) -> pl.DataFrame: ... @@ -245,14 +274,6 @@ def unique( keep: UniqueKeepStrategy, maintain_order: bool | None = None, ) -> Self: ... - def unpivot( - self, - on: Sequence[str] | None, - index: Sequence[str] | None, - variable_name: str, - value_name: str, - ) -> Self: ... - def with_columns(self, *exprs: CompliantExprT_contra) -> Self: ... def with_row_index(self, name: str, order_by: Sequence[str] | None) -> Self: ... @overload def write_csv(self, file: None) -> str: ... @@ -263,98 +284,21 @@ def write_parquet(self, file: str | Path | BytesIO) -> None: ... class CompliantLazyFrame( - _StoresNative[NativeLazyFrameT], - FromNative[NativeLazyFrameT], - ToNarwhals[ToNarwhalsT_co], + CompliantFrame[CompliantExprT_contra, NativeLazyFrameT, ToNarwhalsT_co], Protocol[CompliantExprT_contra, NativeLazyFrameT, ToNarwhalsT_co], ): - _native_frame: NativeLazyFrameT - _implementation: Implementation - _version: Version - def __narwhals_lazyframe__(self) -> Self: ... - def __narwhals_namespace__(self) -> Any: ... - - @classmethod - def from_native( - cls, data: NativeLazyFrameT, /, *, context: _LimitedContext - ) -> Self: ... - - def simple_select(self, *column_names: str) -> Self: - """`select` where all args are column names.""" - ... - - def aggregate(self, *exprs: CompliantExprT_contra) -> Self: - """`select` where all args are aggregations or literals. - - (so, no broadcasting is necessary). - """ - ... - - def _with_version(self, version: Version) -> Self: ... - - @property - def native(self) -> NativeLazyFrameT: - return self._native_frame - - @property - def columns(self) -> Sequence[str]: ... - @property - def schema(self) -> Mapping[str, DType]: ... def _iter_columns(self) -> Iterator[Any]: ... def collect( self, backend: _EagerAllowedImpl | None, **kwargs: Any ) -> CompliantDataFrameAny: ... - def collect_schema(self) -> Mapping[str, DType]: ... - def drop(self, columns: Sequence[str], *, strict: bool) -> Self: ... - def drop_nulls(self, subset: Sequence[str] | None) -> Self: ... - def explode(self, columns: Sequence[str]) -> Self: ... - def filter(self, predicate: CompliantExprT_contra | Incomplete) -> Self: ... def group_by( self, keys: Sequence[str] | Sequence[CompliantExprT_contra], *, drop_null_keys: bool, ) -> CompliantGroupBy[Self, CompliantExprT_contra]: ... - def head(self, n: int) -> Self: ... - def join( - self, - other: Self, - *, - how: JoinStrategy, - left_on: Sequence[str] | None, - right_on: Sequence[str] | None, - suffix: str, - ) -> Self: ... - def join_asof( - self, - other: Self, - *, - left_on: str, - right_on: str, - by_left: Sequence[str] | None, - by_right: Sequence[str] | None, - strategy: AsofJoinStrategy, - suffix: str, - ) -> Self: ... - def rename(self, mapping: Mapping[str, str]) -> Self: ... - def select(self, *exprs: CompliantExprT_contra) -> Self: ... def sink_parquet(self, file: str | Path | BytesIO) -> None: ... - def sort( - self, *by: str, descending: bool | Sequence[bool], nulls_last: bool - ) -> Self: ... - def unique( - self, subset: Sequence[str] | None, *, keep: LazyUniqueKeepStrategy - ) -> Self: ... - def unpivot( - self, - on: Sequence[str] | None, - index: Sequence[str] | None, - variable_name: str, - value_name: str, - ) -> Self: ... - def with_columns(self, *exprs: CompliantExprT_contra) -> Self: ... - def with_row_index(self, name: str, order_by: Sequence[str]) -> Self: ... class EagerDataFrame( From 7b08af34e77f0f6c9de296a3152a480fdc8607a1 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 29 Aug 2025 14:41:23 +0000 Subject: [PATCH 2/8] fix(typing): Update `CompliantGroupBy` --- narwhals/_compliant/dataframe.py | 9 +-------- narwhals/_compliant/typing.py | 3 ++- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/narwhals/_compliant/dataframe.py b/narwhals/_compliant/dataframe.py index eceb9edfab..954601c42b 100644 --- a/narwhals/_compliant/dataframe.py +++ b/narwhals/_compliant/dataframe.py @@ -126,8 +126,7 @@ def group_by( keys: Sequence[str] | Sequence[CompliantExprT_contra], *, drop_null_keys: bool, - # TODO @dangotbanned: Update typing for `CompliantGroupBy` to support `Self` - ) -> CompliantGroupBy[Incomplete, CompliantExprT_contra]: ... + ) -> CompliantGroupBy[Self, CompliantExprT_contra]: ... def head(self, n: int) -> Self: ... def join( self, @@ -292,12 +291,6 @@ def _iter_columns(self) -> Iterator[Any]: ... def collect( self, backend: _EagerAllowedImpl | None, **kwargs: Any ) -> CompliantDataFrameAny: ... - def group_by( - self, - keys: Sequence[str] | Sequence[CompliantExprT_contra], - *, - drop_null_keys: bool, - ) -> CompliantGroupBy[Self, CompliantExprT_contra]: ... def sink_parquet(self, file: str | Path | BytesIO) -> None: ... diff --git a/narwhals/_compliant/typing.py b/narwhals/_compliant/typing.py index 986ca8d031..7163d1acb1 100644 --- a/narwhals/_compliant/typing.py +++ b/narwhals/_compliant/typing.py @@ -8,6 +8,7 @@ from narwhals._compliant.dataframe import ( CompliantDataFrame, + CompliantFrame, CompliantLazyFrame, EagerDataFrame, ) @@ -75,7 +76,7 @@ class ScalarKwargs(TypedDict, total=False): CompliantSeriesOrNativeExprAny: TypeAlias = "CompliantSeriesAny | NativeExpr" CompliantDataFrameAny: TypeAlias = "CompliantDataFrame[Any, Any, Any, Any]" CompliantLazyFrameAny: TypeAlias = "CompliantLazyFrame[Any, Any, Any]" -CompliantFrameAny: TypeAlias = "CompliantDataFrameAny | CompliantLazyFrameAny" +CompliantFrameAny: TypeAlias = "CompliantFrame[Any, Any, Any]" CompliantNamespaceAny: TypeAlias = "CompliantNamespace[Any, Any]" DepthTrackingExprAny: TypeAlias = "DepthTrackingExpr[Any, Any]" From 2e52af7d26a8155ffd19d51c464fd4ea1f249ac3 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 29 Aug 2025 14:44:15 +0000 Subject: [PATCH 3/8] chore: Update exports --- narwhals/_compliant/__init__.py | 2 ++ narwhals/_compliant/dataframe.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/narwhals/_compliant/__init__.py b/narwhals/_compliant/__init__.py index 23550af11f..dee6454183 100644 --- a/narwhals/_compliant/__init__.py +++ b/narwhals/_compliant/__init__.py @@ -2,6 +2,7 @@ from narwhals._compliant.dataframe import ( CompliantDataFrame, + CompliantFrame, CompliantLazyFrame, EagerDataFrame, ) @@ -60,6 +61,7 @@ "CompliantDataFrame", "CompliantExpr", "CompliantExprT", + "CompliantFrame", "CompliantFrameT", "CompliantGroupBy", "CompliantLazyFrame", diff --git a/narwhals/_compliant/dataframe.py b/narwhals/_compliant/dataframe.py index 954601c42b..51d7c3ceba 100644 --- a/narwhals/_compliant/dataframe.py +++ b/narwhals/_compliant/dataframe.py @@ -77,7 +77,7 @@ Incomplete: TypeAlias = Any -__all__ = ["CompliantDataFrame", "CompliantLazyFrame", "EagerDataFrame"] +__all__ = ["CompliantDataFrame", "CompliantFrame", "CompliantLazyFrame", "EagerDataFrame"] T = TypeVar("T") From 2dac51ab455cd0332779ce4b9654d9fa420c26b4 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 29 Aug 2025 14:51:45 +0000 Subject: [PATCH 4/8] fix(typing): Use narrower bounds for `CompliantDataFrame` Missed during #2944 --- narwhals/_compliant/dataframe.py | 5 ++--- narwhals/_utils.py | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/narwhals/_compliant/dataframe.py b/narwhals/_compliant/dataframe.py index 51d7c3ceba..6bf0744bf9 100644 --- a/narwhals/_compliant/dataframe.py +++ b/narwhals/_compliant/dataframe.py @@ -12,7 +12,6 @@ EagerExprT, EagerSeriesT, NativeDataFrameT, - NativeFrameT, NativeLazyFrameT, NativeSeriesT, ) @@ -177,8 +176,8 @@ class CompliantDataFrame( DictConvertible["_ToDict[CompliantSeriesT]", Mapping[str, Any]], ArrowConvertible["pa.Table", "IntoArrowTable"], Sized, - CompliantFrame[CompliantExprT_contra, NativeFrameT, ToNarwhalsT_co], - Protocol[CompliantSeriesT, CompliantExprT_contra, NativeFrameT, ToNarwhalsT_co], + CompliantFrame[CompliantExprT_contra, NativeDataFrameT, ToNarwhalsT_co], + Protocol[CompliantSeriesT, CompliantExprT_contra, NativeDataFrameT, ToNarwhalsT_co], ): def __narwhals_dataframe__(self) -> Self: ... @classmethod diff --git a/narwhals/_utils.py b/narwhals/_utils.py index dee2234d21..7c9bf6c820 100644 --- a/narwhals/_utils.py +++ b/narwhals/_utils.py @@ -70,10 +70,9 @@ CompliantFrameT, CompliantSeriesOrNativeExprT_co, CompliantSeriesT, - NativeFrameT_co, NativeSeriesT_co, ) - from narwhals._compliant.typing import EvalNames, NativeLazyFrameT + from narwhals._compliant.typing import EvalNames, NativeDataFrameT, NativeLazyFrameT from narwhals._namespace import Namespace from narwhals._translate import ArrowStreamExportable, IntoArrowTable, ToNarwhalsT_co from narwhals._typing import ( @@ -1612,11 +1611,11 @@ def _hasattr_static(obj: Any, attr: str) -> bool: def is_compliant_dataframe( obj: CompliantDataFrame[ - CompliantSeriesT, CompliantExprT, NativeFrameT_co, ToNarwhalsT_co + CompliantSeriesT, CompliantExprT, NativeDataFrameT, ToNarwhalsT_co ] | Any, ) -> TypeIs[ - CompliantDataFrame[CompliantSeriesT, CompliantExprT, NativeFrameT_co, ToNarwhalsT_co] + CompliantDataFrame[CompliantSeriesT, CompliantExprT, NativeDataFrameT, ToNarwhalsT_co] ]: return _hasattr_static(obj, "__narwhals_dataframe__") From af6940e640a8e14560386fd56fe75e3bce5513f5 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 29 Aug 2025 15:26:12 +0000 Subject: [PATCH 5/8] refactor(typing): Replace some more type vars --- narwhals/_compliant/group_by.py | 29 ++++++++++++----------------- narwhals/_sql/group_by.py | 8 ++++---- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/narwhals/_compliant/group_by.py b/narwhals/_compliant/group_by.py index 8dfb93aa35..47a7ba434a 100644 --- a/narwhals/_compliant/group_by.py +++ b/narwhals/_compliant/group_by.py @@ -5,12 +5,11 @@ from typing import TYPE_CHECKING, Any, Callable, ClassVar, Protocol, TypeVar from narwhals._compliant.typing import ( - CompliantDataFrameAny, + CompliantDataFrameT, CompliantDataFrameT_co, CompliantExprT_contra, CompliantFrameT, CompliantFrameT_co, - CompliantLazyFrameAny, DepthTrackingExprAny, DepthTrackingExprT_contra, EagerExprT_contra, @@ -23,8 +22,6 @@ from narwhals._compliant.expr import CompliantExpr - _SameFrameT = TypeVar("_SameFrameT", CompliantDataFrameAny, CompliantLazyFrameAny) - __all__ = ["CompliantGroupBy", "DepthTrackingGroupBy", "EagerGroupBy"] @@ -70,14 +67,14 @@ def __iter__(self) -> Iterator[tuple[Any, CompliantDataFrameT_co]]: ... class ParseKeysGroupBy( - CompliantGroupBy[CompliantFrameT_co, CompliantExprT_contra], - Protocol[CompliantFrameT_co, CompliantExprT_contra], + CompliantGroupBy[CompliantFrameT, CompliantExprT_contra], + Protocol[CompliantFrameT, CompliantExprT_contra], ): def _parse_keys( self, - compliant_frame: _SameFrameT, + compliant_frame: CompliantFrameT, keys: Sequence[CompliantExprT_contra] | Sequence[str], - ) -> tuple[_SameFrameT, list[str], list[str]]: + ) -> tuple[CompliantFrameT, list[str], list[str]]: if is_sequence_of(keys, str): keys_str = list(keys) return compliant_frame, keys_str, keys_str.copy() @@ -85,8 +82,8 @@ def _parse_keys( @staticmethod def _parse_expr_keys( - compliant_frame: _SameFrameT, keys: Sequence[CompliantExprT_contra] - ) -> tuple[_SameFrameT, list[str], list[str]]: + compliant_frame: CompliantFrameT, keys: Sequence[CompliantExprT_contra] + ) -> tuple[CompliantFrameT, list[str], list[str]]: """Parses key expressions to set up `.agg` operation with correct information. Since keys are expressions, it's possible to alias any such key to match @@ -125,8 +122,8 @@ def _temporary_name(key: str) -> str: class DepthTrackingGroupBy( - ParseKeysGroupBy[CompliantFrameT_co, DepthTrackingExprT_contra], - Protocol[CompliantFrameT_co, DepthTrackingExprT_contra, NativeAggregationT_co], + ParseKeysGroupBy[CompliantFrameT, DepthTrackingExprT_contra], + Protocol[CompliantFrameT, DepthTrackingExprT_contra, NativeAggregationT_co], ): """`CompliantGroupBy` variant, deals with `Eager` and other backends that utilize `CompliantExpr._depth`.""" @@ -176,9 +173,7 @@ def _leaf_name(cls, expr: DepthTrackingExprAny, /) -> NarwhalsAggregation | Any: class EagerGroupBy( - DepthTrackingGroupBy[ - CompliantDataFrameT_co, EagerExprT_contra, NativeAggregationT_co - ], - DataFrameGroupBy[CompliantDataFrameT_co, EagerExprT_contra], - Protocol[CompliantDataFrameT_co, EagerExprT_contra, NativeAggregationT_co], + DepthTrackingGroupBy[CompliantDataFrameT, EagerExprT_contra, NativeAggregationT_co], + DataFrameGroupBy[CompliantDataFrameT, EagerExprT_contra], + Protocol[CompliantDataFrameT, EagerExprT_contra, NativeAggregationT_co], ): ... diff --git a/narwhals/_sql/group_by.py b/narwhals/_sql/group_by.py index ab5d669e02..3fc4dbb44b 100644 --- a/narwhals/_sql/group_by.py +++ b/narwhals/_sql/group_by.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Protocol from narwhals._compliant.group_by import CompliantGroupBy, ParseKeysGroupBy -from narwhals._compliant.typing import CompliantLazyFrameT_co, NativeExprT_co +from narwhals._compliant.typing import CompliantLazyFrameT, NativeExprT_co from narwhals._sql.typing import SQLExprT_contra from narwhals._utils import zip_strict @@ -12,9 +12,9 @@ class SQLGroupBy( - ParseKeysGroupBy[CompliantLazyFrameT_co, SQLExprT_contra], - CompliantGroupBy[CompliantLazyFrameT_co, SQLExprT_contra], - Protocol[CompliantLazyFrameT_co, SQLExprT_contra, NativeExprT_co], + ParseKeysGroupBy[CompliantLazyFrameT, SQLExprT_contra], + CompliantGroupBy[CompliantLazyFrameT, SQLExprT_contra], + Protocol[CompliantLazyFrameT, SQLExprT_contra, NativeExprT_co], ): _keys: list[str] _output_key_names: list[str] From 4e328af3141f7dd460db96833549ad23b771f48d Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 29 Aug 2025 15:29:49 +0000 Subject: [PATCH 6/8] docs: Why not explain? --- narwhals/_compliant/dataframe.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/narwhals/_compliant/dataframe.py b/narwhals/_compliant/dataframe.py index 6bf0744bf9..80e8f17650 100644 --- a/narwhals/_compliant/dataframe.py +++ b/narwhals/_compliant/dataframe.py @@ -91,6 +91,8 @@ class CompliantFrame( ToNarwhals[ToNarwhalsT_co], Protocol[CompliantExprT_contra, _NativeFrameT, ToNarwhalsT_co], ): + """Common parts of `DataFrame`, `LazyFrame`.""" + _native_frame: _NativeFrameT _implementation: Implementation _version: Version From 9fb8b96a191762c4387e4a7a53d623921eb5a3ea Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 29 Aug 2025 15:36:20 +0000 Subject: [PATCH 7/8] chore: Remove related, unused alias --- narwhals/_compliant/__init__.py | 2 -- narwhals/_compliant/typing.py | 3 --- 2 files changed, 5 deletions(-) diff --git a/narwhals/_compliant/__init__.py b/narwhals/_compliant/__init__.py index dee6454183..70bd22588b 100644 --- a/narwhals/_compliant/__init__.py +++ b/narwhals/_compliant/__init__.py @@ -50,7 +50,6 @@ EagerSeriesT, EvalNames, EvalSeries, - IntoCompliantExpr, NativeFrameT_co, NativeSeriesT_co, ) @@ -94,7 +93,6 @@ "EagerWhen", "EvalNames", "EvalSeries", - "IntoCompliantExpr", "LazyExpr", "LazyExprNamespace", "LazyNamespace", diff --git a/narwhals/_compliant/typing.py b/narwhals/_compliant/typing.py index 7163d1acb1..e3719061be 100644 --- a/narwhals/_compliant/typing.py +++ b/narwhals/_compliant/typing.py @@ -66,7 +66,6 @@ class ScalarKwargs(TypedDict, total=False): "CompliantSeriesT", "EvalNames", "EvalSeries", - "IntoCompliantExpr", "NarwhalsAggregation", "NativeFrameT_co", "NativeSeriesT_co", @@ -137,8 +136,6 @@ class ScalarKwargs(TypedDict, total=False): "CompliantNamespaceT_co", bound=CompliantNamespaceAny, covariant=True ) -IntoCompliantExpr: TypeAlias = "CompliantExpr[CompliantFrameT, CompliantSeriesOrNativeExprT_co] | CompliantSeriesOrNativeExprT_co" - DepthTrackingExprT = TypeVar("DepthTrackingExprT", bound=DepthTrackingExprAny) DepthTrackingExprT_contra = TypeVar( "DepthTrackingExprT_contra", bound=DepthTrackingExprAny, contravariant=True From 440d7897cb7ebc31aef845fed68f63bb2bafe204 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 29 Aug 2025 15:56:55 +0000 Subject: [PATCH 8/8] fix(typing): Fill in `Any` --- narwhals/_compliant/dataframe.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/narwhals/_compliant/dataframe.py b/narwhals/_compliant/dataframe.py index 80e8f17650..e6d88f3c11 100644 --- a/narwhals/_compliant/dataframe.py +++ b/narwhals/_compliant/dataframe.py @@ -41,6 +41,7 @@ if TYPE_CHECKING: from io import BytesIO from pathlib import Path + from types import ModuleType import pandas as pd import polars as pl @@ -97,7 +98,7 @@ class CompliantFrame( _implementation: Implementation _version: Version - def __native_namespace__(self) -> Any: ... + def __native_namespace__(self) -> ModuleType: ... def __narwhals_namespace__(self) -> Any: ... def _with_version(self, version: Version) -> Self: ... @classmethod