Coverage for src / renaissance / recipes / python_refactoring.py: 98%
44 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-09-09 14:04 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-09-09 14:04 +0000
1import importlib
2from collections.abc import Sequence
3from pathlib import Path
4from typing import cast
6from termcolor import colored
8from renaissance.integrations.python.ast.factory import PythonFactory, PythonPatternFactory
9from renaissance.integrations.python.ast.rst_node import PythonRstNode
10from renaissance.integrations.python.ast.util import to_str
11from renaissance.syntax_tree import ASTProcessor
12from renaissance.syntax_tree.match_finder import match_pattern
13from renaissance.utils.text_utils import snake_case
16class PythonRefactoring(ASTProcessor):
17 def __init__(self, file):
18 factory = PythonFactory(PythonRstNode)
19 atu = factory.create(file)
20 super().__init__(atu, factory, False)
21 self.pattern_factory = PythonPatternFactory(self.factory)
22 self.black_list_pattern = ".git"
23 self.white_list_pattern = ""
25 def replace_stmt(self, find, repl):
26 pattern = self.pattern_factory.create_statements(find)
27 for match in match_pattern(self.root.children, pattern):
28 replacement = repl
29 for exp in match.expansions:
30 arg_str = ", ".join([to_str(node) for node in match.expansions[exp]])
31 replacement = replacement.replace(exp, arg_str)
33 replacement = replacement.replace(" ,)", ")").replace(", )", ")")
34 self.replace(replacement, match.nodes, False, False)
36 @staticmethod
37 def process(class_name, file):
38 """Return a subclass by name using importlib, like Java's Class.forName()."""
39 snake = snake_case(class_name)
40 module = importlib.import_module(f"renaissance.recipes.{snake}")
41 cls = getattr(module, class_name)
42 refactor = cls(file)
43 if refactor.black_list_pattern in refactor.filename or refactor.white_list_pattern not in refactor.filename:
44 print(f"skipping: {Path(refactor.filename).resolve()}")
45 return
47 print(colored(f"refactor {Path(refactor.filename).resolve()}", "green", attrs=["bold"]))
48 refactor.run()
50 @property
51 def body(self) -> Sequence[PythonRstNode]:
52 return cast("PythonRstNode", cast("object", self.root)).body
54 def run(self):
55 pass