This repository was archived by the owner on Mar 31, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 104
Expand file tree
/
Copy pathgenerate.py
More file actions
112 lines (94 loc) · 3.95 KB
/
generate.py
File metadata and controls
112 lines (94 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from typing import Sequence
import ast
"""
Entrypoint for initiating an async -> sync conversion using CrossSync
Finds all python files rooted in a given directory, and uses
transformers.CrossSyncFileProcessor to handle any files marked with
__CROSS_SYNC_OUTPUT__
"""
def extract_header_comments(file_path) -> str:
"""
Extract the file header. Header is defined as the top-level
comments before any code or imports
"""
header = []
with open(file_path, "r", encoding="utf-8-sig") as f:
for line in f:
if line.startswith("#") or line.strip() == "":
header.append(line)
else:
break
header.append("\n# This file is automatically generated by CrossSync. Do not edit manually.\n\n")
return "".join(header)
class CrossSyncOutputFile:
def __init__(self, output_path: str, ast_tree, header: str | None = None):
self.output_path = output_path
self.tree = ast_tree
self.header = header or ""
def render(self, with_formatter=True, save_to_disk: bool = True) -> str:
"""
Render the file to a string, and optionally save to disk
Args:
with_formatter: whether to run the output through black before returning
save_to_disk: whether to write the output to the file path
"""
full_str = self.header + ast.unparse(self.tree)
if with_formatter:
import black # type: ignore
import autoflake # type: ignore
full_str = black.format_str(
autoflake.fix_code(full_str, remove_all_unused_imports=True),
mode=black.FileMode(),
)
if save_to_disk:
import os
os.makedirs(os.path.dirname(self.output_path), exist_ok=True)
with open(self.output_path, "w") as f:
f.write(full_str)
return full_str
def convert_files_in_dir(directory: str) -> set[CrossSyncOutputFile]:
import glob
from transformers import CrossSyncFileProcessor
# find all python files in the directory
files = glob.glob(directory + "/**/*.py", recursive=True)
# keep track of the output files pointed to by the annotated classes
artifacts: set[CrossSyncOutputFile] = set()
file_transformer = CrossSyncFileProcessor()
# run each file through ast transformation to find all annotated classes
for file_path in files:
with open(file_path, encoding="utf-8-sig") as f:
ast_tree = ast.parse(f.read())
output_path = file_transformer.get_output_path(ast_tree)
if output_path is not None:
# contains __CROSS_SYNC_OUTPUT__ annotation
converted_tree = file_transformer.visit(ast_tree)
header = extract_header_comments(file_path)
artifacts.add(CrossSyncOutputFile(output_path, converted_tree, header))
# return set of output artifacts
return artifacts
def save_artifacts(artifacts: Sequence[CrossSyncOutputFile]):
for a in artifacts:
a.render(save_to_disk=True)
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python .cross_sync/generate.py <directory>")
sys.exit(1)
search_root = sys.argv[1]
outputs = convert_files_in_dir(search_root)
print(f"Generated {len(outputs)} artifacts: {[a.output_path for a in outputs]}")
save_artifacts(outputs)