77from __future__ import annotations
88
99from functools import lru_cache
10- from itertools import chain
1110from typing import TYPE_CHECKING , Literal , overload
1211
1312from narwhals ._plan import expressions as ir
1918from narwhals .utils import Version
2019
2120if TYPE_CHECKING :
22- from collections .abc import Iterable , Iterator
21+ from collections .abc import Iterator
2322
2423 from narwhals ._plan import Selector
2524
@@ -78,7 +77,7 @@ def output_name(self, *, raise_if_undetermined: bool = True) -> str | None:
7877
7978 def root_names (self ) -> list [str ]:
8079 """Get the root column names."""
81- return list (_expr_to_leaf_column_names_iter (self ._ir ))
80+ return list (iter_root_names (self ._ir ))
8281
8382 def as_selector (self ) -> Selector :
8483 """Try to turn this expression into a selector.
@@ -91,46 +90,17 @@ def as_selector(self) -> Selector:
9190 return self ._ir .to_selector_ir ().to_narwhals ()
9291
9392
94- def _expr_to_leaf_column_names_iter (expr : ir .ExprIR , / ) -> Iterator [str ]:
95- for e in _expr_to_leaf_column_exprs_iter (expr ):
96- result = _expr_to_leaf_column_name (e )
97- if isinstance (result , str ):
98- yield result
99-
100-
101- def _expr_to_leaf_column_exprs_iter (expr : ir .ExprIR , / ) -> Iterator [ir .ExprIR ]:
102- for outer in expr .iter_root_names ():
103- if isinstance (outer , ir .Column ):
104- yield outer
105-
106-
107- def _expr_to_leaf_column_name (expr : ir .ExprIR , / ) -> str | ComputeError :
108- leaves = list (_expr_to_leaf_column_exprs_iter (expr ))
109- if not len (leaves ) <= 1 :
110- msg = "found more than one root column name"
111- return ComputeError (msg )
112- if not leaves :
113- msg = "no root column name found"
114- return ComputeError (msg )
115- leaf = leaves [0 ]
116- if isinstance (leaf , ir .Column ):
117- return leaf .name
118- msg = f"Expected unreachable, got { type (leaf ).__name__ !r} \n \n { leaf } "
119- return ComputeError (msg )
93+ def iter_root_names (expr : ir .ExprIR , / ) -> Iterator [str ]:
94+ yield from (e .name for e in expr .iter_root_names () if isinstance (e , ir .Column ))
12095
12196
12297def root_name_first (expr : ir .ExprIR , / ) -> str :
123- it = _expr_to_leaf_column_names_iter (expr )
124- if name := next (it , None ):
98+ if name := next (iter_root_names (expr ), None ):
12599 return name
126- msg = "`name.keep_name` expected at least one column name"
100+ msg = f "`name.keep_name` expected at least one column name, got ` { expr !r } ` "
127101 raise InvalidOperationError (msg )
128102
129103
130- def root_names_unique (exprs : Iterable [ir .ExprIR ], / ) -> set [str ]:
131- return set (chain .from_iterable (_expr_to_leaf_column_names_iter (e ) for e in exprs ))
132-
133-
134104@lru_cache (maxsize = 32 )
135105def _expr_output_name (expr : ir .ExprIR , / ) -> str | ComputeError :
136106 for e in expr .iter_output_name ():
0 commit comments