Skip to content

Commit cc3288e

Browse files
committed
checkpoint: impl operator definition gen
1 parent b7e5a06 commit cc3288e

6 files changed

Lines changed: 262 additions & 62 deletions

File tree

packages/bigframes/scripts/generate_bigframes_bigquery/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,18 @@
2222
# See the License for the specific language governing permissions and
2323
# limitations under the License.
2424

25-
import pprint
2625

2726
import constants
28-
import yaml_parser
2927
import file_generator
28+
import yaml_parser
3029

3130

3231
def main():
3332
modules = []
3433

3534
for yaml_file in sorted(constants.DATA_DIR.glob("**/*.yaml")):
3635
modules.append(yaml_parser.parse_yaml(yaml_file))
36+
break
3737

3838
file_generator.generate(modules)
3939

packages/bigframes/scripts/generate_bigframes_bigquery/constants.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
# limitations under the License.
1414

1515
import pathlib
16+
1617
import jinja2
1718

1819
SCRIPTS_DIRECTORY = pathlib.Path(__file__).parent.parent.absolute()
1920
PACKAGE_ROOT = SCRIPTS_DIRECTORY.parent
2021
CODE_ROOT = PACKAGE_ROOT / "bigframes"
21-
SCRIPT_PATH_RELATIVE = pathlib.Path(__file__).relative_to(PACKAGE_ROOT)
22+
SCRIPT_PATH_RELATIVE = pathlib.Path(__file__).relative_to(PACKAGE_ROOT).parent
2223

2324
# Directory containing the YAML files
2425
DATA_DIR = SCRIPTS_DIRECTORY / "data" / "sql-functions"
@@ -119,6 +120,59 @@
119120
"decimal<76,38>": "dtypes.BIGNUMERIC_DTYPE",
120121
}
121122

123+
YAML_TYPE_TO_COL = {
124+
"binary": "bytes_col",
125+
"string": "string_col",
126+
"int64": "int64_col",
127+
"i64": "int64_col",
128+
"float64": "float64_col",
129+
"fp64": "float64_col",
130+
"bool": "bool_col",
131+
"boolean": "bool_col",
132+
"geography": "geography_col",
133+
"date": "date_col",
134+
"time": "time_col",
135+
"datetime": "datetime_col",
136+
"timestamp": "timestamp_col",
137+
"decimal<38,9>": "numeric_col",
138+
"decimal<76,38>": "bignumeric_col",
139+
}
140+
141+
PY_TYPE_MAP = {
142+
"binary": "bytes",
143+
"string": "str",
144+
"int64": "int",
145+
"i64": "int",
146+
"float64": "float",
147+
"fp64": "float",
148+
"bool": "bool",
149+
"boolean": "bool",
150+
"geography": "Any",
151+
"json": "Any",
152+
"date": "datetime.date",
153+
"time": "datetime.time",
154+
"datetime": "datetime.datetime",
155+
"timestamp": "datetime.datetime",
156+
"struct": "dict",
157+
"decimal<38,9>": "decimal.Decimal",
158+
"decimal<76,38>": "decimal.Decimal",
159+
"interval_day": "datetime.timedelta",
160+
}
161+
162+
RUFF_COMMON_ARGS = [
163+
"--target-version=py310",
164+
"--line-length=88",
165+
]
166+
RUFF_CHECK_ARGS = [
167+
"check",
168+
"--select",
169+
"I,F",
170+
"--fix",
171+
] + RUFF_COMMON_ARGS
172+
RUFF_FORMAT_ARGS = [
173+
"format",
174+
] + RUFF_COMMON_ARGS
175+
122176

123177
TEMPLATES: dict[str, jinja2.Template] # Lazily-loaded global variable
124178
_templates = None

packages/bigframes/scripts/generate_bigframes_bigquery/data_models.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515

1616
import dataclasses
1717
import pathlib
18+
from typing import Any
1819

1920
import constants
20-
from typing import Any
2121

2222

2323
@dataclasses.dataclass
@@ -28,6 +28,14 @@ class BQFuncArg:
2828
keyword_only: bool
2929

3030

31+
@dataclasses.dataclass
32+
class BigFramesFuncArg:
33+
name: str
34+
types: set[str]
35+
optional: bool
36+
keyword_only: bool
37+
38+
3139
@dataclasses.dataclass
3240
class BQFuncImpl:
3341
args: list[BQFuncArg]
@@ -56,26 +64,19 @@ def to_dict(self) -> dict[str, Any]:
5664
@dataclasses.dataclass
5765
class BQFunc:
5866
name: str
67+
op_base_name: str
5968
description: str
6069
impls: list[BQFuncImpl]
6170

6271

6372
@dataclasses.dataclass
6473
class BQModule:
65-
module_path: pathlib.Path
74+
yaml_file: pathlib.Path
6675
functions: list[BQFunc]
6776

6877
@property
69-
def name(self) -> str:
70-
return self.module_path.name
71-
72-
@property
73-
def is_global_namespace(self) -> bool:
74-
return "global_namespace" in self.module_path.parts
75-
76-
@property
77-
def output_file(self):
78-
return constants.OUTPUT_DIR.joinpath(self.module_path).with_suffix(".py")
78+
def module_path(self):
79+
return self.yaml_file.relative_to(constants.DATA_DIR).with_suffix("")
7980

8081

8182
@dataclasses.dataclass
@@ -84,12 +85,13 @@ class BigFramesOp:
8485
sql_name: str
8586
arg_specs: str
8687
signature: str
87-
signature_definition: str
88+
signature_definition: str | None
8889

8990

9091
@dataclasses.dataclass
9192
class BigFramesFunc:
9293
name: str
94+
op_name: str
9395
description: str
9496
args: list[str]
9597
series_accessor_arg: list[str]

packages/bigframes/scripts/generate_bigframes_bigquery/file_generator.py

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,76 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import pathlib
16+
import sys
17+
import subprocess
18+
1519
import constants
16-
import jinja2
1720
import data_models
18-
import pprint
19-
2021
import template_renderer
2122

2223

23-
def _generate_sql_operator_def():
24-
pass
24+
def _ensure_init_py(directory: pathlib.Path, limit_dir: pathlib.Path):
25+
"""Ensures __init__.py exists in the directory and its parents up to limit_dir."""
26+
curr = directory
27+
while curr != limit_dir and curr != curr.parent:
28+
init_file = curr / "__init__.py"
29+
if not init_file.exists():
30+
print(f" Creating {init_file}")
31+
content = constants.TEMPLATES["license"].render()
32+
with open(init_file, "w") as f:
33+
f.write(content)
34+
curr = curr.parent
35+
36+
37+
def _write_file(content: str, output_file: pathlib.Path, limit_dir: pathlib.Path):
38+
output_file.parent.mkdir(parents=True, exist_ok=True)
39+
_ensure_init_py(output_file.parent, limit_dir)
40+
41+
with open(output_file, "w") as f:
42+
f.write(content)
43+
print(f" Generated {output_file}")
44+
45+
46+
def _run_ruff():
47+
targets = [
48+
constants.OUTPUT_DIR,
49+
constants.TEST_OUTPUT_DIR,
50+
]
51+
52+
subprocess.run(
53+
[sys.executable, "-m", "ruff"] + constants.RUFF_CHECK_ARGS + targets,
54+
check=True,
55+
)
56+
57+
subprocess.run(
58+
[sys.executable, "-m", "ruff"] + constants.RUFF_FORMAT_ARGS + targets,
59+
check=True,
60+
)
61+
62+
63+
def _generate_op_defs(bq_module: data_models.BQModule):
64+
content = template_renderer.render_operation(bq_module)
65+
66+
output_file = constants.OUTPUT_DIR.joinpath(bq_module.module_path).with_suffix(
67+
".py"
68+
)
69+
70+
_write_file(content, output_file, constants.OUTPUT_DIR.parent)
2571

2672

2773
def _generate_accesor():
2874
pass
2975

3076

31-
def _generate_tests():
77+
def _generate_tests(bq_module: data_models.BQModule):
3278
pass
3379

3480

3581
def generate(bq_modules: list[data_models.BQModule]):
3682

3783
for bq_module in bq_modules:
38-
for bq_func in bq_module.functions:
39-
pprint.pp(template_renderer.render_signature_def(bq_func, bq_module))
40-
41-
# Write to file
84+
_generate_op_defs(bq_module)
4285

4386
# Ruff format
44-
pass
87+
_run_ruff()

0 commit comments

Comments
 (0)