/
_module.py
145 lines (125 loc) · 4.36 KB
/
_module.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""
docsig._module
==============
"""
from __future__ import annotations
from pathlib import Path as _Path
import astroid as _ast
from ._disable import Disabled as _Disabled
from ._function import Function as _Function
from ._objects import MutableSequence as _MutableSequence
from ._utils import isprotected as _isprotected
class Parent( # pylint: disable=too-many-arguments
_MutableSequence[_Function]
):
"""Represents an object that contains functions or methods.
:param node: Parent's abstract syntax tree.
:param disabled: Data for lines which are excluded from checks.
:param path: Path to base path representation on.
:param ignore_args: Ignore args prefixed with an asterisk.
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
"""
def __init__(
self,
node: _ast.Module | _ast.ClassDef,
disabled: _Disabled,
path: _Path | None = None,
ignore_args: bool = False,
ignore_kwargs: bool = False,
) -> None:
super().__init__()
self._name = node.name
self._path = f"{path}:" if path is not None else ""
self._directives = disabled
overloads = []
returns = None
for subnode in node.body:
if isinstance(subnode, _ast.FunctionDef):
func = _Function(
subnode,
disabled.get(subnode.lineno, []),
ignore_args,
ignore_kwargs,
)
if func.isoverloaded:
overloads.append(func.name)
returns = func.signature.rettype
else:
if func.name in overloads:
subnode.returns = returns
func = _Function(
subnode,
disabled.get(subnode.lineno, []),
ignore_args,
ignore_kwargs,
)
self.append(func)
@property
def path(self) -> str:
"""Representation of path to parent."""
return self._path
@property
def isprotected(self) -> bool:
"""Boolean value for whether class is protected."""
return _isprotected(self._name)
class _Module(_MutableSequence[Parent]):
def __init__(
self,
string: str,
path: _Path | None = None,
ignore_args: bool = False,
ignore_kwargs: bool = False,
) -> None:
super().__init__()
ast = _ast.parse(string)
disabled = _Disabled(string)
self.append(Parent(ast, disabled, path, ignore_args, ignore_kwargs))
for subnode in ast.body:
if isinstance(subnode, _ast.ClassDef):
self.append(
Parent(subnode, disabled, path, ignore_args, ignore_kwargs)
)
class Modules(_MutableSequence[_Module]):
"""Sequence of ``Module`` objects parsed from Python modules or str.
Recursively collect Python files from within all dirs that exist
under paths provided.
If string is provided, ignore paths.
:param paths: Path(s) to parse ``Module``(s) from.
:param string: String to parse if provided.
:param ignore_args: Ignore args prefixed with an asterisk.
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
"""
def __init__(
self,
*paths: _Path,
string: str | None = None,
ignore_args: bool = False,
ignore_kwargs: bool = False,
) -> None:
super().__init__()
self._ignore_args = ignore_args
self._ignore_kwargs = ignore_kwargs
if string is not None:
self.append(
_Module(
string,
ignore_args=ignore_args,
ignore_kwargs=ignore_kwargs,
)
)
else:
for path in paths:
self._populate(path)
def _populate(self, root: _Path) -> None:
if root.is_file() and root.name.endswith(".py"):
self.append(
_Module(
root.read_text(),
root,
self._ignore_args,
self._ignore_kwargs,
)
)
if root.is_dir():
for path in root.iterdir():
self._populate(path)