from __future__ import annotations import ast import sys import re def transform_file(file_path: str) -> None: with open(file_path, "r", encoding="utf-8") as f: lines = f.read().splitlines() content = "\n".join(lines) tree = ast.parse(content) app_class = next((n for n in tree.body if isinstance(n, ast.ClassDef) and n.name == "App"), None) if not app_class: return render_methods = [ m for m in app_class.body if isinstance(m, ast.FunctionDef) and m.name.startswith("_render_") and m.name != "_render_window_if_open" ] render_names = {m.name for m in render_methods} render_methods.sort(key=lambda x: x.lineno, reverse=True) extracted = [] for m in render_methods: s_idx = m.lineno - 1 e_idx = m.end_lineno if m.decorator_list: s_idx = m.decorator_list[0].lineno - 1 m_lines = lines[s_idx:e_idx] func_name = m.name.lstrip("_") # 1. Out-dent processed = [l[1:] if l.startswith(" ") else l for l in m_lines] def_line_idx = next((i for i, l in enumerate(processed) if l.strip().startswith("def ")), -1) if def_line_idx != -1: l = processed[def_line_idx] l = l.replace(f"def {m.name}(", f"def {func_name}(", 1) l = re.sub(r"\bself\b", "app: App", l, count=1) processed[def_line_idx] = l # 2. Redirect internal calls in this function's body for i in range(def_line_idx + 1, len(processed)): for m_name in render_names: t_func = m_name.lstrip("_") processed[i] = processed[i].replace(f"self.{m_name}(", f"{t_func}(app, ") processed[i] = processed[i].replace("(app, )", "(app)") processed[i] = re.sub(r"(?