|
12 | 12 | from narwhals._plan.expressions.ranges import DateRange, IntRange |
13 | 13 | from narwhals._plan.expressions.strings import ConcatStr |
14 | 14 | from narwhals._plan.when_then import When |
15 | | -from narwhals._utils import Version, flatten |
16 | | -from narwhals.exceptions import ComputeError |
| 15 | +from narwhals._utils import Implementation, Version, flatten, is_eager_allowed |
| 16 | +from narwhals.exceptions import ComputeError, InvalidOperationError |
17 | 17 |
|
18 | 18 | if TYPE_CHECKING: |
| 19 | + import pyarrow as pa |
| 20 | + |
| 21 | + from narwhals._plan import arrow as _arrow |
| 22 | + from narwhals._plan.compliant.namespace import EagerNamespace |
| 23 | + from narwhals._plan.compliant.series import CompliantSeries |
19 | 24 | from narwhals._plan.expr import Expr |
20 | 25 | from narwhals._plan.series import Series |
21 | 26 | from narwhals._plan.typing import IntoExpr, IntoExprColumn, NativeSeriesT |
| 27 | + from narwhals._typing import Arrow |
22 | 28 | from narwhals.dtypes import IntegerType |
23 | | - from narwhals.typing import ClosedInterval, IntoDType, NonNestedLiteral |
| 29 | + from narwhals.typing import ( |
| 30 | + ClosedInterval, |
| 31 | + EagerAllowed, |
| 32 | + IntoBackend, |
| 33 | + IntoDType, |
| 34 | + NonNestedLiteral, |
| 35 | + ) |
24 | 36 |
|
25 | 37 |
|
26 | 38 | def col(*names: str | t.Iterable[str]) -> Expr: |
@@ -145,27 +157,94 @@ def when( |
145 | 157 | return When._from_ir(condition) |
146 | 158 |
|
147 | 159 |
|
| 160 | +@t.overload |
| 161 | +def int_range( |
| 162 | + start: int | IntoExprColumn = ..., |
| 163 | + end: int | IntoExprColumn | None = ..., |
| 164 | + step: int = ..., |
| 165 | + *, |
| 166 | + dtype: IntegerType | type[IntegerType] = ..., |
| 167 | + eager: t.Literal[False] = ..., |
| 168 | +) -> Expr: ... |
| 169 | +@t.overload |
| 170 | +def int_range( |
| 171 | + start: int = ..., |
| 172 | + end: int | None = ..., |
| 173 | + step: int = ..., |
| 174 | + *, |
| 175 | + dtype: IntegerType | type[IntegerType] = ..., |
| 176 | + eager: Arrow, |
| 177 | +) -> Series[pa.ChunkedArray[t.Any]]: ... |
| 178 | +@t.overload |
| 179 | +def int_range( |
| 180 | + start: int = ..., |
| 181 | + end: int | None = ..., |
| 182 | + step: int = ..., |
| 183 | + *, |
| 184 | + dtype: IntegerType | type[IntegerType] = ..., |
| 185 | + eager: IntoBackend[EagerAllowed], |
| 186 | +) -> Series: ... |
148 | 187 | def int_range( |
149 | 188 | start: int | IntoExprColumn = 0, |
150 | 189 | end: int | IntoExprColumn | None = None, |
151 | 190 | step: int = 1, |
152 | 191 | *, |
153 | 192 | dtype: IntegerType | type[IntegerType] = Version.MAIN.dtypes.Int64, |
154 | | - eager: bool = False, |
155 | | -) -> Expr: |
| 193 | + eager: IntoBackend[EagerAllowed] | t.Literal[False] = False, |
| 194 | +) -> Expr | Series: |
156 | 195 | if end is None: |
157 | 196 | end = start |
158 | 197 | start = 0 |
| 198 | + dtype = common.into_dtype(dtype) |
159 | 199 | if eager: |
160 | | - msg = f"{eager=}" |
161 | | - raise NotImplementedError(msg) |
| 200 | + return _int_range_eager(start, end, step, dtype=dtype, ns=_eager_namespace(eager)) |
162 | 201 | return ( |
163 | | - IntRange(step=step, dtype=common.into_dtype(dtype)) |
| 202 | + IntRange(step=step, dtype=dtype) |
164 | 203 | .to_function_expr(*_parse.parse_into_seq_of_expr_ir(start, end)) |
165 | 204 | .to_narwhals() |
166 | 205 | ) |
167 | 206 |
|
168 | 207 |
|
| 208 | +def _int_range_eager( |
| 209 | + start: t.Any, |
| 210 | + end: t.Any, |
| 211 | + step: int, |
| 212 | + *, |
| 213 | + dtype: IntegerType, |
| 214 | + ns: EagerNamespace[t.Any, CompliantSeries[NativeSeriesT], t.Any, t.Any], |
| 215 | +) -> Series[NativeSeriesT]: |
| 216 | + if not (isinstance(start, int) and isinstance(end, int)): |
| 217 | + msg = ( |
| 218 | + f"Expected `start` and `end` to be integer values since `eager={ns.implementation}`.\n" |
| 219 | + f"Found: `start` of type {type(start)} and `end` of type {type(end)}\n\n" |
| 220 | + "Hint: Calling `nw.int_range` with expressions requires:\n" |
| 221 | + " - `eager=False`" |
| 222 | + " - a context such as `select` or `with_columns`" |
| 223 | + ) |
| 224 | + raise InvalidOperationError(msg) |
| 225 | + return ns.int_range_eager(start, end, step, dtype=dtype).to_narwhals() |
| 226 | + |
| 227 | + |
| 228 | +@t.overload |
| 229 | +def _eager_namespace(backend: Arrow, /) -> _arrow.Namespace: ... |
| 230 | +@t.overload |
| 231 | +def _eager_namespace( |
| 232 | + backend: IntoBackend[EagerAllowed], / |
| 233 | +) -> EagerNamespace[t.Any, t.Any, t.Any, t.Any]: ... |
| 234 | +def _eager_namespace( |
| 235 | + backend: IntoBackend[EagerAllowed], / |
| 236 | +) -> EagerNamespace[t.Any, t.Any, t.Any, t.Any] | _arrow.Namespace: |
| 237 | + impl = Implementation.from_backend(backend) |
| 238 | + if is_eager_allowed(impl): |
| 239 | + if impl is Implementation.PYARROW: |
| 240 | + from narwhals._plan.arrow.namespace import ArrowNamespace |
| 241 | + |
| 242 | + return ArrowNamespace(Version.MAIN) |
| 243 | + raise NotImplementedError(impl) |
| 244 | + msg = f"{impl} support in Narwhals is lazy-only" |
| 245 | + raise ValueError(msg) |
| 246 | + |
| 247 | + |
169 | 248 | def date_range( |
170 | 249 | start: dt.date | IntoExprColumn, |
171 | 250 | end: dt.date | IntoExprColumn, |
|
0 commit comments