Repository: narwhals-dev/narwhals
Pull request #656 (2024-07-28 13:05:11)

chore: enable more lazy tests
<!--
# Thanks for contributing a pull request! 
## Please make sure you see our contribution guidelines: https://github.com/narwhals-dev/narwhals/blob/main/CONTRIBUTING.md
-->

## What type of PR is this? (check all applicable)

- [ ] 💾 Refactor
- [ ] ✨ Feature
- [ ] 🐛 Bug Fix
- [ ] 🔧 Optimization
- [ ] 📝 Documentation
- [ ] ✅ Test
- [ ] 🐳 Other

## Related issues 

- Related issue # 
- Closes #

## Checklist

- [ ] Code follows style guide (ruff)
- [ ] Tests added 
- [ ] Documented the changes

## If you have comments or can explain your changes, please do so below.




Patch:
diff --git a/narwhals/_arrow/group_by.py b/narwhals/_arrow/group_by.py
index 59090c4d..4da0356a 100644
--- a/narwhals/_arrow/group_by.py
+++ b/narwhals/_arrow/group_by.py
@@ -16,10 +16,6 @@ if TYPE_CHECKING:
     from narwhals._arrow.expr import ArrowExpr
     from narwhals._arrow.typing import IntoArrowExpr
 
-POLARS_TO_ARROW_AGGREGATIONS = {
-    "len": "size",
-}
-
 
 class ArrowGroupBy:
     def __init__(self, df: ArrowDataFrame, keys: list[str]) -> None:
@@ -98,12 +94,17 @@ def agg_arrow(
                 raise AssertionError(msg)
 
             function_name = remove_prefix(expr._function_name, "col->")
-            function_name = POLARS_TO_ARROW_AGGREGATIONS.get(function_name, function_name)
             for root_name, output_name in zip(expr._root_names, expr._output_names):
-                simple_aggregations[output_name] = (
-                    (root_name, function_name),
-                    f"{root_name}_{function_name}",
-                )
+                if function_name != "len":
+                    simple_aggregations[output_name] = (
+                        (root_name, function_name),
+                        f"{root_name}_{function_name}",
+                    )
+                else:
+                    simple_aggregations[output_name] = (
+                        (root_name, "count", pc.CountOptions(mode="all")),
+                        f"{root_name}_count",
+                    )
 
         aggs: list[Any] = []
         name_mapping = {}
diff --git a/pyproject.toml b/pyproject.toml
index f27b53a4..a835c6b9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -90,7 +90,7 @@ filterwarnings = [
   'ignore:.*defaulting to pandas implementation',
   'ignore:.*implementation has mismatches with pandas',
   'ignore:.*Do not use the `random` module inside strategies',
-  'ignore:.*You are using pyarrow version 12.0.0',
+  'ignore:.*You are using pyarrow version 12',
 ]
 xfail_strict = true
 markers = ["slow: marks tests as slow (deselect with '-m \"not slow\"')"]


Test patch:
diff --git a/tests/frame/drop_nulls_test.py b/tests/frame/drop_nulls_test.py
index d733e46d..53cc57bc 100644
--- a/tests/frame/drop_nulls_test.py
+++ b/tests/frame/drop_nulls_test.py
@@ -9,12 +9,10 @@ data = {
 }
 
 
-def test_drop_nulls(constructor_eager: Any) -> None:
-    result = nw.from_native(constructor_eager(data)).drop_nulls()
+def test_drop_nulls(constructor: Any) -> None:
+    result = nw.from_native(constructor(data)).drop_nulls()
     expected = {
         "a": [2.0, 4.0],
         "b": [3.0, 5.0],
     }
     compare_dicts(result, expected)
-    result = nw.from_native(constructor_eager(data)).lazy().drop_nulls()
-    compare_dicts(result, expected)
diff --git a/tests/frame/drop_test.py b/tests/frame/drop_test.py
index c763c8e7..f22d148b 100644
--- a/tests/frame/drop_test.py
+++ b/tests/frame/drop_test.py
@@ -14,8 +14,8 @@ import narwhals.stable.v1 as nw
         (["a", "b"], ["z"]),
     ],
 )
-def test_drop(constructor_eager: Any, drop: list[str], left: list[str]) -> None:
+def test_drop(constructor: Any, drop: list[str], left: list[str]) -> None:
     data = {"a": [1, 3, 2], "b": [4, 4, 6], "z": [7.0, 8, 9]}
-    df = nw.from_native(constructor_eager(data))
-    assert df.drop(drop).columns == left
-    assert df.drop(*drop).columns == left
+    df = nw.from_native(constructor(data))
+    assert df.drop(drop).collect_schema().names() == left
+    assert df.drop(*drop).collect_schema().names() == left
diff --git a/tests/frame/filter_test.py b/tests/frame/filter_test.py
index 41bd4c06..9b7ed45d 100644
--- a/tests/frame/filter_test.py
+++ b/tests/frame/filter_test.py
@@ -4,9 +4,9 @@ import narwhals.stable.v1 as nw
 from tests.utils import compare_dicts
 
 
-def test_filter(constructor_eager: Any) -> None:
+def test_filter(constructor: Any) -> None:
     data = {"a": [1, 3, 2], "b": [4, 4, 6], "z": [7.0, 8, 9]}
-    df = nw.from_native(constructor_eager(data), eager_only=True)
+    df = nw.from_native(constructor(data))
     result = df.filter(nw.col("a") > 1)
     expected = {"a": [3, 2], "b": [4, 6], "z": [8.0, 9.0]}
     compare_dicts(result, expected)
diff --git a/tests/frame/head_test.py b/tests/frame/head_test.py
index bddfc0f2..f508a9c5 100644
--- a/tests/frame/head_test.py
+++ b/tests/frame/head_test.py
@@ -6,21 +6,22 @@ import narwhals.stable.v1 as nw
 from tests.utils import compare_dicts
 
 
-def test_head(constructor_eager: Any) -> None:
+def test_head(constructor: Any) -> None:
     data = {"a": [1, 3, 2], "b": [4, 4, 6], "z": [7.0, 8, 9]}
     expected = {"a": [1, 3], "b": [4, 4], "z": [7.0, 8.0]}
 
-    df_raw = constructor_eager(data)
-    df = nw.from_native(df_raw).lazy()
+    df_raw = constructor(data)
+    df = nw.from_native(df_raw)
 
     result = df.head(2)
     compare_dicts(result, expected)
 
-    result = df.collect().head(2)  # type: ignore[assignment]
+    result = df.head(2)
     compare_dicts(result, expected)
 
-    result = df.collect().head(-1)  # type: ignore[assignment]
+    # negative indices not allowed for lazyframes
+    result = df.lazy().collect().head(-1)
     compare_dicts(result, expected)
 
-    result = df.collect().select(nw.col("a").head(2))  # type: ignore[assignment]
+    result = df.select(nw.col("a").head(2))
     compare_dicts(result, {"a": expected["a"]})
diff --git a/tests/frame/pipe_test.py b/tests/frame/pipe_test.py
index d8f2d5c6..a9a50133 100644
--- a/tests/frame/pipe_test.py
+++ b/tests/frame/pipe_test.py
@@ -9,11 +9,9 @@ data = {
 }
 
 
-def test_pipe(constructor_eager: Any) -> None:
-    df = nw.from_native(constructor_eager(data))
-    columns = df.lazy().collect().columns
+def test_pipe(constructor: Any) -> None:
+    df = nw.from_native(constructor(data))
+    columns = df.collect_schema().names()
     result = df.pipe(lambda _df: _df.select([x for x in columns if len(x) == 2]))
     expected = {"ab": ["foo", "bars"]}
     compare_dicts(result, expected)
-    result = df.lazy().pipe(lambda _df: _df.select([x for x in columns if len(x) == 2]))
-    compare_dicts(result, expected)
diff --git a/tests/frame/rename_test.py b/tests/frame/rename_test.py
index d921a837..c58eccd4 100644
--- a/tests/frame/rename_test.py
+++ b/tests/frame/rename_test.py
@@ -4,9 +4,9 @@ import narwhals.stable.v1 as nw
 from tests.utils import compare_dicts
 
 
-def test_rename(constructor_eager: Any) -> None:
+def test_rename(constructor: Any) -> None:
     data = {"a": [1, 3, 2], "b": [4, 4, 6], "z": [7.0, 8, 9]}
-    df = nw.from_native(constructor_eager(data), eager_only=True)
+    df = nw.from_native(constructor(data))
     result = df.rename({"a": "x", "b": "y"})
     expected = {"x": [1, 3, 2], "y": [4, 4, 6], "z": [7.0, 8, 9]}
     compare_dicts(result, expected)
diff --git a/tests/frame/select_test.py b/tests/frame/select_test.py
index 286eeac9..6891ec4f 100644
--- a/tests/frame/select_test.py
+++ b/tests/frame/select_test.py
@@ -4,9 +4,9 @@ import narwhals.stable.v1 as nw
 from tests.utils import compare_dicts
 
 
-def test_select(constructor_eager: Any) -> None:
+def test_select(constructor: Any) -> None:
     data = {"a": [1, 3, 2], "b": [4, 4, 6], "z": [7.0, 8, 9]}
-    df = nw.from_native(constructor_eager(data), eager_only=True)
+    df = nw.from_native(constructor(data))
     result = df.select("a")
     expected = {"a": [1, 3, 2]}
     compare_dicts(result, expected)
diff --git a/tests/frame/sort_test.py b/tests/frame/sort_test.py
index a4465944..9e583f8b 100644
--- a/tests/frame/sort_test.py
+++ b/tests/frame/sort_test.py
@@ -4,9 +4,9 @@ import narwhals.stable.v1 as nw
 from tests.utils import compare_dicts
 
 
-def test_sort(constructor_eager: Any) -> None:
+def test_sort(constructor: Any) -> None:
     data = {"a": [1, 3, 2], "b": [4, 4, 6], "z": [7.0, 8, 9]}
-    df = nw.from_native(constructor_eager(data), eager_only=True)
+    df = nw.from_native(constructor(data))
     result = df.sort("a", "b")
     expected = {
         "a": [1, 2, 3],
diff --git a/tests/frame/tail_test.py b/tests/frame/tail_test.py
index 3f76c02e..e279caba 100644
--- a/tests/frame/tail_test.py
+++ b/tests/frame/tail_test.py
@@ -6,11 +6,11 @@ import narwhals.stable.v1 as nw
 from tests.utils import compare_dicts
 
 
-def test_tail(constructor_eager: Any) -> None:
+def test_tail(constructor: Any) -> None:
     data = {"a": [1, 3, 2], "b": [4, 4, 6], "z": [7.0, 8, 9]}
     expected = {"a": [3, 2], "b": [4, 6], "z": [8.0, 9]}
 
-    df_raw = constructor_eager(data)
+    df_raw = constructor(data)
     df = nw.from_native(df_raw).lazy()
 
     result = df.tail(2)
diff --git a/tests/frame/with_row_index_test.py b/tests/frame/with_row_index_test.py
index 2b3870ac..bc1c2fe0 100644
--- a/tests/frame/with_row_index_test.py
+++ b/tests/frame/with_row_index_test.py
@@ -9,9 +9,7 @@ data = {
 }
 
 
-def test_with_row_index(constructor_eager: Any) -> None:
-    result = nw.from_native(constructor_eager(data)).with_row_index()
+def test_with_row_index(constructor: Any) -> None:
+    result = nw.from_native(constructor(data)).with_row_index()
     expected = {"a": ["foo", "bars"], "ab": ["foo", "bars"], "index": [0, 1]}
     compare_dicts(result, expected)
-    result = nw.from_native(constructor_eager(data)).lazy().with_row_index()
-    compare_dicts(result, expected)
diff --git a/tests/from_dict_test.py b/tests/from_dict_test.py
index b4a11e6c..17892d80 100644
--- a/tests/from_dict_test.py
+++ b/tests/from_dict_test.py
@@ -4,10 +4,8 @@ import narwhals.stable.v1 as nw
 from tests.utils import compare_dicts
 
 
-def test_from_dict(constructor_eager: Any) -> None:
-    df = nw.from_native(
-        constructor_eager({"a": [1, 2, 3], "b": [4, 5, 6]}), eager_only=True
-    )
+def test_from_dict(constructor: Any) -> None:
+    df = nw.from_native(constructor({"a": [1, 2, 3], "b": [4, 5, 6]}))
     native_namespace = nw.get_native_namespace(df)
     result = nw.from_dict({"c": [1, 2], "d": [5, 6]}, native_namespace=native_namespace)
     expected = {"c": [1, 2], "d": [5, 6]}
@@ -15,11 +13,9 @@ def test_from_dict(constructor_eager: Any) -> None:
     assert isinstance(result, nw.DataFrame)
 
 
-def test_from_dict_schema(constructor_eager: Any) -> None:
+def test_from_dict_schema(constructor: Any) -> None:
     schema = {"c": nw.Int16(), "d": nw.Float32()}
-    df = nw.from_native(
-        constructor_eager({"a": [1, 2, 3], "b": [4, 5, 6]}), eager_only=True
-    )
+    df = nw.from_native(constructor({"a": [1, 2, 3], "b": [4, 5, 6]}))
     native_namespace = nw.get_native_namespace(df)
     result = nw.from_dict(
         {"c": [1, 2], "d": [5, 6]},
diff --git a/tests/stable_api_test.py b/tests/stable_api_test.py
index 44c15e89..211ba865 100644
--- a/tests/stable_api_test.py
+++ b/tests/stable_api_test.py
@@ -8,7 +8,7 @@ import narwhals.stable.v1 as nw_v1
 from tests.utils import compare_dicts
 
 
-def test_renamed_taxicab_norm(constructor_eager: Any) -> None:
+def test_renamed_taxicab_norm(constructor: Any) -> None:
     # Suppose we need to rename `_l1_norm` to `_taxicab_norm`.
     # We need `narwhals.stable.v1` to stay stable. So, we
     # make the change in `narwhals`, and then add the new method
@@ -17,7 +17,7 @@ def test_renamed_taxicab_norm(constructor_eager: Any) -> None:
     # API will still be able to use it, without the main namespace
     # getting cluttered by the new name.
 
-    df = nw.from_native(constructor_eager({"a": [1, 2, 3, -4, 5]}))
+    df = nw.from_native(constructor({"a": [1, 2, 3, -4, 5]}))
     result = df.with_columns(b=nw.col("a")._taxicab_norm())
     expected = {"a": [1, 2, 3, -4, 5], "b": [15] * 5}
     compare_dicts(result, expected)
@@ -25,7 +25,7 @@ def test_renamed_taxicab_norm(constructor_eager: Any) -> None:
     with pytest.raises(AttributeError):
         result = df.with_columns(b=nw.col("a")._l1_norm())  # type: ignore[attr-defined]
 
-    df = nw_v1.from_native(constructor_eager({"a": [1, 2, 3, -4, 5]}))
+    df = nw_v1.from_native(constructor({"a": [1, 2, 3, -4, 5]}))
     # The newer `_taxicab_norm` can still work in the old API, no issue.
     # It's new, so it couldn't be backwards-incompatible.
     result = df.with_columns(b=nw_v1.col("a")._taxicab_norm())
diff --git a/tests/test_group_by.py b/tests/test_group_by.py
index 35aa6e6b..388d6a69 100644
--- a/tests/test_group_by.py
+++ b/tests/test_group_by.py
@@ -78,15 +78,9 @@ def test_group_by_iter(request: Any, constructor_eager: Any) -> None:
     assert sorted(keys) == sorted(expected_keys)
 
 
-def test_group_by_len(request: Any, constructor_eager: Any) -> None:
-    if "pyarrow_table" in str(constructor_eager):
-        request.applymarker(pytest.mark.xfail)
-
+def test_group_by_len(constructor: Any) -> None:
     result = (
-        nw.from_native(constructor_eager(data))
-        .group_by("a")
-        .agg(nw.col("b").len())
-        .sort("a")
+        nw.from_native(constructor(data)).group_by("a").agg(nw.col("b").len()).sort("a")
     )
     expected = {"a": [1, 3], "b": [2, 1]}
     compare_dicts(result, expected)
diff --git a/tests/test_selectors.py b/tests/test_selectors.py
index 463583b2..6edcb806 100644
--- a/tests/test_selectors.py
+++ b/tests/test_selectors.py
@@ -24,44 +24,42 @@ data = {
 }
 
 
-def test_selectors(constructor_eager: Any) -> None:
-    df = nw.from_native(constructor_eager(data))
+def test_selectors(constructor: Any) -> None:
+    df = nw.from_native(constructor(data))
     result = df.select(by_dtype([nw.Int64, nw.Float64]) + 1)
     expected = {"a": [2, 2, 3], "c": [5.1, 6.0, 7.0]}
     compare_dicts(result, expected)
 
 
-def test_numeric(constructor_eager: Any) -> None:
-    df = nw.from_native(constructor_eager(data))
+def test_numeric(constructor: Any) -> None:
+    df = nw.from_native(constructor(data))
     result = df.select(numeric() + 1)
     expected = {"a": [2, 2, 3], "c": [5.1, 6.0, 7.0]}
     compare_dicts(result, expected)
 
 
-def test_boolean(constructor_eager: Any) -> None:
-    df = nw.from_native(constructor_eager(data))
+def test_boolean(constructor: Any) -> None:
+    df = nw.from_native(constructor(data))
     result = df.select(boolean())
     expected = {"d": [True, False, True]}
     compare_dicts(result, expected)
 
 
-def test_string(constructor_eager: Any) -> None:
-    df = nw.from_native(constructor_eager(data))
+def test_string(constructor: Any) -> None:
+    df = nw.from_native(constructor(data))
     result = df.select(string())
     expected = {"b": ["a", "b", "c"]}
     compare_dicts(result, expected)
 
 
-def test_categorical(request: Any, constructor_eager: Any) -> None:
-    if "pyarrow_table_constructor" in str(constructor_eager) and parse_version(
+def test_categorical(request: Any, constructor: Any) -> None:
+    if "pyarrow_table_constructor" in str(constructor) and parse_version(
         pa.__version__
     ) <= (15,):  # pragma: no cover
         request.applymarker(pytest.mark.xfail)
     expected = {"b": ["a", "b", "c"]}
 
-    df = nw.from_native(constructor_eager(data)).with_columns(
-        nw.col("b").cast(nw.Categorical)
-    )
+    df = nw.from_native(constructor(data)).with_columns(nw.col("b").cast(nw.Categorical))
     result = df.select(categorical())
     compare_dicts(result, expected)
 
@@ -81,10 +79,10 @@ def test_categorical(request: Any, constructor_eager: Any) -> None:
     ],
 )
 def test_set_ops(
-    constructor_eager: Any, selector: nw.selectors.Selector, expected: list[str]
+    constructor: Any, selector: nw.selectors.Selector, expected: list[str]
 ) -> None:
-    df = nw.from_native(constructor_eager(data))
-    result = df.select(selector).columns
+    df = nw.from_native(constructor(data))
+    result = df.select(selector).collect_schema().names()
     assert sorted(result) == expected