Repository: narwhals-dev/narwhals

Issue:
wrong argument in Expr.filter and Series.filter - "other" instead of "*predicates"
I'm working on the docstring for Expr.filter() but I noticed that the name of the argument suggests it accepts "other" df/series.
It's also the case for Series.filter()
Dataframe.filter() has *predicates as an argument and so does Expr.filter() in polars.
Should it be that way or should it be corrected? 



Discussion:

Patch:
diff --git a/narwhals/_pandas_like/expr.py b/narwhals/_pandas_like/expr.py
index f9020824..1dc4f306 100644
--- a/narwhals/_pandas_like/expr.py
+++ b/narwhals/_pandas_like/expr.py
@@ -184,8 +184,12 @@ class PandasExpr:
     def is_in(self, other: Any) -> Self:
         return register_expression_call(self, "is_in", other)
 
-    def filter(self, other: Any) -> Self:
-        return register_expression_call(self, "filter", other)
+    def filter(self, *predicates: Any) -> Self:
+        from narwhals._pandas_like.namespace import PandasNamespace
+
+        plx = PandasNamespace(self._implementation)
+        expr = plx.all_horizontal(*predicates)
+        return register_expression_call(self, "filter", expr)
 
     def drop_nulls(self) -> Self:
         return register_expression_call(self, "drop_nulls")
diff --git a/narwhals/expression.py b/narwhals/expression.py
index fbddc1e3..674b5981 100644
--- a/narwhals/expression.py
+++ b/narwhals/expression.py
@@ -851,9 +851,11 @@ class Expr:
                 "Narwhals `is_in` doesn't accept expressions as an argument, as opposed to Polars. You should provide an iterable instead."
             )
 
-    def filter(self, other: Any) -> Expr:
+    def filter(self, *predicates: Any) -> Expr:
         return self.__class__(
-            lambda plx: self._call(plx).filter(extract_native(plx, other))
+            lambda plx: self._call(plx).filter(
+                *[extract_native(plx, pred) for pred in flatten(predicates)]
+            )
         )
 
     def is_null(self) -> Expr:


Test patch:
diff --git a/tests/expr/filter_test.py b/tests/expr/filter_test.py
new file mode 100644
index 00000000..ea15a94f
--- /dev/null
+++ b/tests/expr/filter_test.py
@@ -0,0 +1,27 @@
+from typing import Any
+
+import pandas as pd
+import polars as pl
+import pytest
+
+import narwhals as nw
+from tests.utils import compare_dicts
+
+data = {
+    "i": [0, 1, 2, 3, 4],
+    "a": [0, 1, 2, 3, 4],
+    "b": [1, 2, 3, 5, 3],
+    "c": [5, 4, 3, 2, 1],
+}
+
+
+@pytest.mark.parametrize("constructor", [pd.DataFrame, pl.DataFrame])
+def test_filter(constructor: Any) -> None:
+    df = nw.from_native(constructor(data), eager_only=True)
+    result = df.select(nw.col("a").filter(nw.col("i") < 2, nw.col("c") == 5))
+    expected = {
+        "a": [0],
+    }
+    compare_dicts(result, expected)
+    result = df.select(df["a"].filter((df["i"] < 2) & (df["c"] == 5)))
+    compare_dicts(result, expected)