Skip to content

Commit 98292dc

Browse files
committed
exploring pl.Expr.meta
- Seems that the first step should be adding an iteration method on nodes for traversal - `polars` has some clearly defined rules over the order nodes should appear in
1 parent 0bada48 commit 98292dc

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed

narwhals/_plan/meta.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""`pl.Expr.meta` namespace functionality.
2+
3+
- It seems like there might be a need to distinguish the top-level nodes for iterating
4+
- polars_plan::dsl::expr::Expr
5+
- https://github.com/pola-rs/polars/blob/dafd0a2d0e32b52bcfa4273bffdd6071a0d5977a/crates/polars-plan/src/dsl/meta.rs#L11-L111
6+
- https://github.com/pola-rs/polars/blob/dafd0a2d0e32b52bcfa4273bffdd6071a0d5977a/crates/polars-plan/src/plans/iterator.rs#L10-L105
7+
"""
8+
9+
from __future__ import annotations
10+
11+
from typing import TYPE_CHECKING
12+
13+
if TYPE_CHECKING:
14+
from typing import Any
15+
16+
import polars as pl
17+
18+
from narwhals._plan.common import ExprIR
19+
20+
21+
class ExprIRMetaNamespace:
22+
"""Requires defining iterator behavior per node."""
23+
24+
def __init__(self, ir: ExprIR, /) -> None:
25+
self._ir: ExprIR = ir
26+
27+
def has_multiple_outputs(self) -> bool:
28+
raise NotImplementedError
29+
30+
def is_column(self) -> bool:
31+
"""Only one that doesn't require iter.
32+
33+
https://github.com/pola-rs/polars/blob/dafd0a2d0e32b52bcfa4273bffdd6071a0d5977a/crates/polars-plan/src/dsl/meta.rs#L65-L71
34+
"""
35+
from narwhals._plan.expr import Column
36+
37+
return isinstance(self._ir, Column)
38+
39+
def is_column_selection(self, *, allow_aliasing: bool = False) -> bool:
40+
raise NotImplementedError
41+
42+
def is_literal(self, *, allow_aliasing: bool = False) -> bool:
43+
raise NotImplementedError
44+
45+
def output_name(self, *, raise_if_undetermined: bool = True) -> str | None:
46+
"""https://github.com/pola-rs/polars/blob/dafd0a2d0e32b52bcfa4273bffdd6071a0d5977a/crates/polars-plan/src/utils.rs#L126-L127."""
47+
raise NotImplementedError
48+
49+
# NOTE: Less important for us, but maybe nice to have
50+
def pop(self) -> list[ExprIR]:
51+
raise NotImplementedError
52+
53+
def root_names(self) -> list[str]:
54+
raise NotImplementedError
55+
56+
def undo_aliases(self) -> ExprIR:
57+
raise NotImplementedError
58+
59+
# NOTE: We don't support `nw.col("*")` or other patterns in col
60+
# Maybe not relevant at all
61+
def is_regex_projection(self) -> bool:
62+
raise NotImplementedError
63+
64+
65+
def profile_polars_expr(expr: pl.Expr) -> dict[str, Any]:
66+
"""Gather all metadata for a native `Expr`.
67+
68+
Eventual goal would be that a `nw.Expr` matches a `pl.Expr` in as much of this as possible.
69+
"""
70+
return {
71+
"has_multiple_outputs": expr.meta.has_multiple_outputs(),
72+
"is_column": expr.meta.is_column(),
73+
"is_regex_projection": expr.meta.is_regex_projection(),
74+
"is_column_selection": expr.meta.is_column_selection(),
75+
"is_column_selection(allow_aliasing=True)": expr.meta.is_column_selection(
76+
allow_aliasing=True
77+
),
78+
"is_literal": expr.meta.is_literal(),
79+
"is_literal(allow_aliasing=True)": expr.meta.is_literal(allow_aliasing=True),
80+
"output_name": expr.meta.output_name(raise_if_undetermined=False),
81+
"root_names": expr.meta.root_names(),
82+
"pop": expr.meta.pop(),
83+
"undo_aliases": expr.meta.undo_aliases(),
84+
"expr": expr,
85+
}

0 commit comments

Comments
 (0)