-
Notifications
You must be signed in to change notification settings - Fork 25
/
_func.py
94 lines (81 loc) 路 2.68 KB
/
_func.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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# built-in
import ast
from pathlib import Path
from typing import Iterable, List, NamedTuple
# external
import astroid
# app
from ._contract import Category, Contract
from ._extractors import get_contracts
class Func(NamedTuple):
name: str
args: ast.arguments
body: list
contracts: Iterable[Contract]
line: int
col: int
@classmethod
def from_path(cls, path: Path) -> List['Func']:
text = path.read_text()
tree = astroid.parse(code=text, path=str(path))
return cls.from_astroid(tree)
@classmethod
def from_text(cls, text: str) -> List['Func']:
tree = astroid.parse(text)
return cls.from_astroid(tree)
@classmethod
def from_ast(cls, tree: ast.Module) -> List['Func']:
funcs = []
for expr in tree.body:
if not isinstance(expr, ast.FunctionDef):
continue
contracts = []
for category, args in get_contracts(expr.decorator_list):
contract = Contract(
args=args,
category=Category(category),
func_args=expr.args,
)
contracts.append(contract)
funcs.append(cls(
name=expr.name,
args=expr.args,
body=expr.body,
contracts=contracts,
line=expr.lineno,
col=expr.col_offset,
))
return funcs
@classmethod
def from_astroid(cls, tree: astroid.Module) -> List['Func']:
funcs = []
for expr in tree.body:
if not isinstance(expr, astroid.FunctionDef):
continue
# make signature
code = 'def f({}):0'.format(expr.args.as_string())
func_args = ast.parse(code).body[0].args # type: ignore
# collect contracts
contracts = []
if expr.decorators:
for category, args in get_contracts(expr.decorators.nodes):
contract = Contract(
args=args,
func_args=func_args,
category=Category(category),
)
contracts.append(contract)
funcs.append(cls(
name=expr.name,
args=func_args,
body=expr.body,
contracts=contracts,
line=expr.lineno,
col=expr.col_offset,
))
return funcs
def __repr__(self) -> str:
return '{name}({cats})'.format(
name=type(self).__name__,
cats=', '.join(contract.category.value for contract in self.contracts),
)