-
Notifications
You must be signed in to change notification settings - Fork 17
/
refactors.py
75 lines (57 loc) · 2.24 KB
/
refactors.py
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
from __future__ import annotations
import ast
from pathlib import Path
import refactor
from refactor import InsertAfter, Replace
from refactor.context import Scope
class RefactorAsserts(refactor.Rule):
FILES = frozenset(["refactor/common.py"])
def check_file(self, file: Path | None) -> bool:
return str(file) in self.FILES
def match(self, node: ast.AST) -> Replace:
assert isinstance(node, ast.Assert)
replacement = ast.Raise(
exc=ast.Call(
ast.Name("ValueError", ast.Load()),
args=[ast.Constant(f"condition failed: {ast.unparse(node.test)}")],
keywords=[],
)
)
guard = ast.If(
test=ast.UnaryOp(op=ast.Not(), operand=node.test),
body=[replacement],
orelse=[],
)
return Replace(node, guard)
def _is_hinted_with(node: ast.AST, name: str) -> bool:
return (
len(node.decorator_list) >= 1
and isinstance(node.decorator_list[0], ast.Call)
and isinstance(node.decorator_list[0].func, ast.Name)
and node.decorator_list[0].func.id == "_hint"
and node.decorator_list[0].args[0].value == name
)
class ProcessDeprecationHints(refactor.Rule):
FILES = frozenset(["refactor/actions.py"])
context_providers = (Scope,)
def check_file(self, file: Path | None) -> bool:
return str(file) in self.FILES
def match(self, node: ast.AST) -> InsertAfter | None:
assert isinstance(node, ast.ClassDef)
assert _is_hinted_with(node, "deprecated_alias")
alias_name = node.decorator_list[0].args[1].value
# If we already have the alias, then we can pass
# this check.
global_scope = self.context.metadata["scope"].resolve(node)
if global_scope.defines(alias_name):
return None
replacement = ast.ClassDef(
name=alias_name,
bases=[ast.Name(node.name), ast.Name("_DeprecatedAliasMixin")],
keywords=[],
body=[ast.Expr(ast.Constant(...))],
decorator_list=[ast.Name("dataclass")],
)
return InsertAfter(node, replacement)
if __name__ == "__main__":
refactor.run([RefactorAsserts, ProcessDeprecationHints])