diff --git a/docs/api-reference/dataframe.md b/docs/api-reference/dataframe.md index f593293f43..1717977f4f 100644 --- a/docs/api-reference/dataframe.md +++ b/docs/api-reference/dataframe.md @@ -6,6 +6,7 @@ members: - __arrow_c_stream__ - __getitem__ + - cast - clone - collect_schema - columns diff --git a/docs/api-reference/lazyframe.md b/docs/api-reference/lazyframe.md index 89a8282ac5..d4d4917175 100644 --- a/docs/api-reference/lazyframe.md +++ b/docs/api-reference/lazyframe.md @@ -4,6 +4,7 @@ handler: python options: members: + - cast - clone - collect - collect_schema diff --git a/narwhals/_arrow/dataframe.py b/narwhals/_arrow/dataframe.py index 89919c7634..912fcd27a6 100644 --- a/narwhals/_arrow/dataframe.py +++ b/narwhals/_arrow/dataframe.py @@ -615,3 +615,19 @@ def sample( mask = rng.choice(idx, size=n, replace=with_replacement) return self._from_native_frame(pc.take(frame, mask)) + + def cast( + self: Self, + dtypes: dict[str, type[DType] | DType] | type[DType] | DType, + *, + strict: bool, + ) -> Self: + plx = self.__narwhals_namespace__() + if isinstance(dtypes, dict): + return self.with_columns( + **{c: plx.col(c).cast(v, strict=strict) for c, v in dtypes.items()} + ) + else: + return self.with_columns( + **{c: plx.col(c).cast(dtypes, strict=strict) for c in self.columns} + ) diff --git a/narwhals/_arrow/expr.py b/narwhals/_arrow/expr.py index 1aceb576ff..b29ed1c8a4 100644 --- a/narwhals/_arrow/expr.py +++ b/narwhals/_arrow/expr.py @@ -175,8 +175,8 @@ def n_unique(self) -> Self: def std(self, ddof: int = 1) -> Self: return reuse_series_implementation(self, "std", ddof=ddof, returns_scalar=True) - def cast(self, dtype: DType) -> Self: - return reuse_series_implementation(self, "cast", dtype) + def cast(self, dtype: DType | type[DType], *, strict: bool) -> Self: + return reuse_series_implementation(self, "cast", dtype=dtype, strict=strict) def abs(self) -> Self: return reuse_series_implementation(self, "abs") diff --git a/narwhals/_arrow/namespace.py b/narwhals/_arrow/namespace.py index ed14dd3359..c8ebb981d4 100644 --- a/narwhals/_arrow/namespace.py +++ b/narwhals/_arrow/namespace.py @@ -155,7 +155,7 @@ def _lit_arrow_series(_: ArrowDataFrame) -> ArrowSeries: backend_version=self._backend_version, ) if dtype: - return arrow_series.cast(dtype) + return arrow_series.cast(dtype, strict=True) return arrow_series return ArrowExpr( @@ -184,7 +184,7 @@ def mean_horizontal(self, *exprs: IntoArrowExpr) -> IntoArrowExpr: total = reduce(lambda x, y: x + y, (e.fill_null(0.0) for e in arrow_exprs)) n_non_zero = reduce( lambda x, y: x + y, - ((1 - e.is_null().cast(self.Int64())) for e in arrow_exprs), + ((1 - e.is_null().cast(self.Int64(), strict=True)) for e in arrow_exprs), ) return total / n_non_zero diff --git a/narwhals/_arrow/series.py b/narwhals/_arrow/series.py index 90e800796b..3c7861ec8a 100644 --- a/narwhals/_arrow/series.py +++ b/narwhals/_arrow/series.py @@ -429,12 +429,12 @@ def is_null(self) -> Self: ser = self._native_series return self._from_native_series(ser.is_null()) - def cast(self, dtype: DType) -> Self: + def cast(self, dtype: DType | type[DType], *, strict: bool) -> Self: import pyarrow.compute as pc # ignore-banned-import() ser = self._native_series dtype = narwhals_to_native_dtype(dtype) - return self._from_native_series(pc.cast(ser, dtype)) + return self._from_native_series(pc.cast(ser, dtype, safe=strict)) def null_count(self: Self) -> int: return self._native_series.null_count # type: ignore[no-any-return] diff --git a/narwhals/_dask/dataframe.py b/narwhals/_dask/dataframe.py index ac10ac2b84..bdd89e3980 100644 --- a/narwhals/_dask/dataframe.py +++ b/narwhals/_dask/dataframe.py @@ -7,6 +7,7 @@ from typing import Sequence from narwhals._dask.utils import add_row_index +from narwhals._dask.utils import narwhals_to_native_dtype from narwhals._dask.utils import parse_exprs_and_named_exprs from narwhals._pandas_like.utils import translate_dtype from narwhals.dependencies import get_dask_dataframe @@ -355,3 +356,19 @@ def gather_every(self: Self, n: int, offset: int) -> Self: ) .drop([row_index_token], strict=False) ) + + def cast( + self: Self, + dtypes: dict[str, type[DType] | DType] | type[DType] | DType, + *, + strict: bool, + ) -> Self: + """`strict` exists for compatibility as dask `astype` does not support + `errors` argument as pandas does. + """ + native_frame = self._native_frame + if isinstance(dtypes, dict): + dtypes = {k: narwhals_to_native_dtype(v) for k, v in dtypes.items()} + else: + dtypes = narwhals_to_native_dtype(dtypes) + return self._from_native_frame(native_frame.astype(dtypes)) diff --git a/narwhals/_dask/expr.py b/narwhals/_dask/expr.py index cd75e87bd8..1de32ee561 100644 --- a/narwhals/_dask/expr.py +++ b/narwhals/_dask/expr.py @@ -9,7 +9,7 @@ from narwhals._dask.utils import add_row_index from narwhals._dask.utils import maybe_evaluate -from narwhals._dask.utils import reverse_translate_dtype +from narwhals._dask.utils import narwhals_to_native_dtype from narwhals.dependencies import get_dask from narwhals.utils import generate_unique_token @@ -675,12 +675,13 @@ def dt(self: Self) -> DaskExprDateTimeNamespace: def name(self: Self) -> DaskExprNameNamespace: return DaskExprNameNamespace(self) - def cast( - self: Self, - dtype: DType | type[DType], - ) -> Self: + def cast(self: Self, dtype: DType | type[DType], *, strict: bool) -> Self: + """`strict` exists for compatibility as dask `astype` does not support + `errors` argument as pandas does. + """ + def func(_input: Any, dtype: DType | type[DType]) -> Any: - dtype = reverse_translate_dtype(dtype) + dtype = narwhals_to_native_dtype(dtype) return _input.astype(dtype) return self._from_call( diff --git a/narwhals/_dask/namespace.py b/narwhals/_dask/namespace.py index 1668ee3235..2a95f92f23 100644 --- a/narwhals/_dask/namespace.py +++ b/narwhals/_dask/namespace.py @@ -12,7 +12,7 @@ from narwhals._dask.dataframe import DaskLazyFrame from narwhals._dask.expr import DaskExpr from narwhals._dask.selectors import DaskSelectorNamespace -from narwhals._dask.utils import reverse_translate_dtype +from narwhals._dask.utils import narwhals_to_native_dtype from narwhals._dask.utils import validate_comparand from narwhals._expression_parsing import parse_into_exprs @@ -75,7 +75,7 @@ def lit(self, value: Any, dtype: dtypes.DType | None) -> DaskExpr: def convert_if_dtype( series: dask_expr.Series, dtype: DType | type[DType] ) -> dask_expr.Series: - return series.astype(reverse_translate_dtype(dtype)) if dtype else series + return series.astype(narwhals_to_native_dtype(dtype)) if dtype else series return DaskExpr( lambda df: [ diff --git a/narwhals/_dask/utils.py b/narwhals/_dask/utils.py index 2740449798..fecf21ab67 100644 --- a/narwhals/_dask/utils.py +++ b/narwhals/_dask/utils.py @@ -83,7 +83,7 @@ def validate_comparand(lhs: dask_expr.Series, rhs: dask_expr.Series) -> None: raise RuntimeError(msg) -def reverse_translate_dtype(dtype: DType | type[DType]) -> Any: +def narwhals_to_native_dtype(dtype: DType | type[DType]) -> Any: from narwhals import dtypes if isinstance_or_issubclass(dtype, dtypes.Float64): diff --git a/narwhals/_pandas_like/dataframe.py b/narwhals/_pandas_like/dataframe.py index 446c68a133..155660119c 100644 --- a/narwhals/_pandas_like/dataframe.py +++ b/narwhals/_pandas_like/dataframe.py @@ -14,6 +14,7 @@ from narwhals._pandas_like.utils import convert_str_slice_to_int_slice from narwhals._pandas_like.utils import create_native_series from narwhals._pandas_like.utils import horizontal_concat +from narwhals._pandas_like.utils import narwhals_to_native_dtype from narwhals._pandas_like.utils import translate_dtype from narwhals._pandas_like.utils import validate_dataframe_comparand from narwhals.dependencies import get_cudf @@ -728,3 +729,32 @@ def sample( n=n, frac=fraction, replace=with_replacement, random_state=seed ) ) + + def cast( + self: Self, + dtypes: dict[str, type[DType] | DType] | type[DType] | DType, + *, + strict: bool, + ) -> Self: + native_frame = self._native_frame + implementation = self._implementation + if isinstance(dtypes, dict): + dtypes = { + col: narwhals_to_native_dtype( + dtype, + starting_dtype=native_frame[col].dtype, + implementation=implementation, + ) + for col, dtype in dtypes.items() + } + else: + dtypes = { + col: narwhals_to_native_dtype( + dtypes, + starting_dtype=native_frame[col].dtype, + implementation=implementation, + ) + for col in self.columns + } + errors = "raise" if strict else "ignore" + return self._from_native_frame(native_frame.astype(dtypes, errors=errors)) diff --git a/narwhals/_pandas_like/expr.py b/narwhals/_pandas_like/expr.py index 06be543946..8d95f7d24f 100644 --- a/narwhals/_pandas_like/expr.py +++ b/narwhals/_pandas_like/expr.py @@ -14,6 +14,7 @@ from narwhals._pandas_like.dataframe import PandasLikeDataFrame from narwhals._pandas_like.namespace import PandasLikeNamespace + from narwhals.dtypes import DType from narwhals.utils import Implementation @@ -81,11 +82,8 @@ def func(df: PandasLikeDataFrame) -> list[PandasLikeSeries]: backend_version=backend_version, ) - def cast( - self, - dtype: Any, - ) -> Self: - return reuse_series_implementation(self, "cast", dtype=dtype) + def cast(self: Self, dtype: DType | type[DType], *, strict: bool) -> Self: + return reuse_series_implementation(self, "cast", dtype=dtype, strict=strict) def __eq__(self, other: PandasLikeExpr | Any) -> Self: # type: ignore[override] return reuse_series_implementation(self, "__eq__", other=other) diff --git a/narwhals/_pandas_like/namespace.py b/narwhals/_pandas_like/namespace.py index 37c889549e..f2ec51f763 100644 --- a/narwhals/_pandas_like/namespace.py +++ b/narwhals/_pandas_like/namespace.py @@ -140,7 +140,7 @@ def _lit_pandas_series(df: PandasLikeDataFrame) -> PandasLikeSeries: backend_version=self._backend_version, ) if dtype: - return pandas_series.cast(dtype) + return pandas_series.cast(dtype, strict=True) return pandas_series return PandasLikeExpr( diff --git a/narwhals/_pandas_like/series.py b/narwhals/_pandas_like/series.py index 0092e97c83..f386544fca 100644 --- a/narwhals/_pandas_like/series.py +++ b/narwhals/_pandas_like/series.py @@ -184,13 +184,11 @@ def scatter(self, indices: int | Sequence[int], values: Any) -> Self: s.name = self.name return self._from_native_series(s) - def cast( - self, - dtype: Any, - ) -> Self: + def cast(self, dtype: DType | type[DType], *, strict: bool) -> Self: ser = self._native_series dtype = narwhals_to_native_dtype(dtype, ser.dtype, self._implementation) - return self._from_native_series(ser.astype(dtype)) + errors = "raise" if strict else "ignore" + return self._from_native_series(ser.astype(dtype, errors=errors)) def item(self: Self, index: int | None = None) -> Any: # cuDF doesn't have Series.item(). diff --git a/narwhals/_polars/dataframe.py b/narwhals/_polars/dataframe.py index 77d8a016be..0412f1d4bb 100644 --- a/narwhals/_polars/dataframe.py +++ b/narwhals/_polars/dataframe.py @@ -6,6 +6,7 @@ from narwhals._polars.namespace import PolarsNamespace from narwhals._polars.utils import convert_str_slice_to_int_slice from narwhals._polars.utils import extract_args_kwargs +from narwhals._polars.utils import narwhals_to_native_dtype from narwhals._polars.utils import translate_dtype from narwhals.dependencies import get_polars from narwhals.utils import Implementation @@ -16,6 +17,8 @@ import numpy as np from typing_extensions import Self + from narwhals.dtypes import DType + class PolarsDataFrame: def __init__(self, df: Any, *, backend_version: tuple[int, ...]) -> None: @@ -186,6 +189,19 @@ def drop(self: Self, columns: list[str], strict: bool) -> Self: # noqa: FBT001 return self._from_native_frame(self._native_frame.drop(to_drop)) return self._from_native_frame(self._native_frame.drop(columns, strict=strict)) + def cast( + self: Self, + dtypes: dict[str, type[DType] | DType] | type[DType] | DType, + *, + strict: bool, + ) -> Self: + native_frame = self._native_frame + if isinstance(dtypes, dict): + dtypes = {k: narwhals_to_native_dtype(v) for k, v in dtypes.items()} + else: + dtypes = narwhals_to_native_dtype(dtypes) + return self._from_native_frame(native_frame.cast(dtypes, strict=strict)) + class PolarsLazyFrame: def __init__(self, df: Any, *, backend_version: tuple[int, ...]) -> None: @@ -251,3 +267,16 @@ def drop(self: Self, columns: list[str], strict: bool) -> Self: # noqa: FBT001 if self._backend_version < (1, 0, 0): # pragma: no cover return self._from_native_frame(self._native_frame.drop(columns)) return self._from_native_frame(self._native_frame.drop(columns, strict=strict)) + + def cast( + self: Self, + dtypes: dict[str, type[DType] | DType] | type[DType] | DType, + *, + strict: bool, + ) -> Self: + native_frame = self._native_frame + if isinstance(dtypes, dict): + dtypes = {k: narwhals_to_native_dtype(v) for k, v in dtypes.items()} + else: + dtypes = narwhals_to_native_dtype(dtypes) + return self._from_native_frame(native_frame.cast(dtypes, strict=strict)) diff --git a/narwhals/_polars/expr.py b/narwhals/_polars/expr.py index 4f15328232..fa3bd69130 100644 --- a/narwhals/_polars/expr.py +++ b/narwhals/_polars/expr.py @@ -34,10 +34,10 @@ def func(*args: Any, **kwargs: Any) -> Any: return func - def cast(self, dtype: DType) -> Self: + def cast(self: Self, dtype: DType | type[DType], *, strict: bool) -> Self: expr = self._native_expr dtype = narwhals_to_native_dtype(dtype) - return self._from_native_expr(expr.cast(dtype)) + return self._from_native_expr(expr.cast(dtype, strict=strict)) def __eq__(self, other: object) -> Self: # type: ignore[override] return self._from_native_expr(self._native_expr.__eq__(extract_native(other))) diff --git a/narwhals/_polars/series.py b/narwhals/_polars/series.py index e715200423..5bd8e33044 100644 --- a/narwhals/_polars/series.py +++ b/narwhals/_polars/series.py @@ -7,6 +7,8 @@ from narwhals._polars.utils import extract_args_kwargs from narwhals._polars.utils import extract_native +from narwhals._polars.utils import narwhals_to_native_dtype +from narwhals._polars.utils import translate_dtype from narwhals.dependencies import get_polars from narwhals.utils import Implementation @@ -17,8 +19,6 @@ from narwhals._polars.dataframe import PolarsDataFrame from narwhals.dtypes import DType -from narwhals._polars.utils import narwhals_to_native_dtype -from narwhals._polars.utils import translate_dtype PL = get_polars() @@ -88,10 +88,10 @@ def __getitem__(self, item: slice | Sequence[int]) -> Self: ... def __getitem__(self, item: int | slice | Sequence[int]) -> Any | Self: return self._from_native_object(self._native_series.__getitem__(item)) - def cast(self, dtype: DType) -> Self: + def cast(self, dtype: DType | type[DType], *, strict: bool) -> Self: ser = self._native_series dtype = narwhals_to_native_dtype(dtype) - return self._from_native_series(ser.cast(dtype)) + return self._from_native_series(ser.cast(dtype, strict=strict)) def __array__(self, dtype: Any = None, copy: bool | None = None) -> np.ndarray: if self._backend_version < (0, 20, 29): # pragma: no cover diff --git a/narwhals/dataframe.py b/narwhals/dataframe.py index 83ebdcdc5a..baa51c3123 100644 --- a/narwhals/dataframe.py +++ b/narwhals/dataframe.py @@ -28,6 +28,7 @@ import pyarrow as pa from typing_extensions import Self + from narwhals.dtypes import DType from narwhals.group_by import GroupBy from narwhals.group_by import LazyGroupBy from narwhals.series import Series @@ -292,6 +293,16 @@ def join_asof( ) ) + def cast( + self: Self, + dtypes: dict[str, type[DType] | DType] | type[DType] | DType, + *, + strict: bool = True, + ) -> Self: + return self._from_compliant_dataframe( + self._compliant_frame.cast(dtypes=dtypes, strict=strict) + ) + class DataFrame(BaseFrame[FrameT]): """ @@ -2616,6 +2627,70 @@ def sample( ) ) + def cast( + self: Self, + dtypes: dict[str, type[DType] | DType] | type[DType] | DType, + *, + strict: bool = True, + ) -> Self: + r""" + Cast DataFrame column(s) to the specified dtype(s). + + Arguments: + dtypes: Mapping of column names to dtypes, or a single dtype to + which all columns will be cast. + strict: Throw an error if a cast could not be done (for instance, + due to an overflow). Remark that not all backends support this + feature. + + Examples: + >>> import narwhals as nw + >>> import pandas as pd + >>> import polars as pl + >>> import pyarrow as pa + >>> data = { + ... "foo": [1, 2, 3], + ... "bar": [6.0, 7.0, 8.0], + ... } + + Let's define a dataframe-agnostic function that casts specific frame + columns to the specified dtypes: + + >>> @nw.narwhalify + ... def func(df): + ... return df.cast({"foo": nw.Float32, "bar": nw.UInt8}) + + We can then pass any supported library such as pandas, Polars + (eager), or PyArrow to `func`: + + >>> func(pd.DataFrame(data)) + foo bar + 0 1.0 6 + 1 2.0 7 + 2 3.0 8 + + >>> func(pl.DataFrame(data)) + shape: (3, 2) + ┌─────┬─────┐ + │ foo ┆ bar │ + │ --- ┆ --- │ + │ f32 ┆ u8 │ + ╞═════╪═════╡ + │ 1.0 ┆ 6 │ + │ 2.0 ┆ 7 │ + │ 3.0 ┆ 8 │ + └─────┴─────┘ + + >>> func(pa.table(data)) + pyarrow.Table + foo: float + bar: uint8 + ---- + foo: [[1,2,3]] + bar: [[6,7,8]] + """ + return super().cast(dtypes=dtypes, strict=strict) + class LazyFrame(BaseFrame[FrameT]): """ @@ -4159,3 +4234,49 @@ def gather_every(self: Self, n: int, offset: int = 0) -> Self: └─────┴─────┘ """ return super().gather_every(n=n, offset=offset) + + def cast( + self: Self, + dtypes: dict[str, type[DType] | DType] | type[DType] | DType, + *, + strict: bool = True, + ) -> Self: + r""" + Cast LazyFrame column(s) to the specified dtype(s). + + Arguments: + dtypes: Mapping of column names to dtypes, or a single dtype to + which all columns will be cast. + strict: Throw an error if a cast could not be done (for instance, + due to an overflow). Remark that not all backends support this + feature. + + Examples: + + >>> import narwhals as nw + >>> import polars as pl + >>> data = { + ... "foo": [1, 2, 3], + ... "bar": [6.0, 7.0, 8.0], + ... } + + Let's define a dataframe-agnostic function that casts specific frame + columns to the specified dtypes + + >>> @nw.narwhalify + ... def func(df): + ... return df.cast({"foo": nw.Float32, "bar": nw.UInt8}).collect() + + >>> func(pl.LazyFrame(data)) + shape: (3, 2) + ┌─────┬─────┐ + │ foo ┆ bar │ + │ --- ┆ --- │ + │ f32 ┆ u8 │ + ╞═════╪═════╡ + │ 1.0 ┆ 6 │ + │ 2.0 ┆ 7 │ + │ 3.0 ┆ 8 │ + └─────┴─────┘ + """ + return super().cast(dtypes=dtypes, strict=strict) diff --git a/narwhals/expr.py b/narwhals/expr.py index b04a471daa..3abef8c845 100644 --- a/narwhals/expr.py +++ b/narwhals/expr.py @@ -117,15 +117,13 @@ def pipe(self, function: Callable[[Any], Self], *args: Any, **kwargs: Any) -> Se """ return function(self, *args, **kwargs) - def cast( - self, - dtype: Any, - ) -> Self: + def cast(self, dtype: DType | type[DType], *, strict: bool = True) -> Self: """ Redefine an object's data type. Arguments: dtype: Data type that the object will be cast into. + strict: If True invalid casts generate exceptions instead of nulls. Examples: >>> import pandas as pd @@ -163,7 +161,7 @@ def cast( └─────┴─────┘ """ return self.__class__( - lambda plx: self._call(plx).cast(dtype), + lambda plx: self._call(plx).cast(dtype, strict=strict), ) # --- binary --- diff --git a/narwhals/series.py b/narwhals/series.py index 441900a310..759b343c67 100644 --- a/narwhals/series.py +++ b/narwhals/series.py @@ -16,6 +16,7 @@ from typing_extensions import Self from narwhals.dataframe import DataFrame + from narwhals.dtypes import DType class Series: @@ -357,15 +358,13 @@ def name(self) -> str: """ return self._compliant_series.name # type: ignore[no-any-return] - def cast( - self, - dtype: Any, - ) -> Self: + def cast(self: Self, dtype: DType | type[DType], *, strict: bool = True) -> Self: """ Cast between data types. Arguments: dtype: Data type that the object will be cast into. + strict: If True invalid casts generate exceptions instead of nulls. Examples: >>> import pandas as pd @@ -397,7 +396,9 @@ def cast( 1 ] """ - return self._from_compliant_series(self._compliant_series.cast(dtype)) + return self._from_compliant_series( + self._compliant_series.cast(dtype, strict=strict) + ) def to_frame(self) -> DataFrame[Any]: """ diff --git a/tests/expr_and_series/cast_test.py b/tests/expr_and_series/cast_test.py index 00f242148c..72c994dbbb 100644 --- a/tests/expr_and_series/cast_test.py +++ b/tests/expr_and_series/cast_test.py @@ -179,4 +179,4 @@ class Banana: pass with pytest.raises(AssertionError, match=r"Unknown dtype"): - df.select(nw.col("a").cast(Banana)) + df.select(nw.col("a").cast(Banana)) # type: ignore[arg-type] diff --git a/tests/frame/cast_test.py b/tests/frame/cast_test.py new file mode 100644 index 0000000000..0e4da6ffab --- /dev/null +++ b/tests/frame/cast_test.py @@ -0,0 +1,118 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import pyarrow as pa +import pytest + +import narwhals.stable.v1 as nw +from narwhals.utils import parse_version + +if TYPE_CHECKING: + from narwhals.dtypes import DType + from tests.utils import Constructor + +data = { + "a": [1], + "b": [1], + "c": [1], + "d": [1], + "e": [1], + "f": [1], + "g": [1], + "h": [1], + "i": [1], + "j": [1], + "k": ["1"], + "l": [1], + "m": [True], + "n": [True], + "o": ["a"], + "p": [1], +} +schema: dict[str, type[DType] | DType] | type[DType] | DType = { + "a": nw.Int64, + "b": nw.Int32, + "c": nw.Int16, + "d": nw.Int8, + "e": nw.UInt64, + "f": nw.UInt32, + "g": nw.UInt16, + "h": nw.UInt8, + "i": nw.Float64, + "j": nw.Float32, + "k": nw.String, + "l": nw.Datetime, + "m": nw.Boolean, + "n": nw.Boolean, + "o": nw.Categorical, + "p": nw.Int64, +} + + +@pytest.mark.filterwarnings("ignore:casting period[M] values to int64:FutureWarning") +def test_cast(constructor: Constructor, request: pytest.FixtureRequest) -> None: + if "pyarrow_table_constructor" in str(constructor) and parse_version( + pa.__version__ + ) <= (15,): # pragma: no cover + request.applymarker(pytest.mark.xfail) + if "modin" in str(constructor): + # TODO(unassigned): in modin, we end up with `' None: + if "pyarrow_table_constructor" in str(constructor) and parse_version( + pa.__version__ + ) <= (15,): # pragma: no cover + request.applymarker(pytest.mark.xfail) + if "modin" in str(constructor): + # TODO(unassigned): in modin, we end up with `' None: with pytest.raises(TypeError, match="Perhaps you:"): df.select([pl.col("a")]) # type: ignore[list-item] with pytest.raises(TypeError, match="Perhaps you:"): - df.select([nw.col("a").cast(pl.Int64)]) + df.select([nw.col("a").cast(pl.Int64)]) # type: ignore[arg-type]