Skip to content

Commit c1f364f

Browse files
committed
fix: raise on selectors addition
1 parent 23ed049 commit c1f364f

File tree

5 files changed

+38
-40
lines changed

5 files changed

+38
-40
lines changed

narwhals/_arrow/selectors.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from typing import TYPE_CHECKING
44
from typing import Any
5-
from typing import NoReturn
65
from typing import Sequence
76

87
from narwhals._arrow.expr import ArrowExpr
@@ -178,12 +177,3 @@ def __invert__(self: Self) -> ArrowSelector:
178177
).all()
179178
- self
180179
)
181-
182-
def __rsub__(self: Self, other: Any) -> NoReturn:
183-
raise NotImplementedError
184-
185-
def __rand__(self: Self, other: Any) -> NoReturn:
186-
raise NotImplementedError
187-
188-
def __ror__(self: Self, other: Any) -> NoReturn:
189-
raise NotImplementedError

narwhals/_dask/selectors.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from typing import TYPE_CHECKING
44
from typing import Any
5-
from typing import NoReturn
65

76
from narwhals._dask.expr import DaskExpr
87
from narwhals.utils import import_dtypes_module
@@ -186,12 +185,3 @@ def __invert__(self: Self) -> DaskSelector:
186185
).all()
187186
- self
188187
)
189-
190-
def __rsub__(self: Self, other: Any) -> NoReturn:
191-
raise NotImplementedError
192-
193-
def __rand__(self: Self, other: Any) -> NoReturn:
194-
raise NotImplementedError
195-
196-
def __ror__(self: Self, other: Any) -> NoReturn:
197-
raise NotImplementedError

narwhals/_pandas_like/selectors.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from typing import TYPE_CHECKING
44
from typing import Any
5-
from typing import NoReturn
65

76
from narwhals._pandas_like.expr import PandasLikeExpr
87
from narwhals.utils import import_dtypes_module
@@ -189,12 +188,3 @@ def __invert__(self: Self) -> PandasSelector:
189188
).all()
190189
- self
191190
)
192-
193-
def __rsub__(self, other: Any) -> NoReturn:
194-
raise NotImplementedError
195-
196-
def __rand__(self, other: Any) -> NoReturn:
197-
raise NotImplementedError
198-
199-
def __ror__(self, other: Any) -> NoReturn:
200-
raise NotImplementedError

narwhals/selectors.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,39 @@
11
from __future__ import annotations
22

3+
from typing import TYPE_CHECKING
34
from typing import Any
5+
from typing import NoReturn
46

57
from narwhals.expr import Expr
68
from narwhals.utils import flatten
79

10+
if TYPE_CHECKING:
11+
from typing_extensions import Self
812

9-
class Selector(Expr): ...
13+
14+
class Selector(Expr):
15+
def _to_expr(self: Self) -> Expr:
16+
return Expr(
17+
to_compliant_expr=self._to_compliant_expr,
18+
is_order_dependent=self._is_order_dependent,
19+
changes_length=self._changes_length,
20+
aggregates=self._aggregates,
21+
)
22+
23+
def __add__(self: Self, other: Any) -> Expr: # type: ignore[override]
24+
if isinstance(other, Selector):
25+
msg = "unsupported operand type(s) for op: ('Selector' + 'Selector')"
26+
raise TypeError(msg)
27+
return self._to_expr() + other # type: ignore[no-any-return]
28+
29+
def __rsub__(self: Self, other: Any) -> NoReturn:
30+
raise NotImplementedError
31+
32+
def __rand__(self: Self, other: Any) -> NoReturn:
33+
raise NotImplementedError
34+
35+
def __ror__(self: Self, other: Any) -> NoReturn:
36+
raise NotImplementedError
1037

1138

1239
def by_dtype(*dtypes: Any) -> Expr:

tests/selectors_test.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

3-
import pandas as pd
4-
import pyarrow as pa
3+
import re
4+
55
import pytest
66

77
import narwhals.stable.v1 as nw
@@ -103,16 +103,17 @@ def test_set_ops(
103103
assert sorted(result) == expected
104104

105105

106-
@pytest.mark.parametrize("invalid_constructor", [pd.DataFrame, pa.table])
107-
def test_set_ops_invalid(
108-
invalid_constructor: Constructor, request: pytest.FixtureRequest
109-
) -> None:
110-
if "duckdb" in str(invalid_constructor):
111-
request.applymarker(pytest.mark.xfail)
112-
df = nw.from_native(invalid_constructor(data))
106+
def test_set_ops_invalid(constructor: Constructor) -> None:
107+
df = nw.from_native(constructor(data))
113108
with pytest.raises((NotImplementedError, ValueError)):
114109
df.select(1 - numeric())
115110
with pytest.raises((NotImplementedError, ValueError)):
116111
df.select(1 | numeric())
117112
with pytest.raises((NotImplementedError, ValueError)):
118113
df.select(1 & numeric())
114+
115+
with pytest.raises(
116+
TypeError,
117+
match=re.escape("unsupported operand type(s) for op: ('Selector' + 'Selector')"),
118+
):
119+
df.select(boolean() + numeric())

0 commit comments

Comments
 (0)