Repository: narwhals-dev/narwhals

Issue:
test: use `constructor_eager` instead of parametrising over example dataframes
There's still some cases in the test suite where we're parametrising over dataframes instead of using `constructor` / `constructor_eager`:

The task is:
- look for instances of `df_pandas = ` in the `tests` folder. e.g.: https://github.com/narwhals-dev/narwhals/blob/000c360fef499bc8f4169f0759abd7cd2b6ee0ef/tests/frame/rows_test.py#L13-L41
- rewrite the test using `constructor_eager` instead

Discussion:

Patch:
diff --git a/narwhals/_arrow/series.py b/narwhals/_arrow/series.py
index 65a393ca..2eb73829 100644
--- a/narwhals/_arrow/series.py
+++ b/narwhals/_arrow/series.py
@@ -784,7 +784,7 @@ class ArrowSeriesDateTimeNamespace:
         import pyarrow as pa  # ignore-banned-import()
 
         return self._arrow_series._from_native_series(
-            self._arrow_series._native_series.cast(pa.date64())
+            self._arrow_series._native_series.cast(pa.date32())
         )
 
     def year(self: Self) -> ArrowSeries:
diff --git a/narwhals/_expression_parsing.py b/narwhals/_expression_parsing.py
index d281cc94..89d020b0 100644
--- a/narwhals/_expression_parsing.py
+++ b/narwhals/_expression_parsing.py
@@ -219,19 +219,21 @@ def reuse_series_implementation(
     plx = expr.__narwhals_namespace__()
 
     def func(df: CompliantDataFrame) -> list[CompliantSeries]:
-        out: list[CompliantSeries] = []
-        for column in expr._call(df):  # type: ignore[arg-type]
-            _out = getattr(column, attr)(
-                *[maybe_evaluate_expr(df, arg) for arg in args],
-                **{
-                    arg_name: maybe_evaluate_expr(df, arg_value)
-                    for arg_name, arg_value in kwargs.items()
-                },
+        _args = [maybe_evaluate_expr(df, arg) for arg in args]
+        _kwargs = {
+            arg_name: maybe_evaluate_expr(df, arg_value)
+            for arg_name, arg_value in kwargs.items()
+        }
+
+        out: list[CompliantSeries] = [
+            plx._create_series_from_scalar(
+                getattr(column, attr)(*_args, **_kwargs),
+                column,  # type: ignore[arg-type]
             )
-            if returns_scalar:
-                out.append(plx._create_series_from_scalar(_out, column))  # type: ignore[arg-type]
-            else:
-                out.append(_out)
+            if returns_scalar
+            else getattr(column, attr)(*_args, **_kwargs)
+            for column in expr._call(df)  # type: ignore[arg-type]
+        ]
         if expr._output_names is not None and (
             [s.name for s in out] != expr._output_names
         ):  # pragma: no cover


Test patch:
diff --git a/tests/expr_and_series/dt/datetime_attributes_test.py b/tests/expr_and_series/dt/datetime_attributes_test.py
index 757d226f..017daace 100644
--- a/tests/expr_and_series/dt/datetime_attributes_test.py
+++ b/tests/expr_and_series/dt/datetime_attributes_test.py
@@ -104,3 +104,15 @@ def test_datetime_chained_attributes(
 
     result = df.select(nw.col("a").dt.date().dt.year())
     compare_dicts(result, {"a": [2021, 2020]})
+
+
+def test_to_date(request: pytest.FixtureRequest, constructor: Constructor) -> None:
+    if any(
+        x in str(constructor)
+        for x in ("pandas_constructor", "pandas_nullable_constructor", "dask")
+    ):
+        request.applymarker(pytest.mark.xfail)
+    dates = {"a": [datetime(2001, 1, 1), None, datetime(2001, 1, 3)]}
+    df = nw.from_native(constructor(dates))
+    result = df.select(nw.col("a").dt.date())
+    assert result.collect_schema() == {"a": nw.Date}
diff --git a/tests/expr_and_series/str/contains_test.py b/tests/expr_and_series/str/contains_test.py
index 2c2e0cb9..98e8ceaa 100644
--- a/tests/expr_and_series/str/contains_test.py
+++ b/tests/expr_and_series/str/contains_test.py
@@ -1,7 +1,5 @@
 from __future__ import annotations
 
-import pandas as pd
-import polars as pl
 import pytest
 
 import narwhals.stable.v1 as nw
@@ -11,9 +9,6 @@ from tests.utils import compare_dicts
 
 data = {"pets": ["cat", "dog", "rabbit and parrot", "dove"]}
 
-df_pandas = pd.DataFrame(data)
-df_polars = pl.DataFrame(data)
-
 
 def test_contains_case_insensitive(
     constructor: Constructor, request: pytest.FixtureRequest
diff --git a/tests/series_only/cast_test.py b/tests/series_only/cast_test.py
index 55752149..c5b37b8c 100644
--- a/tests/series_only/cast_test.py
+++ b/tests/series_only/cast_test.py
@@ -2,6 +2,7 @@ from __future__ import annotations
 
 from datetime import date
 from datetime import datetime
+from typing import TYPE_CHECKING
 
 import pandas as pd
 import polars as pl
@@ -12,16 +13,18 @@ from polars.testing import assert_frame_equal
 import narwhals.stable.v1 as nw
 from narwhals.utils import parse_version
 
+if TYPE_CHECKING:
+    from tests.utils import ConstructorEager
 
-def test_cast_253() -> None:
-    df_polars = pl.DataFrame({"a": [1]})
-    result = nw.from_native(df_polars, eager_only=True).select(
-        nw.col("a").cast(nw.String) + "hi"
-    )["a"][0]
-    assert result == "1hi"
 
-    df_pandas = pd.DataFrame({"a": [1]})
-    result = nw.from_native(df_pandas, eager_only=True).select(
+def test_cast_253(
+    request: pytest.FixtureRequest, constructor_eager: ConstructorEager
+) -> None:
+    if "pyarrow_table" in str(constructor_eager):
+        request.applymarker(pytest.mark.xfail)
+
+    df_raw = constructor_eager({"a": [1]})
+    result = nw.from_native(df_raw, eager_only=True).select(
         nw.col("a").cast(nw.String) + "hi"
     )["a"][0]
     assert result == "1hi"