Skip to content

Commit 9b46e00

Browse files
Copilotpwwang
andauthored
Add environment variables to control verb AST fallback behavior (#219)
Co-authored-by: pwwang <[email protected]> Co-authored-by: copilot-swe-agent[bot] <[email protected]>
1 parent 876afac commit 9b46e00

File tree

10 files changed

+527
-106
lines changed

10 files changed

+527
-106
lines changed

datar/apis/dplyr.py

Lines changed: 88 additions & 77 deletions
Large diffs are not rendered by default.

datar/apis/tibble.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
register_verb as _register_verb,
66
register_func as _register_func,
77
)
8+
from ..core.verb_env import get_verb_ast_fallback as _get_verb_ast_fallback
89

910
from ..core.utils import (
1011
NotImplementedByCurrentBackendError as _NotImplementedByCurrentBackendError,
@@ -112,13 +113,13 @@ def tibble_row(
112113
raise _NotImplementedByCurrentBackendError("tibble_row")
113114

114115

115-
@_register_verb()
116+
@_register_verb(ast_fallback=_get_verb_ast_fallback("as_tibble"))
116117
def as_tibble(df) -> Any:
117118
"""Convert a DataFrame object to Tibble object"""
118119
raise _NotImplementedByCurrentBackendError("as_tibble", df)
119120

120121

121-
@_register_verb()
122+
@_register_verb(ast_fallback=_get_verb_ast_fallback("enframe"))
122123
def enframe(x, name="name", value="value") -> Any:
123124
"""Converts mappings or lists to one- or two-column data frames.
124125
@@ -136,7 +137,7 @@ def enframe(x, name="name", value="value") -> Any:
136137
raise _NotImplementedByCurrentBackendError("enframe", x)
137138

138139

139-
@_register_verb()
140+
@_register_verb(ast_fallback=_get_verb_ast_fallback("deframe"))
140141
def deframe(x) -> Any:
141142
"""Converts two-column data frames to a dictionary
142143
using the first column as name and the second column as value.
@@ -151,7 +152,7 @@ def deframe(x) -> Any:
151152
raise _NotImplementedByCurrentBackendError("deframe", x)
152153

153154

154-
@_register_verb()
155+
@_register_verb(ast_fallback=_get_verb_ast_fallback("add_row"))
155156
def add_row(
156157
_data,
157158
*args,
@@ -178,7 +179,7 @@ def add_row(
178179
raise _NotImplementedByCurrentBackendError("add_row", _data)
179180

180181

181-
@_register_verb()
182+
@_register_verb(ast_fallback=_get_verb_ast_fallback("add_column"))
182183
def add_column(
183184
_data,
184185
*args,
@@ -206,7 +207,7 @@ def add_column(
206207
raise _NotImplementedByCurrentBackendError("add_column", _data)
207208

208209

209-
@_register_verb()
210+
@_register_verb(ast_fallback=_get_verb_ast_fallback("has_rownames"))
210211
def has_rownames(_data) -> bool:
211212
"""Detect if a data frame has row names
212213
@@ -222,7 +223,7 @@ def has_rownames(_data) -> bool:
222223
raise _NotImplementedByCurrentBackendError("has_rownames", _data)
223224

224225

225-
@_register_verb()
226+
@_register_verb(ast_fallback=_get_verb_ast_fallback("remove_rownames"))
226227
def remove_rownames(_data) -> Any:
227228
"""Remove the index/rownames of a data frame
228229
@@ -238,7 +239,7 @@ def remove_rownames(_data) -> Any:
238239
raise _NotImplementedByCurrentBackendError("remove_rownames", _data)
239240

240241

241-
@_register_verb()
242+
@_register_verb(ast_fallback=_get_verb_ast_fallback("rownames_to_column"))
242243
def rownames_to_column(_data, var="rowname") -> Any:
243244
"""Add rownames as a column
244245
@@ -255,7 +256,7 @@ def rownames_to_column(_data, var="rowname") -> Any:
255256
raise _NotImplementedByCurrentBackendError("rownames_to_column", _data)
256257

257258

258-
@_register_verb()
259+
@_register_verb(ast_fallback=_get_verb_ast_fallback("rowid_to_column"))
259260
def rowid_to_column(_data, var="rowid") -> Any:
260261
"""Add rownames as a column
261262
@@ -270,7 +271,7 @@ def rowid_to_column(_data, var="rowid") -> Any:
270271
raise _NotImplementedByCurrentBackendError("rowid_to_column", _data)
271272

272273

273-
@_register_verb()
274+
@_register_verb(ast_fallback=_get_verb_ast_fallback("column_to_rownames"))
274275
def column_to_rownames(_data, var="rowname") -> Any:
275276
"""Set rownames/index with one column, and remove it
276277

datar/apis/tidyr.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
register_verb as _register_verb,
66
register_func as _register_func,
77
)
8+
from ..core.verb_env import get_verb_ast_fallback as _get_verb_ast_fallback
89

910
from ..core.utils import (
1011
NotImplementedByCurrentBackendError as _NotImplementedByCurrentBackendError,
@@ -28,7 +29,7 @@ def full_seq(x, period, tol=1e-6) -> Any:
2829
raise _NotImplementedByCurrentBackendError("full_seq", x)
2930

3031

31-
@_register_verb()
32+
@_register_verb(ast_fallback=_get_verb_ast_fallback("chop"))
3233
def chop(
3334
data,
3435
cols=None,
@@ -46,7 +47,7 @@ def chop(
4647
raise _NotImplementedByCurrentBackendError("chop", data)
4748

4849

49-
@_register_verb()
50+
@_register_verb(ast_fallback=_get_verb_ast_fallback("unchop"))
5051
def unchop(
5152
data,
5253
cols=None,
@@ -89,7 +90,7 @@ def unchop(
8990
raise _NotImplementedByCurrentBackendError("unchop", data)
9091

9192

92-
@_register_verb()
93+
@_register_verb(ast_fallback=_get_verb_ast_fallback("nest"))
9394
def nest(
9495
_data,
9596
_names_sep: str = None,
@@ -113,7 +114,7 @@ def nest(
113114
raise _NotImplementedByCurrentBackendError("nest", _data)
114115

115116

116-
@_register_verb()
117+
@_register_verb(ast_fallback=_get_verb_ast_fallback("unnest"))
117118
def unnest(
118119
data,
119120
*cols: str | int,
@@ -158,7 +159,7 @@ def unnest(
158159
raise _NotImplementedByCurrentBackendError("unnest", data)
159160

160161

161-
@_register_verb()
162+
@_register_verb(ast_fallback=_get_verb_ast_fallback("pack"))
162163
def pack(
163164
_data,
164165
_names_sep: str = None,
@@ -179,7 +180,7 @@ def pack(
179180
raise _NotImplementedByCurrentBackendError("pack", _data)
180181

181182

182-
@_register_verb()
183+
@_register_verb(ast_fallback=_get_verb_ast_fallback("unpack"))
183184
def unpack(
184185
data,
185186
cols,
@@ -213,7 +214,7 @@ def unpack(
213214
raise _NotImplementedByCurrentBackendError("unpack", data)
214215

215216

216-
@_register_verb()
217+
@_register_verb(ast_fallback=_get_verb_ast_fallback("expand"))
217218
def expand(
218219
data,
219220
*args,
@@ -319,7 +320,7 @@ def crossing(
319320
raise _NotImplementedByCurrentBackendError("crossing")
320321

321322

322-
@_register_verb()
323+
@_register_verb(ast_fallback=_get_verb_ast_fallback("complete"))
323324
def complete(
324325
data,
325326
*args,
@@ -353,7 +354,7 @@ def complete(
353354
raise _NotImplementedByCurrentBackendError("complete", data)
354355

355356

356-
@_register_verb()
357+
@_register_verb(ast_fallback=_get_verb_ast_fallback("drop_na"))
357358
def drop_na(
358359
_data,
359360
*columns: str,
@@ -377,7 +378,7 @@ def drop_na(
377378
raise _NotImplementedByCurrentBackendError("drop_na", _data)
378379

379380

380-
@_register_verb()
381+
@_register_verb(ast_fallback=_get_verb_ast_fallback("extract"))
381382
def extract(
382383
data,
383384
col: str | int,
@@ -409,7 +410,7 @@ def extract(
409410
raise _NotImplementedByCurrentBackendError("extract", data)
410411

411412

412-
@_register_verb()
413+
@_register_verb(ast_fallback=_get_verb_ast_fallback("fill"))
413414
def fill(
414415
_data,
415416
*columns: str | int,
@@ -434,7 +435,7 @@ def fill(
434435
raise _NotImplementedByCurrentBackendError("fill", _data)
435436

436437

437-
@_register_verb()
438+
@_register_verb(ast_fallback=_get_verb_ast_fallback("pivot_longer"))
438439
def pivot_longer(
439440
_data,
440441
cols,
@@ -540,7 +541,7 @@ def pivot_longer(
540541
raise _NotImplementedByCurrentBackendError("pivot_longer", _data)
541542

542543

543-
@_register_verb()
544+
@_register_verb(ast_fallback=_get_verb_ast_fallback("pivot_wider"))
544545
def pivot_wider(
545546
_data,
546547
id_cols=None,
@@ -593,7 +594,7 @@ def pivot_wider(
593594
raise _NotImplementedByCurrentBackendError("pivot_wider", _data)
594595

595596

596-
@_register_verb()
597+
@_register_verb(ast_fallback=_get_verb_ast_fallback("separate"))
597598
def separate(
598599
data,
599600
col: int | str,
@@ -640,7 +641,7 @@ def separate(
640641
raise _NotImplementedByCurrentBackendError("separate", data)
641642

642643

643-
@_register_verb()
644+
@_register_verb(ast_fallback=_get_verb_ast_fallback("separate_rows"))
644645
def separate_rows(
645646
data,
646647
*columns: str,
@@ -662,7 +663,7 @@ def separate_rows(
662663
raise _NotImplementedByCurrentBackendError("separate_rows", data)
663664

664665

665-
@_register_verb()
666+
@_register_verb(ast_fallback=_get_verb_ast_fallback("uncount"))
666667
def uncount(
667668
data,
668669
weights,
@@ -685,7 +686,7 @@ def uncount(
685686
raise _NotImplementedByCurrentBackendError("uncount", data)
686687

687688

688-
@_register_verb()
689+
@_register_verb(ast_fallback=_get_verb_ast_fallback("unite"))
689690
def unite(
690691
data,
691692
col: str,
@@ -711,7 +712,7 @@ def unite(
711712
raise _NotImplementedByCurrentBackendError("unite", data)
712713

713714

714-
@_register_verb()
715+
@_register_verb(ast_fallback=_get_verb_ast_fallback("replace_na"))
715716
def replace_na(
716717
data,
717718
data_or_replace=None,

datar/core/verb_env.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Utilities for getting verb AST fallback from environment variables"""
2+
from __future__ import annotations
3+
4+
import os
5+
6+
7+
def get_verb_ast_fallback(verb: str) -> str | None:
8+
"""Get ast_fallback value from environment variables.
9+
10+
Checks for per-verb environment variable first, then falls back to global.
11+
12+
Args:
13+
verb: The name of the verb (e.g., "mutate", "select", "filter")
14+
15+
Returns:
16+
The ast_fallback value from environment variables, or None if not set
17+
18+
Example:
19+
>>> @register_verb(ast_fallback=get_verb_ast_fallback("mutate"))
20+
>>> def mutate(...):
21+
... pass
22+
"""
23+
# Convert verb name to uppercase, removing trailing underscore if present
24+
# e.g., "select" -> "SELECT", "filter_" -> "FILTER"
25+
verb_name = verb.rstrip("_").upper()
26+
27+
# Check for per-verb environment variable first
28+
# e.g., DATAR_MUTATE_AST_FALLBACK
29+
per_verb_key = f"DATAR_{verb_name}_AST_FALLBACK"
30+
per_verb_value = os.environ.get(per_verb_key)
31+
if per_verb_value:
32+
return per_verb_value
33+
34+
# Fall back to global environment variable
35+
global_key = "DATAR_VERB_AST_FALLBACK"
36+
global_value = os.environ.get(global_key)
37+
if global_value:
38+
return global_value
39+
40+
return None

datar/misc.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from typing import Any as _Any, Callable as _Callable
22

33
from pipda import register_verb as _register_verb
4+
from .core.verb_env import get_verb_ast_fallback as _get_verb_ast_fallback
45

56
from .core.load_plugins import plugin as _plugin
67

78
locals().update(_plugin.hooks.misc_api())
89

910

10-
@_register_verb(object)
11+
@_register_verb(object, ast_fallback=_get_verb_ast_fallback("pipe"))
1112
def pipe(data: _Any, func: _Callable, *args, **kwargs) -> _Any:
1213
"""Apply a function to the data
1314

0 commit comments

Comments
 (0)