Repository: narwhals-dev/narwhals
Pull request #1382 (2024-11-15 16:58:28)

feat: Improve error message when comparing Series with list literal, or when using multi-output expressions in unsupported context
https://github.com/narwhals-dev/narwhals/issues/920

<!--
# 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 #\<issue number\>
- Closes #\<issue number\>

## 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/utils.py b/narwhals/_arrow/utils.py
index d5f5fc31..272a7ecd 100644
--- a/narwhals/_arrow/utils.py
+++ b/narwhals/_arrow/utils.py
@@ -152,8 +152,15 @@ def validate_column_comparand(other: Any) -> Any:
 
     if isinstance(other, list):
         if len(other) > 1:
-            # e.g. `plx.all() + plx.all()`
-            msg = "Multi-output expressions are not supported in this context"
+            if hasattr(other[0], "__narwhals_expr__") or hasattr(
+                other[0], "__narwhals_series__"
+            ):
+                # e.g. `plx.all() + plx.all()`
+                msg = "Multi-output expressions (e.g. `nw.all()` or `nw.col('a', 'b')`) are not supported in this context"
+                raise ValueError(msg)
+            msg = (
+                f"Expected scalar value, Series, or Expr, got list of : {type(other[0])}"
+            )
             raise ValueError(msg)
         other = other[0]
     if isinstance(other, ArrowDataFrame):
diff --git a/narwhals/_dask/utils.py b/narwhals/_dask/utils.py
index 913beb19..7ae5e021 100644
--- a/narwhals/_dask/utils.py
+++ b/narwhals/_dask/utils.py
@@ -24,7 +24,7 @@ def maybe_evaluate(df: DaskLazyFrame, obj: Any) -> Any:
     if isinstance(obj, DaskExpr):
         results = obj._call(df)
         if len(results) != 1:  # pragma: no cover
-            msg = "Multi-output expressions not supported in this context"
+            msg = "Multi-output expressions (e.g. `nw.all()` or `nw.col('a', 'b')`) not supported in this context"
             raise NotImplementedError(msg)
         result = results[0]
         validate_comparand(df._native_frame, result)
diff --git a/narwhals/_pandas_like/utils.py b/narwhals/_pandas_like/utils.py
index e9da85ed..2b31ce9c 100644
--- a/narwhals/_pandas_like/utils.py
+++ b/narwhals/_pandas_like/utils.py
@@ -93,8 +93,15 @@ def validate_column_comparand(index: Any, other: Any) -> Any:
 
     if isinstance(other, list):
         if len(other) > 1:
-            # e.g. `plx.all() + plx.all()`
-            msg = "Multi-output expressions are not supported in this context"
+            if hasattr(other[0], "__narwhals_expr__") or hasattr(
+                other[0], "__narwhals_series__"
+            ):
+                # e.g. `plx.all() + plx.all()`
+                msg = "Multi-output expressions (e.g. `nw.all()` or `nw.col('a', 'b')`) are not supported in this context"
+                raise ValueError(msg)
+            msg = (
+                f"Expected scalar value, Series, or Expr, got list of : {type(other[0])}"
+            )
             raise ValueError(msg)
         other = other[0]
     if isinstance(other, PandasLikeDataFrame):
diff --git a/narwhals/expr.py b/narwhals/expr.py
index 9865a04e..be28fd07 100644
--- a/narwhals/expr.py
+++ b/narwhals/expr.py
@@ -2692,8 +2692,7 @@ class Expr:
         return self.__class__(lambda plx: self._call(plx).mode())
 
     def cum_count(self: Self, *, reverse: bool = False) -> Self:
-        r"""
-        Return the cumulative count of the non-null values in the column.
+        r"""Return the cumulative count of the non-null values in the column.
 
         Arguments:
             reverse: reverse the operation
diff --git a/narwhals/series.py b/narwhals/series.py
index 360db996..2fe4b243 100644
--- a/narwhals/series.py
+++ b/narwhals/series.py
@@ -2630,8 +2630,7 @@ class Series:
         return self._from_compliant_series(self._compliant_series.mode())
 
     def cum_count(self: Self, *, reverse: bool = False) -> Self:
-        r"""
-        Return the cumulative count of the non-null values in the series.
+        r"""Return the cumulative count of the non-null values in the series.
 
         Arguments:
             reverse: reverse the operation


Test patch:
diff --git a/tests/frame/reindex_test.py b/tests/frame/reindex_test.py
index 5696f567..e31ca936 100644
--- a/tests/frame/reindex_test.py
+++ b/tests/frame/reindex_test.py
@@ -28,5 +28,5 @@ def test_reindex(df_raw: Any) -> None:
     result = df.with_columns(s.sort())
     expected = {"a": [1, 2, 3], "b": [4, 4, 6], "z": [7.0, 8.0, 9.0]}  # type: ignore[list-item]
     assert_equal_data(result, expected)
-    with pytest.raises(ValueError, match="Multi-output expressions are not supported"):
+    with pytest.raises(ValueError, match="Multi-output expressions"):
         nw.to_native(df.with_columns(nw.all() + nw.all()))
diff --git a/tests/frame/select_test.py b/tests/frame/select_test.py
index 52c2a71f..93f28ace 100644
--- a/tests/frame/select_test.py
+++ b/tests/frame/select_test.py
@@ -1,6 +1,7 @@
 from __future__ import annotations
 
 import pandas as pd
+import pyarrow as pa
 import pytest
 
 import narwhals.stable.v1 as nw
@@ -44,3 +45,11 @@ def test_select_boolean_cols(request: pytest.FixtureRequest) -> None:
     assert_equal_data(result.to_dict(as_series=False), {True: [1, 2]})  # type: ignore[dict-item]
     result = df.select(nw.col([False, True]))  # type: ignore[list-item]
     assert_equal_data(result.to_dict(as_series=False), {True: [1, 2], False: [3, 4]})  # type: ignore[dict-item]
+
+
+def test_comparison_with_list_error_message() -> None:
+    msg = "Expected scalar value, Series, or Expr, got list of : <class 'int'>"
+    with pytest.raises(ValueError, match=msg):
+        nw.from_native(pa.chunked_array([[1, 2, 3]]), series_only=True) == [1, 2, 3]  # noqa: B015
+    with pytest.raises(ValueError, match=msg):
+        nw.from_native(pd.Series([[1, 2, 3]]), series_only=True) == [1, 2, 3]  # noqa: B015