Skip to content

Commit f525f38

Browse files
authored
refactor(expr-ir): Add _guards.py (#3092)
1 parent c3cde01 commit f525f38

File tree

15 files changed

+131
-131
lines changed

15 files changed

+131
-131
lines changed

narwhals/_plan/_guards.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""Common type guards, mostly with inline imports."""
2+
3+
from __future__ import annotations
4+
5+
import datetime as dt
6+
from decimal import Decimal
7+
from typing import TYPE_CHECKING, Any, TypeVar
8+
9+
from narwhals._utils import _hasattr_static
10+
11+
if TYPE_CHECKING:
12+
from typing_extensions import TypeIs
13+
14+
from narwhals._plan import expr
15+
from narwhals._plan.dummy import Expr, Series
16+
from narwhals._plan.protocols import CompliantSeries
17+
from narwhals._plan.typing import NativeSeriesT, Seq
18+
from narwhals.typing import NonNestedLiteral
19+
20+
T = TypeVar("T")
21+
22+
_NON_NESTED_LITERAL_TPS = (
23+
int,
24+
float,
25+
str,
26+
dt.date,
27+
dt.time,
28+
dt.timedelta,
29+
bytes,
30+
Decimal,
31+
)
32+
33+
34+
def _dummy(*_: Any): # type: ignore[no-untyped-def] # noqa: ANN202
35+
from narwhals._plan import dummy
36+
37+
return dummy
38+
39+
40+
def _expr(*_: Any): # type: ignore[no-untyped-def] # noqa: ANN202
41+
from narwhals._plan import expr
42+
43+
return expr
44+
45+
46+
def is_non_nested_literal(obj: Any) -> TypeIs[NonNestedLiteral]:
47+
return obj is None or isinstance(obj, _NON_NESTED_LITERAL_TPS)
48+
49+
50+
def is_expr(obj: Any) -> TypeIs[Expr]:
51+
return isinstance(obj, _dummy().Expr)
52+
53+
54+
def is_column(obj: Any) -> TypeIs[Expr]:
55+
"""Indicate if the given object is a basic/unaliased column."""
56+
return is_expr(obj) and obj.meta.is_column()
57+
58+
59+
def is_series(obj: Series[NativeSeriesT] | Any) -> TypeIs[Series[NativeSeriesT]]:
60+
return isinstance(obj, _dummy().Series)
61+
62+
63+
def is_compliant_series(
64+
obj: CompliantSeries[NativeSeriesT] | Any,
65+
) -> TypeIs[CompliantSeries[NativeSeriesT]]:
66+
return _hasattr_static(obj, "__narwhals_series__")
67+
68+
69+
def is_iterable_reject(obj: Any) -> TypeIs[str | bytes | Series | CompliantSeries]:
70+
return isinstance(obj, (str, bytes, _dummy().Series)) or is_compliant_series(obj)
71+
72+
73+
def is_window_expr(obj: Any) -> TypeIs[expr.WindowExpr]:
74+
return isinstance(obj, _expr().WindowExpr)
75+
76+
77+
def is_function_expr(obj: Any) -> TypeIs[expr.FunctionExpr[Any]]:
78+
return isinstance(obj, _expr().FunctionExpr)
79+
80+
81+
def is_binary_expr(obj: Any) -> TypeIs[expr.BinaryExpr]:
82+
return isinstance(obj, _expr().BinaryExpr)
83+
84+
85+
def is_agg_expr(obj: Any) -> TypeIs[expr.AggExpr]:
86+
return isinstance(obj, _expr().AggExpr)
87+
88+
89+
def is_aggregation(obj: Any) -> TypeIs[expr.AggExpr | expr.FunctionExpr[Any]]:
90+
"""Superset of `ExprIR.is_scalar`, excludes literals & len."""
91+
return is_agg_expr(obj) or (is_function_expr(obj) and obj.is_scalar)
92+
93+
94+
def is_literal(obj: Any) -> TypeIs[expr.Literal[Any]]:
95+
return isinstance(obj, _expr().Literal)
96+
97+
98+
def is_horizontal_reduction(obj: Any) -> TypeIs[expr.FunctionExpr[Any]]:
99+
return is_function_expr(obj) and obj.options.is_input_wildcard_expansion()
100+
101+
102+
def is_tuple_of(obj: Any, tp: type[T]) -> TypeIs[Seq[T]]:
103+
return bool(isinstance(obj, tuple) and obj and isinstance(obj[0], tp))

narwhals/_plan/arrow/namespace.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
import pyarrow.compute as pc # ignore-banned-import
88

99
from narwhals._arrow.utils import narwhals_to_native_dtype
10+
from narwhals._plan._guards import is_tuple_of
1011
from narwhals._plan.arrow import functions as fn
1112
from narwhals._plan.arrow.functions import lit
12-
from narwhals._plan.common import collect, is_tuple_of
13+
from narwhals._plan.common import collect
1314
from narwhals._plan.literal import is_literal_scalar
1415
from narwhals._plan.protocols import EagerNamespace
1516
from narwhals._utils import Version

narwhals/_plan/common.py

Lines changed: 6 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from operator import attrgetter
99
from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypeVar, cast, overload
1010

11+
from narwhals._plan._guards import is_function_expr, is_iterable_reject, is_literal
1112
from narwhals._plan._immutable import Immutable
1213
from narwhals._plan.options import ExprIROptions, FEOptions, FunctionOptions
1314
from narwhals._plan.typing import (
@@ -19,33 +20,22 @@
1920
IRNamespaceT,
2021
MapIR,
2122
NamedOrExprIRT,
22-
NativeSeriesT,
2323
NonNestedDTypeT,
2424
Seq,
2525
)
26-
from narwhals._utils import _hasattr_static
2726
from narwhals.dtypes import DType
2827
from narwhals.utils import Version
2928

3029
if TYPE_CHECKING:
3130
from collections.abc import Iterator
3231
from typing import Any, Callable
3332

34-
from typing_extensions import Self, TypeAlias, TypeIs
35-
36-
from narwhals._plan import expr
37-
from narwhals._plan.dummy import Expr, Selector, Series
38-
from narwhals._plan.expr import (
39-
AggExpr,
40-
Alias,
41-
BinaryExpr,
42-
Cast,
43-
Column,
44-
FunctionExpr,
45-
WindowExpr,
46-
)
33+
from typing_extensions import Self, TypeAlias
34+
35+
from narwhals._plan.dummy import Expr, Selector
36+
from narwhals._plan.expr import Alias, Cast, Column, FunctionExpr
4737
from narwhals._plan.meta import IRMetaNamespace
48-
from narwhals._plan.protocols import CompliantSeries, Ctx, FrameT_contra, R_co
38+
from narwhals._plan.protocols import Ctx, FrameT_contra, R_co
4939
from narwhals.typing import NonNestedDType, NonNestedLiteral
5040

5141

@@ -453,97 +443,6 @@ class HorizontalFunction(
453443
): ...
454444

455445

456-
_NON_NESTED_LITERAL_TPS = (
457-
int,
458-
float,
459-
str,
460-
dt.date,
461-
dt.time,
462-
dt.timedelta,
463-
bytes,
464-
Decimal,
465-
)
466-
467-
468-
def is_non_nested_literal(obj: Any) -> TypeIs[NonNestedLiteral]:
469-
return obj is None or isinstance(obj, _NON_NESTED_LITERAL_TPS)
470-
471-
472-
def is_expr(obj: Any) -> TypeIs[Expr]:
473-
from narwhals._plan.dummy import Expr
474-
475-
return isinstance(obj, Expr)
476-
477-
478-
def is_column(obj: Any) -> TypeIs[Expr]:
479-
"""Indicate if the given object is a basic/unaliased column.
480-
481-
https://github.com/pola-rs/polars/blob/a3d6a3a7863b4d42e720a05df69ff6b6f5fc551f/py-polars/polars/_utils/various.py#L164-L168.
482-
"""
483-
return is_expr(obj) and obj.meta.is_column()
484-
485-
486-
def is_series(obj: Series[NativeSeriesT] | Any) -> TypeIs[Series[NativeSeriesT]]:
487-
from narwhals._plan.dummy import Series
488-
489-
return isinstance(obj, Series)
490-
491-
492-
def is_compliant_series(
493-
obj: CompliantSeries[NativeSeriesT] | Any,
494-
) -> TypeIs[CompliantSeries[NativeSeriesT]]:
495-
return _hasattr_static(obj, "__narwhals_series__")
496-
497-
498-
def is_iterable_reject(obj: Any) -> TypeIs[str | bytes | Series | CompliantSeries]:
499-
from narwhals._plan.dummy import Series
500-
501-
return isinstance(obj, (str, bytes, Series)) or is_compliant_series(obj)
502-
503-
504-
def is_window_expr(obj: Any) -> TypeIs[WindowExpr]:
505-
from narwhals._plan.expr import WindowExpr
506-
507-
return isinstance(obj, WindowExpr)
508-
509-
510-
def is_function_expr(obj: Any) -> TypeIs[FunctionExpr[Any]]:
511-
from narwhals._plan.expr import FunctionExpr
512-
513-
return isinstance(obj, FunctionExpr)
514-
515-
516-
def is_binary_expr(obj: Any) -> TypeIs[BinaryExpr]:
517-
from narwhals._plan.expr import BinaryExpr
518-
519-
return isinstance(obj, BinaryExpr)
520-
521-
522-
def is_agg_expr(obj: Any) -> TypeIs[AggExpr]:
523-
from narwhals._plan.expr import AggExpr
524-
525-
return isinstance(obj, AggExpr)
526-
527-
528-
def is_aggregation(obj: Any) -> TypeIs[AggExpr | FunctionExpr[Any]]:
529-
"""Superset of `ExprIR.is_scalar`, excludes literals & len."""
530-
return is_agg_expr(obj) or (is_function_expr(obj) and obj.is_scalar)
531-
532-
533-
def is_literal(obj: Any) -> TypeIs[expr.Literal[Any]]:
534-
from narwhals._plan import expr
535-
536-
return isinstance(obj, expr.Literal)
537-
538-
539-
def is_horizontal_reduction(obj: FunctionExpr[Any] | Any) -> TypeIs[FunctionExpr[Any]]:
540-
return is_function_expr(obj) and obj.options.is_input_wildcard_expansion()
541-
542-
543-
def is_tuple_of(obj: Any, tp: type[T]) -> TypeIs[Seq[T]]:
544-
return bool(isinstance(obj, tuple) and obj and isinstance(obj[0], tp))
545-
546-
547446
def py_to_narwhals_dtype(obj: NonNestedLiteral, version: Version = Version.MAIN) -> DType:
548447
dtypes = version.dtypes
549448
mapping: dict[type[NonNestedLiteral], type[NonNestedDType]] = {

narwhals/_plan/demo.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,8 @@
33
import builtins
44
import typing as t
55

6-
from narwhals._plan import boolean, expr, expr_parsing as parse, functions as F
7-
from narwhals._plan.common import (
8-
into_dtype,
9-
is_non_nested_literal,
10-
is_series,
11-
py_to_narwhals_dtype,
12-
)
6+
from narwhals._plan import _guards, boolean, expr, expr_parsing as parse, functions as F
7+
from narwhals._plan.common import into_dtype, py_to_narwhals_dtype
138
from narwhals._plan.expr import All, Len
149
from narwhals._plan.literal import ScalarLiteral, SeriesLiteral
1510
from narwhals._plan.ranges import IntRange
@@ -39,9 +34,9 @@ def nth(*indices: int | t.Sequence[int]) -> Expr:
3934
def lit(
4035
value: NonNestedLiteral | Series[NativeSeriesT], dtype: IntoDType | None = None
4136
) -> Expr:
42-
if is_series(value):
37+
if _guards.is_series(value):
4338
return SeriesLiteral(value=value).to_literal().to_narwhals()
44-
if not is_non_nested_literal(value):
39+
if not _guards.is_non_nested_literal(value):
4540
msg = f"{type(value).__name__!r} is not supported in `nw.lit`, got: {value!r}."
4641
raise TypeError(msg)
4742
if dtype is None:

narwhals/_plan/dummy.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
functions as F,
1616
operators as ops,
1717
)
18-
from narwhals._plan.common import NamedIR, into_dtype, is_column, is_expr, is_series
18+
from narwhals._plan._guards import is_column, is_expr, is_series
19+
from narwhals._plan.common import NamedIR, into_dtype
1920
from narwhals._plan.contexts import ExprContext
2021
from narwhals._plan.options import (
2122
EWMOptions,

narwhals/_plan/expr_expansion.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@
4343
from typing import TYPE_CHECKING
4444

4545
from narwhals._plan import common, meta
46+
from narwhals._plan._guards import is_horizontal_reduction
4647
from narwhals._plan._immutable import Immutable
47-
from narwhals._plan.common import ExprIR, NamedIR, SelectorIR, is_horizontal_reduction
48+
from narwhals._plan.common import ExprIR, NamedIR, SelectorIR
4849
from narwhals._plan.exceptions import (
4950
column_index_error,
5051
column_not_found_error,

narwhals/_plan/expr_parsing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from itertools import chain
77
from typing import TYPE_CHECKING, TypeVar
88

9-
from narwhals._plan.common import is_expr, is_iterable_reject
9+
from narwhals._plan._guards import is_expr, is_iterable_reject
1010
from narwhals._plan.exceptions import (
1111
invalid_into_expr_error,
1212
is_iterable_pandas_error,

narwhals/_plan/expr_rewrites.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55
from typing import TYPE_CHECKING
66

77
from narwhals._plan import expr_parsing as parse
8-
from narwhals._plan.common import (
9-
NamedIR,
8+
from narwhals._plan._guards import (
109
is_aggregation,
1110
is_binary_expr,
1211
is_function_expr,
1312
is_window_expr,
14-
map_ir,
15-
replace,
1613
)
14+
from narwhals._plan.common import NamedIR, map_ir, replace
1715
from narwhals._plan.expr_expansion import into_named_irs, prepare_projection
1816

1917
if TYPE_CHECKING:

narwhals/_plan/literal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
from typing import TYPE_CHECKING, Any, Generic
44

5+
from narwhals._plan._guards import is_literal
56
from narwhals._plan._immutable import Immutable
6-
from narwhals._plan.common import is_literal
77
from narwhals._plan.typing import LiteralT, NativeSeriesT, NonNestedLiteralT
88

99
if TYPE_CHECKING:

narwhals/_plan/operators.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import operator as op
44
from typing import TYPE_CHECKING
55

6+
from narwhals._plan._guards import is_function_expr
67
from narwhals._plan._immutable import Immutable
7-
from narwhals._plan.common import is_function_expr
88
from narwhals._plan.exceptions import (
99
binary_expr_length_changing_error,
1010
binary_expr_multi_output_error,

0 commit comments

Comments
 (0)