93 lines
2.8 KiB
Python
93 lines
2.8 KiB
Python
from __future__ import annotations
|
|
import ast
|
|
import sys
|
|
import os
|
|
import re
|
|
|
|
def transform_file(file_path: str) -> None:
|
|
"""
|
|
Refactors App._render_xxx methods to module-level functions for hot-reloading.
|
|
Now correctly renames 'self' to 'app' inside function bodies.
|
|
"""
|
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
content = f.read()
|
|
tree = ast.parse(content)
|
|
|
|
class VariableRenamer(ast.NodeTransformer):
|
|
def visit_Name(self, node: ast.Name) -> ast.Name:
|
|
if node.id == "self":
|
|
node.id = "app"
|
|
return node
|
|
|
|
class RenderTransformer(ast.NodeTransformer):
|
|
def __init__(self):
|
|
self.new_functions = []
|
|
def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef:
|
|
if node.name != "App": return node
|
|
new_body = []
|
|
for item in node.body:
|
|
if isinstance(item, ast.FunctionDef) and item.name.startswith("_render_") and item.name != "_render_window_if_open":
|
|
func_name = item.name.lstrip("_")
|
|
# Transform body: rename 'self' to 'app'
|
|
renamer = VariableRenamer()
|
|
new_body_nodes = [renamer.visit(b) for b in item.body]
|
|
|
|
new_func = ast.FunctionDef(
|
|
name=func_name,
|
|
args=item.args,
|
|
body=new_body_nodes,
|
|
decorator_list=item.decorator_list,
|
|
returns=item.returns
|
|
)
|
|
if new_func.args.args and new_func.args.args[0].arg == "self":
|
|
new_func.args.args[0].arg = "app"
|
|
self.new_functions.append(new_func)
|
|
|
|
# Create delegation wrapper in class
|
|
wrapper_body = [
|
|
ast.Expr(
|
|
value=ast.Call(
|
|
func=ast.Name(id=func_name, ctx=ast.Load()),
|
|
args=[ast.Name(id="self", ctx=ast.Load())] + [ast.Name(id=a.arg, ctx=ast.Load()) for a in item.args.args[1:]],
|
|
keywords=[ast.keyword(arg=kw.arg, value=ast.Name(id=kw.arg, ctx=ast.Load())) for kw in item.args.kwonlyargs]
|
|
)
|
|
)
|
|
]
|
|
item.body = wrapper_body
|
|
new_body.append(item)
|
|
else:
|
|
new_body.append(item)
|
|
node.body = new_body
|
|
return node
|
|
|
|
transformer = RenderTransformer()
|
|
new_tree = transformer.visit(tree)
|
|
for func in transformer.new_functions:
|
|
new_tree.body.append(func)
|
|
ast.fix_missing_locations(new_tree)
|
|
|
|
if hasattr(ast, "unparse"):
|
|
raw_output = ast.unparse(new_tree)
|
|
lines = raw_output.splitlines()
|
|
new_lines = []
|
|
for line in lines:
|
|
match = re.match(r"^( +)(.*)", line)
|
|
if match:
|
|
spaces, rest = match.groups()
|
|
new_indent = " " * (len(spaces) // 4)
|
|
new_lines.append(new_indent + rest)
|
|
else:
|
|
new_lines.append(line)
|
|
final_content = "\n".join(new_lines)
|
|
with open(file_path, "w", encoding="utf-8") as f:
|
|
f.write(final_content)
|
|
print(f"Successfully transformed {file_path} with 1-space indentation and 'self'->'app' migration.")
|
|
else:
|
|
print("ast.unparse not available.")
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) < 2:
|
|
print("Usage: python scripts/transform_render_methods.py <file_path>")
|
|
else:
|
|
transform_file(sys.argv[1])
|