docsig 0.46.0__tar.gz → 0.47.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {docsig-0.46.0 → docsig-0.47.0}/PKG-INFO +5 -4
- {docsig-0.46.0 → docsig-0.47.0}/README.rst +4 -3
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_config.py +6 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_core.py +54 -12
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_display.py +4 -4
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_main.py +1 -0
- docsig-0.47.0/docsig/_module.py +428 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_report.py +3 -3
- docsig-0.46.0/docsig/_function.py → docsig-0.47.0/docsig/_stub.py +21 -158
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_utils.py +0 -9
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_version.py +1 -1
- {docsig-0.46.0 → docsig-0.47.0}/pyproject.toml +1 -1
- docsig-0.46.0/docsig/_module.py +0 -246
- {docsig-0.46.0 → docsig-0.47.0}/LICENSE +0 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/__init__.py +0 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/__main__.py +0 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_decorators.py +0 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_directives.py +0 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_hooks.py +0 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/_message.py +0 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/messages.py +0 -0
- {docsig-0.46.0 → docsig-0.47.0}/docsig/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: docsig
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.47.0
|
|
4
4
|
Summary: Check signature params for proper documentation
|
|
5
5
|
Home-page: https://pypi.org/project/docsig/
|
|
6
6
|
License: MIT
|
|
@@ -106,8 +106,8 @@ Commandline
|
|
|
106
106
|
|
|
107
107
|
.. code-block:: console
|
|
108
108
|
|
|
109
|
-
usage: docsig [-h] [-V] [-l] [-c | -C] [-D] [-m] [-o] [-p] [-P] [-i] [-a]
|
|
110
|
-
[-n] [-S] [-v] [-s STR] [-d LIST] [-t LIST] [-e EXCLUDE]
|
|
109
|
+
usage: docsig [-h] [-V] [-l] [-c | -C] [-D] [-m] [-N] [-o] [-p] [-P] [-i] [-a]
|
|
110
|
+
[-k] [-n] [-S] [-v] [-s STR] [-d LIST] [-t LIST] [-e EXCLUDE]
|
|
111
111
|
[path [path ...]]
|
|
112
112
|
|
|
113
113
|
Check signature params for proper documentation
|
|
@@ -125,6 +125,7 @@ Commandline
|
|
|
125
125
|
-D, --check-dunders check dunder methods
|
|
126
126
|
-m, --check-protected-class-methods check public methods belonging to protected
|
|
127
127
|
classes
|
|
128
|
+
-N, --check-nested check nested functions and classes
|
|
128
129
|
-o, --check-overridden check overridden methods
|
|
129
130
|
-p, --check-protected check protected functions and classes
|
|
130
131
|
-P, --check-property-returns check property return values
|
|
@@ -232,7 +233,7 @@ It can be added to your .pre-commit-config.yaml as follows:
|
|
|
232
233
|
|
|
233
234
|
repos:
|
|
234
235
|
- repo: https://github.com/jshwi/docsig
|
|
235
|
-
rev: v0.
|
|
236
|
+
rev: v0.47.0
|
|
236
237
|
hooks:
|
|
237
238
|
- id: docsig
|
|
238
239
|
args:
|
|
@@ -77,8 +77,8 @@ Commandline
|
|
|
77
77
|
|
|
78
78
|
.. code-block:: console
|
|
79
79
|
|
|
80
|
-
usage: docsig [-h] [-V] [-l] [-c | -C] [-D] [-m] [-o] [-p] [-P] [-i] [-a]
|
|
81
|
-
[-n] [-S] [-v] [-s STR] [-d LIST] [-t LIST] [-e EXCLUDE]
|
|
80
|
+
usage: docsig [-h] [-V] [-l] [-c | -C] [-D] [-m] [-N] [-o] [-p] [-P] [-i] [-a]
|
|
81
|
+
[-k] [-n] [-S] [-v] [-s STR] [-d LIST] [-t LIST] [-e EXCLUDE]
|
|
82
82
|
[path [path ...]]
|
|
83
83
|
|
|
84
84
|
Check signature params for proper documentation
|
|
@@ -96,6 +96,7 @@ Commandline
|
|
|
96
96
|
-D, --check-dunders check dunder methods
|
|
97
97
|
-m, --check-protected-class-methods check public methods belonging to protected
|
|
98
98
|
classes
|
|
99
|
+
-N, --check-nested check nested functions and classes
|
|
99
100
|
-o, --check-overridden check overridden methods
|
|
100
101
|
-p, --check-protected check protected functions and classes
|
|
101
102
|
-P, --check-property-returns check property return values
|
|
@@ -203,7 +204,7 @@ It can be added to your .pre-commit-config.yaml as follows:
|
|
|
203
204
|
|
|
204
205
|
repos:
|
|
205
206
|
- repo: https://github.com/jshwi/docsig
|
|
206
|
-
rev: v0.
|
|
207
|
+
rev: v0.47.0
|
|
207
208
|
hooks:
|
|
208
209
|
- id: docsig
|
|
209
210
|
args:
|
|
@@ -67,6 +67,12 @@ class Parser(_ArgumentParser):
|
|
|
67
67
|
action="store_true",
|
|
68
68
|
help="check public methods belonging to protected classes",
|
|
69
69
|
)
|
|
70
|
+
self.add_argument(
|
|
71
|
+
"-N",
|
|
72
|
+
"--check-nested",
|
|
73
|
+
action="store_true",
|
|
74
|
+
help="check nested functions and classes",
|
|
75
|
+
)
|
|
70
76
|
self.add_argument(
|
|
71
77
|
"-o",
|
|
72
78
|
"--check-overridden",
|
|
@@ -13,6 +13,7 @@ from ._display import Failure as _Failure
|
|
|
13
13
|
from ._display import Failures as _Failures
|
|
14
14
|
from ._display import FuncStr as _FuncStr
|
|
15
15
|
from ._message import Message as _Message
|
|
16
|
+
from ._module import Function as _Function
|
|
16
17
|
from ._module import Modules as _Modules
|
|
17
18
|
from ._module import Parent as _Parent
|
|
18
19
|
from ._report import generate_report as _generate_report
|
|
@@ -45,40 +46,75 @@ def _print_checks() -> None:
|
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
def _run_check( # pylint: disable=too-many-arguments
|
|
49
|
+
child: _Parent,
|
|
48
50
|
parent: _Parent,
|
|
49
51
|
check_class: bool,
|
|
50
52
|
check_class_constructor: bool,
|
|
51
53
|
check_dunders: bool,
|
|
54
|
+
check_nested: bool,
|
|
52
55
|
check_overridden: bool,
|
|
53
56
|
check_protected: bool,
|
|
54
57
|
check_property_returns: bool,
|
|
55
58
|
ignore_no_params: bool,
|
|
56
59
|
no_ansi: bool,
|
|
57
60
|
targets: list[_Message],
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if not (
|
|
62
|
-
not (
|
|
61
|
+
failures: _Failures,
|
|
62
|
+
) -> None:
|
|
63
|
+
if isinstance(child, _Function):
|
|
64
|
+
if not (child.isoverridden and not check_overridden) and (
|
|
65
|
+
not (child.isprotected and not check_protected)
|
|
63
66
|
and not (
|
|
64
|
-
|
|
67
|
+
child.isinit
|
|
65
68
|
and not (
|
|
66
69
|
(check_class or check_class_constructor)
|
|
67
70
|
and not (parent.isprotected and not check_protected)
|
|
68
71
|
)
|
|
69
72
|
)
|
|
70
|
-
and not (
|
|
71
|
-
and not (
|
|
73
|
+
and not (child.isdunder and not check_dunders)
|
|
74
|
+
and not (child.docstring.bare and ignore_no_params)
|
|
72
75
|
):
|
|
73
76
|
report = _generate_report(
|
|
74
|
-
|
|
77
|
+
child, targets, child.disabled, check_property_returns
|
|
75
78
|
)
|
|
76
79
|
if report:
|
|
77
80
|
failures.append(
|
|
78
|
-
_Failure(
|
|
81
|
+
_Failure(child, _FuncStr(child, no_ansi), report)
|
|
79
82
|
)
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
if check_nested:
|
|
85
|
+
for func in child:
|
|
86
|
+
_run_check(
|
|
87
|
+
func,
|
|
88
|
+
child,
|
|
89
|
+
check_class,
|
|
90
|
+
check_class_constructor,
|
|
91
|
+
check_dunders,
|
|
92
|
+
check_nested,
|
|
93
|
+
check_overridden,
|
|
94
|
+
check_protected,
|
|
95
|
+
check_property_returns,
|
|
96
|
+
ignore_no_params,
|
|
97
|
+
no_ansi,
|
|
98
|
+
targets,
|
|
99
|
+
failures,
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
for func in child:
|
|
103
|
+
_run_check(
|
|
104
|
+
func,
|
|
105
|
+
child,
|
|
106
|
+
check_class,
|
|
107
|
+
check_class_constructor,
|
|
108
|
+
check_dunders,
|
|
109
|
+
check_nested,
|
|
110
|
+
check_overridden,
|
|
111
|
+
check_protected,
|
|
112
|
+
check_property_returns,
|
|
113
|
+
ignore_no_params,
|
|
114
|
+
no_ansi,
|
|
115
|
+
targets,
|
|
116
|
+
failures,
|
|
117
|
+
)
|
|
82
118
|
|
|
83
119
|
|
|
84
120
|
@_decorators.parse_msgs
|
|
@@ -91,6 +127,7 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
91
127
|
check_class_constructor: bool = False,
|
|
92
128
|
check_dunders: bool = False,
|
|
93
129
|
check_protected_class_methods: bool = False,
|
|
130
|
+
check_nested: bool = False,
|
|
94
131
|
check_overridden: bool = False,
|
|
95
132
|
check_protected: bool = False,
|
|
96
133
|
check_property_returns: bool = False,
|
|
@@ -122,6 +159,7 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
122
159
|
:param check_dunders: Check dunder methods
|
|
123
160
|
:param check_protected_class_methods: Check public methods belonging
|
|
124
161
|
to protected classes.
|
|
162
|
+
:param check_nested: Check nested functions and classes.
|
|
125
163
|
:param check_overridden: Check overridden methods
|
|
126
164
|
:param check_protected: Check protected functions and classes.
|
|
127
165
|
:param check_property_returns: Run return checks on properties.
|
|
@@ -163,17 +201,21 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
163
201
|
or check_protected
|
|
164
202
|
or check_protected_class_methods
|
|
165
203
|
):
|
|
166
|
-
failures =
|
|
204
|
+
failures = _Failures()
|
|
205
|
+
_run_check(
|
|
167
206
|
top_level,
|
|
207
|
+
module,
|
|
168
208
|
check_class,
|
|
169
209
|
check_class_constructor,
|
|
170
210
|
check_dunders,
|
|
211
|
+
check_nested,
|
|
171
212
|
check_overridden,
|
|
172
213
|
check_protected,
|
|
173
214
|
check_property_returns,
|
|
174
215
|
ignore_no_params,
|
|
175
216
|
no_ansi,
|
|
176
217
|
targets or [],
|
|
218
|
+
failures,
|
|
177
219
|
)
|
|
178
220
|
if failures:
|
|
179
221
|
display[top_level.path].append(failures)
|
|
@@ -17,11 +17,11 @@ from pygments.formatters.terminal256 import (
|
|
|
17
17
|
# noinspection PyUnresolvedReferences
|
|
18
18
|
from pygments.lexers.python import PythonLexer as _PythonLexer
|
|
19
19
|
|
|
20
|
-
from .
|
|
21
|
-
from ._function import KEY as _KEY
|
|
22
|
-
from ._function import Function as _Function
|
|
23
|
-
from ._function import Param as _Param
|
|
20
|
+
from ._module import Function as _Function
|
|
24
21
|
from ._report import Report as _Report
|
|
22
|
+
from ._stub import ARG as _ARG
|
|
23
|
+
from ._stub import KEY as _KEY
|
|
24
|
+
from ._stub import Param as _Param
|
|
25
25
|
|
|
26
26
|
color = _Color()
|
|
27
27
|
|
|
@@ -31,6 +31,7 @@ def main() -> str | int:
|
|
|
31
31
|
check_protected_class_methods=(
|
|
32
32
|
parser.args.check_protected_class_methods
|
|
33
33
|
),
|
|
34
|
+
check_nested=parser.args.check_nested,
|
|
34
35
|
check_overridden=parser.args.check_overridden,
|
|
35
36
|
check_protected=parser.args.check_protected,
|
|
36
37
|
check_property_returns=parser.args.check_property_returns,
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
"""
|
|
2
|
+
docsig._module
|
|
3
|
+
==============
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations as _
|
|
7
|
+
|
|
8
|
+
import re as _re
|
|
9
|
+
import typing as _t
|
|
10
|
+
from pathlib import Path as _Path
|
|
11
|
+
|
|
12
|
+
import astroid as _ast
|
|
13
|
+
from astroid import AstroidSyntaxError as _AstroidSyntaxError
|
|
14
|
+
|
|
15
|
+
from ._directives import Directive as _Directive
|
|
16
|
+
from ._directives import Directives as _Directives
|
|
17
|
+
from ._message import Message as _Message
|
|
18
|
+
from ._stub import Docstring as _Docstring
|
|
19
|
+
from ._stub import Signature as _Signature
|
|
20
|
+
from ._utils import vprint as _vprint
|
|
21
|
+
|
|
22
|
+
_FILE_INFO = "{path}: {msg}"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Parent(_t.List["Parent"]):
|
|
26
|
+
"""Represents an object that contains functions or methods.
|
|
27
|
+
|
|
28
|
+
:param node: Parent's abstract syntax tree.
|
|
29
|
+
:param directives: Data for directives and, subsequently, total of
|
|
30
|
+
errors which are excluded from function checks.
|
|
31
|
+
:param path: Path to base path representation on.
|
|
32
|
+
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
33
|
+
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
34
|
+
:param check_class_constructor: Check the class constructor's
|
|
35
|
+
docstring. Otherwise, expect the constructor's documentation to
|
|
36
|
+
be on the class level docstring.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__( # pylint: disable=too-many-arguments
|
|
40
|
+
self,
|
|
41
|
+
node: _ast.Module | _ast.ClassDef | _ast.FunctionDef,
|
|
42
|
+
directives: _Directives,
|
|
43
|
+
path: _Path | None = None,
|
|
44
|
+
ignore_args: bool = False,
|
|
45
|
+
ignore_kwargs: bool = False,
|
|
46
|
+
check_class_constructor: bool = False,
|
|
47
|
+
) -> None:
|
|
48
|
+
super().__init__()
|
|
49
|
+
self._name = node.name
|
|
50
|
+
self._path = f"{path}:" if path is not None else ""
|
|
51
|
+
overloads: list[str] = []
|
|
52
|
+
returns = None
|
|
53
|
+
self._parse_ast(
|
|
54
|
+
node,
|
|
55
|
+
directives,
|
|
56
|
+
path,
|
|
57
|
+
ignore_args,
|
|
58
|
+
ignore_kwargs,
|
|
59
|
+
check_class_constructor,
|
|
60
|
+
overloads,
|
|
61
|
+
returns,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def _parse_ast( # pylint: disable=protected-access,too-many-arguments
|
|
65
|
+
self,
|
|
66
|
+
node,
|
|
67
|
+
directives,
|
|
68
|
+
path,
|
|
69
|
+
ignore_args,
|
|
70
|
+
ignore_kwargs,
|
|
71
|
+
check_class_constructor,
|
|
72
|
+
overloads,
|
|
73
|
+
returns,
|
|
74
|
+
) -> None:
|
|
75
|
+
parent_comments, parent_disabled = directives.get(
|
|
76
|
+
node.lineno, ([], [])
|
|
77
|
+
)
|
|
78
|
+
if hasattr(node, "body"):
|
|
79
|
+
for subnode in node.body:
|
|
80
|
+
comments, disabled = directives.get(subnode.lineno, ([], []))
|
|
81
|
+
comments.extend(parent_comments)
|
|
82
|
+
disabled.extend(parent_disabled)
|
|
83
|
+
if isinstance(subnode, _ast.FunctionDef):
|
|
84
|
+
func = Function(
|
|
85
|
+
subnode,
|
|
86
|
+
comments,
|
|
87
|
+
directives,
|
|
88
|
+
disabled,
|
|
89
|
+
path,
|
|
90
|
+
ignore_args,
|
|
91
|
+
ignore_kwargs,
|
|
92
|
+
check_class_constructor,
|
|
93
|
+
)
|
|
94
|
+
if func.isoverloaded:
|
|
95
|
+
overloads.append(func.name)
|
|
96
|
+
returns = func.signature.rettype
|
|
97
|
+
else:
|
|
98
|
+
if func.name in overloads:
|
|
99
|
+
subnode.returns = returns
|
|
100
|
+
# noinspection PyProtectedMember
|
|
101
|
+
func._signature._rettype = (
|
|
102
|
+
returns
|
|
103
|
+
if isinstance(returns, str)
|
|
104
|
+
else func._signature._get_rettype(returns)
|
|
105
|
+
)
|
|
106
|
+
# noinspection PyProtectedMember
|
|
107
|
+
func._signature._returns = (
|
|
108
|
+
str(func._signature._rettype) != "None"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
self.append(func)
|
|
112
|
+
elif isinstance(subnode, _ast.ClassDef):
|
|
113
|
+
self.append(
|
|
114
|
+
Parent(
|
|
115
|
+
subnode,
|
|
116
|
+
directives,
|
|
117
|
+
path,
|
|
118
|
+
ignore_args,
|
|
119
|
+
ignore_kwargs,
|
|
120
|
+
check_class_constructor,
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
self._parse_ast(
|
|
125
|
+
subnode,
|
|
126
|
+
directives,
|
|
127
|
+
path,
|
|
128
|
+
ignore_args,
|
|
129
|
+
ignore_kwargs,
|
|
130
|
+
check_class_constructor,
|
|
131
|
+
overloads,
|
|
132
|
+
returns,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
def path(self) -> str:
|
|
137
|
+
"""Representation of path to parent."""
|
|
138
|
+
return self._path
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def isprotected(self) -> bool:
|
|
142
|
+
"""Boolean value for whether class is protected."""
|
|
143
|
+
return self._name.startswith("_")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class Function(Parent):
|
|
147
|
+
"""Represents a function with signature and docstring parameters.
|
|
148
|
+
|
|
149
|
+
:param node: Function's abstract syntax tree.
|
|
150
|
+
:param comments: Comments in list form containing directives.
|
|
151
|
+
:param directives: Directive, if any, belonging to this function.
|
|
152
|
+
:param disabled: List of disabled checks specific to this function.
|
|
153
|
+
:param path: Path to base path representation on.
|
|
154
|
+
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
155
|
+
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
156
|
+
:param check_class_constructor: If the function is the class
|
|
157
|
+
constructor, use its own docstring. Otherwise, use the class
|
|
158
|
+
level docstring for the constructor function.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
def __init__( # pylint: disable=too-many-arguments
|
|
162
|
+
self,
|
|
163
|
+
node: _ast.FunctionDef,
|
|
164
|
+
comments: _t.List[_Directive],
|
|
165
|
+
directives: _Directives,
|
|
166
|
+
disabled: list[_Message],
|
|
167
|
+
path: _Path | None = None,
|
|
168
|
+
ignore_args: bool = False,
|
|
169
|
+
ignore_kwargs: bool = False,
|
|
170
|
+
check_class_constructor: bool = False,
|
|
171
|
+
) -> None:
|
|
172
|
+
super().__init__(
|
|
173
|
+
node,
|
|
174
|
+
directives,
|
|
175
|
+
path,
|
|
176
|
+
ignore_args,
|
|
177
|
+
ignore_kwargs,
|
|
178
|
+
check_class_constructor,
|
|
179
|
+
)
|
|
180
|
+
self._node = node
|
|
181
|
+
self._directives = comments
|
|
182
|
+
self._disabled = disabled
|
|
183
|
+
self._parent = node.parent.frame()
|
|
184
|
+
self._signature = _Signature(
|
|
185
|
+
node.args,
|
|
186
|
+
node.returns,
|
|
187
|
+
self.ismethod,
|
|
188
|
+
self.isstaticmethod,
|
|
189
|
+
ignore_args,
|
|
190
|
+
ignore_kwargs,
|
|
191
|
+
)
|
|
192
|
+
if self.isinit and not check_class_constructor:
|
|
193
|
+
# docstring for __init__ is expected on the class docstring
|
|
194
|
+
relevant_doc_node = self._parent.doc_node
|
|
195
|
+
else:
|
|
196
|
+
relevant_doc_node = node.doc_node
|
|
197
|
+
self._docstring = _Docstring(relevant_doc_node, ignore_kwargs)
|
|
198
|
+
|
|
199
|
+
def __len__(self) -> int:
|
|
200
|
+
"""Length of the longest sequence of args."""
|
|
201
|
+
return max([len(self.signature.args), len(self.docstring.args)])
|
|
202
|
+
|
|
203
|
+
def _decorated_with(self, name: str) -> bool:
|
|
204
|
+
if self._node.decorators is not None:
|
|
205
|
+
for dec in self._node.decorators.nodes:
|
|
206
|
+
return (isinstance(dec, _ast.Name) and dec.name == name) or (
|
|
207
|
+
isinstance(dec, _ast.Attribute) and dec.attrname == name
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def ismethod(self) -> bool:
|
|
214
|
+
"""Boolean value for whether function is a method."""
|
|
215
|
+
return isinstance(self._parent, _ast.ClassDef)
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def isproperty(self) -> bool:
|
|
219
|
+
"""Boolean value for whether function is a property."""
|
|
220
|
+
valid_properties = [
|
|
221
|
+
"property",
|
|
222
|
+
"cached_property",
|
|
223
|
+
]
|
|
224
|
+
return self.ismethod and any(
|
|
225
|
+
self._decorated_with(i) for i in valid_properties
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
@property
|
|
229
|
+
def isoverloaded(self) -> bool:
|
|
230
|
+
"""Boolean value for whether function is a property."""
|
|
231
|
+
return self._decorated_with("overload")
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def isinit(self) -> bool:
|
|
235
|
+
"""Boolean value for whether function is a class constructor."""
|
|
236
|
+
return self.ismethod and self.name == "__init__"
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def isoverridden(self) -> bool:
|
|
240
|
+
"""Boolean value for whether function is overridden."""
|
|
241
|
+
if self.ismethod and not self.isinit:
|
|
242
|
+
for ancestor in self._parent.ancestors():
|
|
243
|
+
if self.name in ancestor and isinstance(
|
|
244
|
+
ancestor[self.name], _ast.FunctionDef
|
|
245
|
+
):
|
|
246
|
+
return True
|
|
247
|
+
|
|
248
|
+
return False
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def isprotected(self) -> bool:
|
|
252
|
+
"""Boolean value for whether function is protected."""
|
|
253
|
+
return super().isprotected and not self.isinit and not self.isdunder
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def isstaticmethod(self) -> bool:
|
|
257
|
+
"""Boolean value for whether function is a static method."""
|
|
258
|
+
return self.ismethod and self._decorated_with("staticmethod")
|
|
259
|
+
|
|
260
|
+
@property
|
|
261
|
+
def isdunder(self) -> bool:
|
|
262
|
+
"""Boolean value for whether function is a dunder method."""
|
|
263
|
+
return (
|
|
264
|
+
self.ismethod
|
|
265
|
+
and not self.isinit
|
|
266
|
+
and bool(_re.match(r"__(.*)__", self.name))
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
@property
|
|
270
|
+
def name(self) -> str:
|
|
271
|
+
"""The name of the function."""
|
|
272
|
+
return self._node.name
|
|
273
|
+
|
|
274
|
+
@property
|
|
275
|
+
def parent(
|
|
276
|
+
self,
|
|
277
|
+
) -> _ast.FunctionDef | _ast.Module | _ast.ClassDef | _ast.Lambda:
|
|
278
|
+
"""Function's parent node."""
|
|
279
|
+
return self._parent
|
|
280
|
+
|
|
281
|
+
@property
|
|
282
|
+
def lineno(self) -> int:
|
|
283
|
+
"""Line number of function declaration."""
|
|
284
|
+
return self._node.lineno or 0
|
|
285
|
+
|
|
286
|
+
@property
|
|
287
|
+
def signature(self) -> _Signature:
|
|
288
|
+
"""The function's signature parameters."""
|
|
289
|
+
return self._signature
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
def docstring(self) -> _Docstring:
|
|
293
|
+
"""The function's docstring."""
|
|
294
|
+
return self._docstring
|
|
295
|
+
|
|
296
|
+
@property
|
|
297
|
+
def disabled(self) -> list[_Message]:
|
|
298
|
+
"""List of disabled checks specific to this function."""
|
|
299
|
+
return self._disabled
|
|
300
|
+
|
|
301
|
+
@property
|
|
302
|
+
def directives(self) -> _t.List[_Directive]:
|
|
303
|
+
"""Directive, if any, belonging to this function."""
|
|
304
|
+
return self._directives
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class Modules(_t.List[Parent]):
|
|
308
|
+
"""Sequence of ``Module`` objects parsed from Python modules or str.
|
|
309
|
+
|
|
310
|
+
Recursively collect Python files from within all dirs that exist
|
|
311
|
+
under paths provided.
|
|
312
|
+
|
|
313
|
+
If string is provided, ignore paths.
|
|
314
|
+
|
|
315
|
+
:param paths: Path(s) to parse ``Module``(s) from.
|
|
316
|
+
:param disable: List of checks to disable.
|
|
317
|
+
:param excludes: List pf regular expression of files and dirs to
|
|
318
|
+
exclude from checks.
|
|
319
|
+
:param string: String to parse if provided.
|
|
320
|
+
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
321
|
+
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
322
|
+
:param check_class_constructor: Check the class constructor's
|
|
323
|
+
docstring. Otherwise, expect the constructor's documentation to
|
|
324
|
+
be on the class level docstring.
|
|
325
|
+
:param verbose: increase output verbosity.
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
# handle errors here before appending a module
|
|
329
|
+
def _add_module( # pylint: disable=too-many-arguments
|
|
330
|
+
self,
|
|
331
|
+
disable: list[_Message],
|
|
332
|
+
string: str | None = None,
|
|
333
|
+
root: _Path | None = None,
|
|
334
|
+
ignore_args: bool = False,
|
|
335
|
+
ignore_kwargs: bool = False,
|
|
336
|
+
check_class_constructor: bool = False,
|
|
337
|
+
) -> None:
|
|
338
|
+
try:
|
|
339
|
+
if root is not None:
|
|
340
|
+
string = root.read_text(encoding="utf-8")
|
|
341
|
+
|
|
342
|
+
# empty string won't happen but keeps the
|
|
343
|
+
# typechecker happy
|
|
344
|
+
string = string or ""
|
|
345
|
+
self.append(
|
|
346
|
+
Parent(
|
|
347
|
+
_ast.parse(string),
|
|
348
|
+
_Directives(string, disable),
|
|
349
|
+
root,
|
|
350
|
+
ignore_args,
|
|
351
|
+
ignore_kwargs,
|
|
352
|
+
check_class_constructor,
|
|
353
|
+
)
|
|
354
|
+
)
|
|
355
|
+
except (_AstroidSyntaxError, UnicodeDecodeError) as err:
|
|
356
|
+
if root is not None and root.name.endswith(".py"):
|
|
357
|
+
# keep raising errors for .py files as was done prior to
|
|
358
|
+
# this change
|
|
359
|
+
# pass by silently for files that do not end with .py,
|
|
360
|
+
# which were not checked at all prior (these may result
|
|
361
|
+
# in a 123 syntax error exit status in the future)
|
|
362
|
+
# with this there should be no breaking change, and
|
|
363
|
+
# files that are supposed to be python, files evident by
|
|
364
|
+
# their suffix, will continue to fail
|
|
365
|
+
raise err
|
|
366
|
+
|
|
367
|
+
_vprint(
|
|
368
|
+
_FILE_INFO.format(
|
|
369
|
+
path=root or "stdin", msg=str(err).replace("\n", " ")
|
|
370
|
+
),
|
|
371
|
+
self._verbose,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
def __init__( # pylint: disable=too-many-arguments
|
|
375
|
+
self,
|
|
376
|
+
*paths: _Path,
|
|
377
|
+
disable: list[_Message],
|
|
378
|
+
excludes: list[str],
|
|
379
|
+
string: str | None = None,
|
|
380
|
+
ignore_args: bool = False,
|
|
381
|
+
ignore_kwargs: bool = False,
|
|
382
|
+
check_class_constructor: bool = False,
|
|
383
|
+
verbose: bool = False,
|
|
384
|
+
) -> None:
|
|
385
|
+
super().__init__()
|
|
386
|
+
self._disable = disable
|
|
387
|
+
self._excludes = excludes
|
|
388
|
+
self._ignore_args = ignore_args
|
|
389
|
+
self._ignore_kwargs = ignore_kwargs
|
|
390
|
+
self.check_class_constructor = check_class_constructor
|
|
391
|
+
self._verbose = verbose
|
|
392
|
+
if string is not None:
|
|
393
|
+
self._add_module(
|
|
394
|
+
disable,
|
|
395
|
+
string=string,
|
|
396
|
+
ignore_args=ignore_args,
|
|
397
|
+
ignore_kwargs=ignore_kwargs,
|
|
398
|
+
check_class_constructor=check_class_constructor,
|
|
399
|
+
)
|
|
400
|
+
else:
|
|
401
|
+
for path in paths:
|
|
402
|
+
self._populate(path)
|
|
403
|
+
|
|
404
|
+
def _populate(self, root: _Path) -> None:
|
|
405
|
+
if not root.exists():
|
|
406
|
+
raise FileNotFoundError(root)
|
|
407
|
+
|
|
408
|
+
if str(root) != "." and any(
|
|
409
|
+
_re.match(i, root.name) for i in self._excludes
|
|
410
|
+
):
|
|
411
|
+
_vprint(
|
|
412
|
+
_FILE_INFO.format(path=root, msg="in exclude list, skipping"),
|
|
413
|
+
self._verbose,
|
|
414
|
+
)
|
|
415
|
+
return
|
|
416
|
+
|
|
417
|
+
if root.is_file():
|
|
418
|
+
self._add_module(
|
|
419
|
+
self._disable,
|
|
420
|
+
root=root,
|
|
421
|
+
ignore_args=self._ignore_args,
|
|
422
|
+
ignore_kwargs=self._ignore_kwargs,
|
|
423
|
+
check_class_constructor=self.check_class_constructor,
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
if root.is_dir():
|
|
427
|
+
for path in root.iterdir():
|
|
428
|
+
self._populate(path)
|
|
@@ -7,10 +7,10 @@ from __future__ import annotations as _
|
|
|
7
7
|
|
|
8
8
|
import typing as _t
|
|
9
9
|
|
|
10
|
-
from ._function import RETURN as _RETURN
|
|
11
|
-
from ._function import Function as _Function
|
|
12
|
-
from ._function import Param as _Param
|
|
13
10
|
from ._message import Message as _Message
|
|
11
|
+
from ._module import Function as _Function
|
|
12
|
+
from ._stub import RETURN as _RETURN
|
|
13
|
+
from ._stub import Param as _Param
|
|
14
14
|
from ._utils import almost_equal as _almost_equal
|
|
15
15
|
from .messages import TEMPLATE as _TEMPLATE
|
|
16
16
|
from .messages import E as _E
|
|
@@ -13,10 +13,6 @@ from collections import Counter as _Counter
|
|
|
13
13
|
import astroid as _ast
|
|
14
14
|
import sphinx.ext.napoleon as _s
|
|
15
15
|
|
|
16
|
-
from ._directives import Directive as _Directive
|
|
17
|
-
from ._message import Message as _Message
|
|
18
|
-
from ._utils import isprotected as _isprotected
|
|
19
|
-
|
|
20
16
|
PARAM = "param"
|
|
21
17
|
KEYWORD = "keyword"
|
|
22
18
|
KEY = "key"
|
|
@@ -151,7 +147,7 @@ class _Params(_t.List[Param]):
|
|
|
151
147
|
return any(k for k, v in _Counter(self).items() if v > 1)
|
|
152
148
|
|
|
153
149
|
|
|
154
|
-
class
|
|
150
|
+
class _Stub:
|
|
155
151
|
def __init__(
|
|
156
152
|
self, ignore_args: bool = False, ignore_kwargs: bool = False
|
|
157
153
|
) -> None:
|
|
@@ -169,7 +165,18 @@ class _DocSig:
|
|
|
169
165
|
return self._returns
|
|
170
166
|
|
|
171
167
|
|
|
172
|
-
class
|
|
168
|
+
class Signature(_Stub):
|
|
169
|
+
"""Represents a function signature.
|
|
170
|
+
|
|
171
|
+
:param arguments: Arguments provided to signature.
|
|
172
|
+
:param returns: Returns declared in signature.
|
|
173
|
+
:param ismethod: Whether this signature belongs to a method.
|
|
174
|
+
:param isstaticmethod: Whether this signature belongs to a static
|
|
175
|
+
method.
|
|
176
|
+
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
177
|
+
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
178
|
+
"""
|
|
179
|
+
|
|
173
180
|
def __init__( # pylint: disable=too-many-arguments
|
|
174
181
|
self,
|
|
175
182
|
arguments: _ast.Arguments,
|
|
@@ -239,7 +246,14 @@ class _Signature(_DocSig):
|
|
|
239
246
|
return self._rettype
|
|
240
247
|
|
|
241
248
|
|
|
242
|
-
class
|
|
249
|
+
class Docstring(_Stub):
|
|
250
|
+
"""Represents a function docstring.
|
|
251
|
+
|
|
252
|
+
:param node: Docstring ast node.
|
|
253
|
+
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
254
|
+
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
255
|
+
"""
|
|
256
|
+
|
|
243
257
|
def __init__(
|
|
244
258
|
self,
|
|
245
259
|
node: _ast.Const | None = None,
|
|
@@ -269,154 +283,3 @@ class _Docstring(_DocSig):
|
|
|
269
283
|
Docstring has to exist for docstring to be considered bare.
|
|
270
284
|
"""
|
|
271
285
|
return self._string is not None and not self._args and not self.returns
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
class Function: # pylint: disable=too-many-arguments
|
|
275
|
-
"""Represents a function with signature and docstring parameters.
|
|
276
|
-
|
|
277
|
-
:param node: Function's abstract syntax tree.
|
|
278
|
-
:param directives: Directive, if any, belonging to this function.
|
|
279
|
-
:param disabled: List of disabled checks specific to this function.
|
|
280
|
-
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
281
|
-
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
282
|
-
:param check_class_constructor: If the function is the class
|
|
283
|
-
constructor, use its own docstring. Otherwise, use the class
|
|
284
|
-
level docstring for the constructor function.
|
|
285
|
-
"""
|
|
286
|
-
|
|
287
|
-
def __init__( # pylint: disable=too-many-arguments
|
|
288
|
-
self,
|
|
289
|
-
node: _ast.FunctionDef,
|
|
290
|
-
directives: _t.List[_Directive],
|
|
291
|
-
disabled: list[_Message],
|
|
292
|
-
ignore_args: bool = False,
|
|
293
|
-
ignore_kwargs: bool = False,
|
|
294
|
-
check_class_constructor: bool = False,
|
|
295
|
-
) -> None:
|
|
296
|
-
self._node = node
|
|
297
|
-
self._directives = directives
|
|
298
|
-
self._disabled = disabled
|
|
299
|
-
self._parent = node.parent.frame()
|
|
300
|
-
self._signature = _Signature(
|
|
301
|
-
node.args,
|
|
302
|
-
node.returns,
|
|
303
|
-
self.ismethod,
|
|
304
|
-
self.isstaticmethod,
|
|
305
|
-
ignore_args,
|
|
306
|
-
ignore_kwargs,
|
|
307
|
-
)
|
|
308
|
-
if self.isinit and not check_class_constructor:
|
|
309
|
-
# docstring for __init__ is expected on the class docstring
|
|
310
|
-
relevant_doc_node = self._parent.doc_node
|
|
311
|
-
else:
|
|
312
|
-
relevant_doc_node = node.doc_node
|
|
313
|
-
self._docstring = _Docstring(relevant_doc_node, ignore_kwargs)
|
|
314
|
-
|
|
315
|
-
def __len__(self) -> int:
|
|
316
|
-
"""Length of the longest sequence of args."""
|
|
317
|
-
return max([len(self.signature.args), len(self.docstring.args)])
|
|
318
|
-
|
|
319
|
-
def _decorated_with(self, name: str) -> bool:
|
|
320
|
-
if self._node.decorators is not None:
|
|
321
|
-
for dec in self._node.decorators.nodes:
|
|
322
|
-
return (isinstance(dec, _ast.Name) and dec.name == name) or (
|
|
323
|
-
isinstance(dec, _ast.Attribute) and dec.attrname == name
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
return False
|
|
327
|
-
|
|
328
|
-
@property
|
|
329
|
-
def ismethod(self) -> bool:
|
|
330
|
-
"""Boolean value for whether function is a method."""
|
|
331
|
-
return isinstance(self._parent, _ast.ClassDef)
|
|
332
|
-
|
|
333
|
-
@property
|
|
334
|
-
def isproperty(self) -> bool:
|
|
335
|
-
"""Boolean value for whether function is a property."""
|
|
336
|
-
valid_properties = [
|
|
337
|
-
"property",
|
|
338
|
-
"cached_property",
|
|
339
|
-
]
|
|
340
|
-
return self.ismethod and any(
|
|
341
|
-
self._decorated_with(i) for i in valid_properties
|
|
342
|
-
)
|
|
343
|
-
|
|
344
|
-
@property
|
|
345
|
-
def isoverloaded(self) -> bool:
|
|
346
|
-
"""Boolean value for whether function is a property."""
|
|
347
|
-
return self._decorated_with("overload")
|
|
348
|
-
|
|
349
|
-
@property
|
|
350
|
-
def isinit(self) -> bool:
|
|
351
|
-
"""Boolean value for whether function is a class constructor."""
|
|
352
|
-
return self.ismethod and self.name == "__init__"
|
|
353
|
-
|
|
354
|
-
@property
|
|
355
|
-
def isoverridden(self) -> bool:
|
|
356
|
-
"""Boolean value for whether function is overridden."""
|
|
357
|
-
if self.ismethod and not self.isinit:
|
|
358
|
-
for ancestor in self._parent.ancestors():
|
|
359
|
-
if self.name in ancestor and isinstance(
|
|
360
|
-
ancestor[self.name], _ast.FunctionDef
|
|
361
|
-
):
|
|
362
|
-
return True
|
|
363
|
-
|
|
364
|
-
return False
|
|
365
|
-
|
|
366
|
-
@property
|
|
367
|
-
def isprotected(self) -> bool:
|
|
368
|
-
"""Boolean value for whether function is protected."""
|
|
369
|
-
return (
|
|
370
|
-
_isprotected(self.name) and not self.isinit and not self.isdunder
|
|
371
|
-
)
|
|
372
|
-
|
|
373
|
-
@property
|
|
374
|
-
def isstaticmethod(self) -> bool:
|
|
375
|
-
"""Boolean value for whether function is a static method."""
|
|
376
|
-
return self.ismethod and self._decorated_with("staticmethod")
|
|
377
|
-
|
|
378
|
-
@property
|
|
379
|
-
def isdunder(self) -> bool:
|
|
380
|
-
"""Boolean value for whether function is a dunder method."""
|
|
381
|
-
return (
|
|
382
|
-
self.ismethod
|
|
383
|
-
and not self.isinit
|
|
384
|
-
and bool(_re.match(r"__(.*)__", self.name))
|
|
385
|
-
)
|
|
386
|
-
|
|
387
|
-
@property
|
|
388
|
-
def name(self) -> str:
|
|
389
|
-
"""The name of the function."""
|
|
390
|
-
return self._node.name
|
|
391
|
-
|
|
392
|
-
@property
|
|
393
|
-
def parent(
|
|
394
|
-
self,
|
|
395
|
-
) -> _ast.FunctionDef | _ast.Module | _ast.ClassDef | _ast.Lambda:
|
|
396
|
-
"""Function's parent node."""
|
|
397
|
-
return self._parent
|
|
398
|
-
|
|
399
|
-
@property
|
|
400
|
-
def lineno(self) -> int:
|
|
401
|
-
"""Line number of function declaration."""
|
|
402
|
-
return self._node.lineno or 0
|
|
403
|
-
|
|
404
|
-
@property
|
|
405
|
-
def signature(self) -> _Signature:
|
|
406
|
-
"""The function's signature parameters."""
|
|
407
|
-
return self._signature
|
|
408
|
-
|
|
409
|
-
@property
|
|
410
|
-
def docstring(self) -> _Docstring:
|
|
411
|
-
"""The function's docstring."""
|
|
412
|
-
return self._docstring
|
|
413
|
-
|
|
414
|
-
@property
|
|
415
|
-
def disabled(self) -> list[_Message]:
|
|
416
|
-
"""List of disabled checks specific to this function."""
|
|
417
|
-
return self._disabled
|
|
418
|
-
|
|
419
|
-
@property
|
|
420
|
-
def directives(self) -> _t.List[_Directive]:
|
|
421
|
-
"""Directive, if any, belonging to this function."""
|
|
422
|
-
return self._directives
|
|
@@ -8,15 +8,6 @@ from __future__ import annotations as _
|
|
|
8
8
|
from difflib import SequenceMatcher as _SequenceMatcher
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def isprotected(name: str | None) -> bool:
|
|
12
|
-
"""Confirm whether attribute is protected or not.
|
|
13
|
-
|
|
14
|
-
:param name: Name to check.
|
|
15
|
-
:return: Boolean value for whether attribute is protected or not.
|
|
16
|
-
"""
|
|
17
|
-
return str(name).startswith("_")
|
|
18
|
-
|
|
19
|
-
|
|
20
11
|
def almost_equal(str1: str, str2: str, mini: float, maxi: float) -> bool:
|
|
21
12
|
"""Show result for more than the minimum but less than the maximum.
|
|
22
13
|
|
docsig-0.46.0/docsig/_module.py
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
docsig._module
|
|
3
|
-
==============
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations as _
|
|
7
|
-
|
|
8
|
-
import re as _re
|
|
9
|
-
import typing as _t
|
|
10
|
-
from pathlib import Path as _Path
|
|
11
|
-
|
|
12
|
-
import astroid as _ast
|
|
13
|
-
from astroid import AstroidSyntaxError as _AstroidSyntaxError
|
|
14
|
-
|
|
15
|
-
from ._directives import Directives as _Directives
|
|
16
|
-
from ._function import Function as _Function
|
|
17
|
-
from ._message import Message as _Message
|
|
18
|
-
from ._utils import isprotected as _isprotected
|
|
19
|
-
from ._utils import vprint as _vprint
|
|
20
|
-
|
|
21
|
-
_FILE_INFO = "{path}: {msg}"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class Parent(_t.List[_Function]):
|
|
25
|
-
"""Represents an object that contains functions or methods.
|
|
26
|
-
|
|
27
|
-
:param node: Parent's abstract syntax tree.
|
|
28
|
-
:param directives: Data for directives and, subsequently, total of
|
|
29
|
-
errors which are excluded from function checks.
|
|
30
|
-
:param path: Path to base path representation on.
|
|
31
|
-
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
32
|
-
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
33
|
-
:param check_class_constructor: Check the class constructor's
|
|
34
|
-
docstring. Otherwise, expect the constructor's documentation to
|
|
35
|
-
be on the class level docstring.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
def __init__( # pylint: disable=too-many-arguments
|
|
39
|
-
self,
|
|
40
|
-
node: _ast.Module | _ast.ClassDef,
|
|
41
|
-
directives: _Directives,
|
|
42
|
-
path: _Path | None = None,
|
|
43
|
-
ignore_args: bool = False,
|
|
44
|
-
ignore_kwargs: bool = False,
|
|
45
|
-
check_class_constructor: bool = False,
|
|
46
|
-
) -> None:
|
|
47
|
-
super().__init__()
|
|
48
|
-
self._name = node.name
|
|
49
|
-
self._path = f"{path}:" if path is not None else ""
|
|
50
|
-
overloads = []
|
|
51
|
-
returns = None
|
|
52
|
-
parent_comments, parent_disabled = directives.get(
|
|
53
|
-
node.lineno, ([], [])
|
|
54
|
-
)
|
|
55
|
-
for subnode in node.body:
|
|
56
|
-
comments, disabled = directives.get(subnode.lineno, ([], []))
|
|
57
|
-
comments.extend(parent_comments)
|
|
58
|
-
disabled.extend(parent_disabled)
|
|
59
|
-
if isinstance(subnode, _ast.FunctionDef):
|
|
60
|
-
func = _Function(
|
|
61
|
-
subnode,
|
|
62
|
-
comments,
|
|
63
|
-
disabled,
|
|
64
|
-
ignore_args,
|
|
65
|
-
ignore_kwargs,
|
|
66
|
-
check_class_constructor,
|
|
67
|
-
)
|
|
68
|
-
if func.isoverloaded:
|
|
69
|
-
overloads.append(func.name)
|
|
70
|
-
returns = func.signature.rettype
|
|
71
|
-
else:
|
|
72
|
-
if func.name in overloads:
|
|
73
|
-
subnode.returns = returns
|
|
74
|
-
# noinspection PyProtectedMember
|
|
75
|
-
func._signature._rettype = (
|
|
76
|
-
returns
|
|
77
|
-
if isinstance(returns, str)
|
|
78
|
-
else func._signature._get_rettype(returns)
|
|
79
|
-
)
|
|
80
|
-
# noinspection PyProtectedMember
|
|
81
|
-
func._signature._returns = (
|
|
82
|
-
str(func._signature._rettype) != "None"
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
self.append(func)
|
|
86
|
-
|
|
87
|
-
@property
|
|
88
|
-
def path(self) -> str:
|
|
89
|
-
"""Representation of path to parent."""
|
|
90
|
-
return self._path
|
|
91
|
-
|
|
92
|
-
@property
|
|
93
|
-
def isprotected(self) -> bool:
|
|
94
|
-
"""Boolean value for whether class is protected."""
|
|
95
|
-
return _isprotected(self._name)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
class _Module(_t.List[Parent]):
|
|
99
|
-
def __init__( # pylint: disable=too-many-arguments
|
|
100
|
-
self,
|
|
101
|
-
string: str,
|
|
102
|
-
disable: list[_Message],
|
|
103
|
-
path: _Path | None = None,
|
|
104
|
-
ignore_args: bool = False,
|
|
105
|
-
ignore_kwargs: bool = False,
|
|
106
|
-
check_class_constructor: bool = False,
|
|
107
|
-
) -> None:
|
|
108
|
-
super().__init__()
|
|
109
|
-
ast = _ast.parse(string)
|
|
110
|
-
directives = _Directives(string, disable)
|
|
111
|
-
self.append(Parent(ast, directives, path, ignore_args, ignore_kwargs))
|
|
112
|
-
for subnode in ast.body:
|
|
113
|
-
if isinstance(subnode, _ast.ClassDef):
|
|
114
|
-
self.append(
|
|
115
|
-
Parent(
|
|
116
|
-
subnode,
|
|
117
|
-
directives,
|
|
118
|
-
path,
|
|
119
|
-
ignore_args,
|
|
120
|
-
ignore_kwargs,
|
|
121
|
-
check_class_constructor,
|
|
122
|
-
)
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
class Modules(_t.List[_Module]):
|
|
127
|
-
"""Sequence of ``Module`` objects parsed from Python modules or str.
|
|
128
|
-
|
|
129
|
-
Recursively collect Python files from within all dirs that exist
|
|
130
|
-
under paths provided.
|
|
131
|
-
|
|
132
|
-
If string is provided, ignore paths.
|
|
133
|
-
|
|
134
|
-
:param paths: Path(s) to parse ``Module``(s) from.
|
|
135
|
-
:param disable: List of checks to disable.
|
|
136
|
-
:param excludes: List pf regular expression of files and dirs to
|
|
137
|
-
exclude from checks.
|
|
138
|
-
:param string: String to parse if provided.
|
|
139
|
-
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
140
|
-
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
141
|
-
:param check_class_constructor: Check the class constructor's
|
|
142
|
-
docstring. Otherwise, expect the constructor's documentation to
|
|
143
|
-
be on the class level docstring.
|
|
144
|
-
:param verbose: increase output verbosity.
|
|
145
|
-
"""
|
|
146
|
-
|
|
147
|
-
# handle errors here before appending a module
|
|
148
|
-
def _add_module( # pylint: disable=too-many-arguments
|
|
149
|
-
self,
|
|
150
|
-
disable: list[_Message],
|
|
151
|
-
string: str | None = None,
|
|
152
|
-
root: _Path | None = None,
|
|
153
|
-
ignore_args: bool = False,
|
|
154
|
-
ignore_kwargs: bool = False,
|
|
155
|
-
check_class_constructor: bool = False,
|
|
156
|
-
) -> None:
|
|
157
|
-
try:
|
|
158
|
-
if root is not None:
|
|
159
|
-
string = root.read_text(encoding="utf-8")
|
|
160
|
-
|
|
161
|
-
self.append(
|
|
162
|
-
_Module(
|
|
163
|
-
# empty string won't happen but keeps the
|
|
164
|
-
# typechecker happy
|
|
165
|
-
string or "",
|
|
166
|
-
disable,
|
|
167
|
-
root,
|
|
168
|
-
ignore_args,
|
|
169
|
-
ignore_kwargs,
|
|
170
|
-
check_class_constructor,
|
|
171
|
-
)
|
|
172
|
-
)
|
|
173
|
-
except (_AstroidSyntaxError, UnicodeDecodeError) as err:
|
|
174
|
-
if root is not None and root.name.endswith(".py"):
|
|
175
|
-
# keep raising errors for .py files as was done prior to
|
|
176
|
-
# this change
|
|
177
|
-
# pass by silently for files that do not end with .py,
|
|
178
|
-
# which were not checked at all prior (these may result
|
|
179
|
-
# in a 123 syntax error exit status in the future)
|
|
180
|
-
# with this there should be no breaking change, and
|
|
181
|
-
# files that are supposed to be python, files evident by
|
|
182
|
-
# their suffix, will continue to fail
|
|
183
|
-
raise err
|
|
184
|
-
|
|
185
|
-
_vprint(
|
|
186
|
-
_FILE_INFO.format(
|
|
187
|
-
path=root or "stdin", msg=str(err).replace("\n", " ")
|
|
188
|
-
),
|
|
189
|
-
self._verbose,
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
def __init__( # pylint: disable=too-many-arguments
|
|
193
|
-
self,
|
|
194
|
-
*paths: _Path,
|
|
195
|
-
disable: list[_Message],
|
|
196
|
-
excludes: list[str],
|
|
197
|
-
string: str | None = None,
|
|
198
|
-
ignore_args: bool = False,
|
|
199
|
-
ignore_kwargs: bool = False,
|
|
200
|
-
check_class_constructor: bool = False,
|
|
201
|
-
verbose: bool = False,
|
|
202
|
-
) -> None:
|
|
203
|
-
super().__init__()
|
|
204
|
-
self._disable = disable
|
|
205
|
-
self._excludes = excludes
|
|
206
|
-
self._ignore_args = ignore_args
|
|
207
|
-
self._ignore_kwargs = ignore_kwargs
|
|
208
|
-
self.check_class_constructor = check_class_constructor
|
|
209
|
-
self._verbose = verbose
|
|
210
|
-
if string is not None:
|
|
211
|
-
self._add_module(
|
|
212
|
-
disable,
|
|
213
|
-
string=string,
|
|
214
|
-
ignore_args=ignore_args,
|
|
215
|
-
ignore_kwargs=ignore_kwargs,
|
|
216
|
-
check_class_constructor=check_class_constructor,
|
|
217
|
-
)
|
|
218
|
-
else:
|
|
219
|
-
for path in paths:
|
|
220
|
-
self._populate(path)
|
|
221
|
-
|
|
222
|
-
def _populate(self, root: _Path) -> None:
|
|
223
|
-
if not root.exists():
|
|
224
|
-
raise FileNotFoundError(root)
|
|
225
|
-
|
|
226
|
-
if str(root) != "." and any(
|
|
227
|
-
_re.match(i, root.name) for i in self._excludes
|
|
228
|
-
):
|
|
229
|
-
_vprint(
|
|
230
|
-
_FILE_INFO.format(path=root, msg="in exclude list, skipping"),
|
|
231
|
-
self._verbose,
|
|
232
|
-
)
|
|
233
|
-
return
|
|
234
|
-
|
|
235
|
-
if root.is_file():
|
|
236
|
-
self._add_module(
|
|
237
|
-
self._disable,
|
|
238
|
-
root=root,
|
|
239
|
-
ignore_args=self._ignore_args,
|
|
240
|
-
ignore_kwargs=self._ignore_kwargs,
|
|
241
|
-
check_class_constructor=self.check_class_constructor,
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
if root.is_dir():
|
|
245
|
-
for path in root.iterdir():
|
|
246
|
-
self._populate(path)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|