docsig 0.47.0__tar.gz → 0.48.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.47.0 → docsig-0.48.0}/PKG-INFO +5 -6
- {docsig-0.47.0 → docsig-0.48.0}/README.rst +4 -4
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_config.py +1 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_core.py +2 -2
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_decorators.py +1 -1
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_directives.py +1 -3
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_display.py +9 -11
- docsig-0.48.0/docsig/_main.py +45 -0
- docsig-0.48.0/docsig/_report.py +196 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_version.py +1 -1
- {docsig-0.47.0 → docsig-0.48.0}/pyproject.toml +1 -2
- docsig-0.47.0/docsig/_main.py +0 -47
- docsig-0.47.0/docsig/_report.py +0 -275
- {docsig-0.47.0 → docsig-0.48.0}/LICENSE +0 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/__init__.py +0 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/__main__.py +0 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_hooks.py +0 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_message.py +0 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_module.py +0 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_stub.py +0 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/_utils.py +0 -0
- {docsig-0.47.0 → docsig-0.48.0}/docsig/messages.py +0 -0
- {docsig-0.47.0 → docsig-0.48.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.48.0
|
|
4
4
|
Summary: Check signature params for proper documentation
|
|
5
5
|
Home-page: https://pypi.org/project/docsig/
|
|
6
6
|
License: MIT
|
|
@@ -22,7 +22,6 @@ Requires-Dist: Sphinx (>=7.0.0,<8.0.0)
|
|
|
22
22
|
Requires-Dist: arcon (>=0.4.0)
|
|
23
23
|
Requires-Dist: astroid (>=3.0.1,<4.0.0)
|
|
24
24
|
Requires-Dist: object-colors (>=2.1.0,<3.0.0)
|
|
25
|
-
Requires-Dist: typing-extensions (>=4.8.0,<5.0.0)
|
|
26
25
|
Project-URL: Documentation, https://docsig.readthedocs.io/en/latest
|
|
27
26
|
Project-URL: Repository, https://github.com/jshwi/docsig
|
|
28
27
|
Description-Content-Type: text/x-rst
|
|
@@ -139,7 +138,7 @@ Commandline
|
|
|
139
138
|
-s STR, --string STR string to parse instead of files
|
|
140
139
|
-d LIST, --disable LIST comma separated list of rules to disable
|
|
141
140
|
-t LIST, --target LIST comma separated list of rules to target
|
|
142
|
-
-e
|
|
141
|
+
-e PATTERN, --exclude PATTERN regular expression of files or dirs to exclude
|
|
143
142
|
from checks
|
|
144
143
|
|
|
145
144
|
Options can also be configured with the pyproject.toml file
|
|
@@ -182,7 +181,7 @@ API
|
|
|
182
181
|
... :param param3: About param3.
|
|
183
182
|
... '''
|
|
184
183
|
... """
|
|
185
|
-
>>> docsig(string=string)
|
|
184
|
+
>>> docsig(string=string, no_ansi=True)
|
|
186
185
|
0
|
|
187
186
|
|
|
188
187
|
.. code-block:: python
|
|
@@ -196,7 +195,7 @@ API
|
|
|
196
195
|
... :param param3: About param3.
|
|
197
196
|
... '''
|
|
198
197
|
... """
|
|
199
|
-
>>> docsig(string=string)
|
|
198
|
+
>>> docsig(string=string, no_ansi=True)
|
|
200
199
|
2
|
|
201
200
|
-
|
|
202
201
|
def function(✓param1, ✓param2, ✖None) -> ✓None:
|
|
@@ -233,7 +232,7 @@ It can be added to your .pre-commit-config.yaml as follows:
|
|
|
233
232
|
|
|
234
233
|
repos:
|
|
235
234
|
- repo: https://github.com/jshwi/docsig
|
|
236
|
-
rev: v0.
|
|
235
|
+
rev: v0.48.0
|
|
237
236
|
hooks:
|
|
238
237
|
- id: docsig
|
|
239
238
|
args:
|
|
@@ -110,7 +110,7 @@ Commandline
|
|
|
110
110
|
-s STR, --string STR string to parse instead of files
|
|
111
111
|
-d LIST, --disable LIST comma separated list of rules to disable
|
|
112
112
|
-t LIST, --target LIST comma separated list of rules to target
|
|
113
|
-
-e
|
|
113
|
+
-e PATTERN, --exclude PATTERN regular expression of files or dirs to exclude
|
|
114
114
|
from checks
|
|
115
115
|
|
|
116
116
|
Options can also be configured with the pyproject.toml file
|
|
@@ -153,7 +153,7 @@ API
|
|
|
153
153
|
... :param param3: About param3.
|
|
154
154
|
... '''
|
|
155
155
|
... """
|
|
156
|
-
>>> docsig(string=string)
|
|
156
|
+
>>> docsig(string=string, no_ansi=True)
|
|
157
157
|
0
|
|
158
158
|
|
|
159
159
|
.. code-block:: python
|
|
@@ -167,7 +167,7 @@ API
|
|
|
167
167
|
... :param param3: About param3.
|
|
168
168
|
... '''
|
|
169
169
|
... """
|
|
170
|
-
>>> docsig(string=string)
|
|
170
|
+
>>> docsig(string=string, no_ansi=True)
|
|
171
171
|
2
|
|
172
172
|
-
|
|
173
173
|
def function(✓param1, ✓param2, ✖None) -> ✓None:
|
|
@@ -204,7 +204,7 @@ It can be added to your .pre-commit-config.yaml as follows:
|
|
|
204
204
|
|
|
205
205
|
repos:
|
|
206
206
|
- repo: https://github.com/jshwi/docsig
|
|
207
|
-
rev: v0.
|
|
207
|
+
rev: v0.48.0
|
|
208
208
|
hooks:
|
|
209
209
|
- id: docsig
|
|
210
210
|
args:
|
|
@@ -16,7 +16,7 @@ from ._message import Message as _Message
|
|
|
16
16
|
from ._module import Function as _Function
|
|
17
17
|
from ._module import Modules as _Modules
|
|
18
18
|
from ._module import Parent as _Parent
|
|
19
|
-
from ._report import
|
|
19
|
+
from ._report import Report as _Report
|
|
20
20
|
from .messages import TEMPLATE as _TEMPLATE
|
|
21
21
|
from .messages import E as _E
|
|
22
22
|
|
|
@@ -73,7 +73,7 @@ def _run_check( # pylint: disable=too-many-arguments
|
|
|
73
73
|
and not (child.isdunder and not check_dunders)
|
|
74
74
|
and not (child.docstring.bare and ignore_no_params)
|
|
75
75
|
):
|
|
76
|
-
report =
|
|
76
|
+
report = _Report(
|
|
77
77
|
child, targets, child.disabled, check_property_returns
|
|
78
78
|
)
|
|
79
79
|
if report:
|
|
@@ -59,7 +59,7 @@ def validate_args(func: _FuncType) -> _WrappedFuncType:
|
|
|
59
59
|
for message in kwargs.get("targets") or []:
|
|
60
60
|
if not message.isknown:
|
|
61
61
|
stderr.append(
|
|
62
|
-
f"unknown option to target '{message.description}'"
|
|
62
|
+
f"unknown option to target '{message.description}'"
|
|
63
63
|
)
|
|
64
64
|
|
|
65
65
|
if kwargs.get("check_class") and kwargs.get(
|
|
@@ -10,8 +10,6 @@ import tokenize as _tokenize
|
|
|
10
10
|
import typing as _t
|
|
11
11
|
from io import StringIO as _StringIO
|
|
12
12
|
|
|
13
|
-
from typing_extensions import Self as _Self
|
|
14
|
-
|
|
15
13
|
from ._message import Message as _Message
|
|
16
14
|
from .messages import E as _E
|
|
17
15
|
|
|
@@ -96,7 +94,7 @@ class Directive:
|
|
|
96
94
|
return self._kind == self._valid_kinds[1]
|
|
97
95
|
|
|
98
96
|
@classmethod
|
|
99
|
-
def parse(cls, comment: str, col: int) ->
|
|
97
|
+
def parse(cls, comment: str, col: int) -> Directive | None:
|
|
100
98
|
"""Parse string into directive object if possible.
|
|
101
99
|
|
|
102
100
|
:param comment: Comment to parse.
|
|
@@ -209,15 +209,7 @@ class Failures(_t.List[Failure]):
|
|
|
209
209
|
"""Sequence of failed functions."""
|
|
210
210
|
|
|
211
211
|
|
|
212
|
-
class
|
|
213
|
-
def __getitem__(self, key: str) -> list[Failures]:
|
|
214
|
-
if key not in super().__iter__():
|
|
215
|
-
super().__setitem__(key, [])
|
|
216
|
-
|
|
217
|
-
return super().__getitem__(key)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
class Display(_DisplaySequence):
|
|
212
|
+
class Display(_t.Dict[str, _t.List[Failures]]):
|
|
221
213
|
"""Collect and display report.
|
|
222
214
|
|
|
223
215
|
:param no_ansi: Disable ANSI output.
|
|
@@ -227,6 +219,12 @@ class Display(_DisplaySequence):
|
|
|
227
219
|
super().__init__()
|
|
228
220
|
self._ansi = _ANSI(no_ansi)
|
|
229
221
|
|
|
222
|
+
def __getitem__(self, key: str) -> list[Failures]:
|
|
223
|
+
if key not in super().__iter__():
|
|
224
|
+
super().__setitem__(key, [])
|
|
225
|
+
|
|
226
|
+
return super().__getitem__(key)
|
|
227
|
+
|
|
230
228
|
def report(self) -> None:
|
|
231
229
|
"""Display report if any checks have failed."""
|
|
232
230
|
for key, value in self.items():
|
|
@@ -253,8 +251,8 @@ class Display(_DisplaySequence):
|
|
|
253
251
|
|
|
254
252
|
header += f" in {function}"
|
|
255
253
|
print(
|
|
256
|
-
"{}\n
|
|
254
|
+
"{}\n {}".format(
|
|
257
255
|
self._ansi.color(header, color.magenta),
|
|
258
|
-
failure.report.get_report("
|
|
256
|
+
failure.report.get_report(" ").strip(),
|
|
259
257
|
)
|
|
260
258
|
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
docsig._main
|
|
3
|
+
============
|
|
4
|
+
|
|
5
|
+
Contains package entry point.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations as _
|
|
9
|
+
|
|
10
|
+
from ._config import Parser as _Parser
|
|
11
|
+
from ._core import docsig as _docsig
|
|
12
|
+
from ._hooks import pretty_print_error as _pretty_print_error
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main() -> str | int:
|
|
16
|
+
"""Main function for package.
|
|
17
|
+
|
|
18
|
+
Collect config and arguments for the commandline.
|
|
19
|
+
|
|
20
|
+
:return: Exit status for whether test failed or not.
|
|
21
|
+
"""
|
|
22
|
+
p = _Parser()
|
|
23
|
+
_pretty_print_error()
|
|
24
|
+
return _docsig(
|
|
25
|
+
*p.args.path,
|
|
26
|
+
string=p.args.string,
|
|
27
|
+
list_checks=p.args.list_checks,
|
|
28
|
+
check_class=p.args.check_class,
|
|
29
|
+
check_class_constructor=p.args.check_class_constructor,
|
|
30
|
+
check_dunders=p.args.check_dunders,
|
|
31
|
+
check_protected_class_methods=p.args.check_protected_class_methods,
|
|
32
|
+
check_nested=p.args.check_nested,
|
|
33
|
+
check_overridden=p.args.check_overridden,
|
|
34
|
+
check_protected=p.args.check_protected,
|
|
35
|
+
check_property_returns=p.args.check_property_returns,
|
|
36
|
+
ignore_no_params=p.args.ignore_no_params,
|
|
37
|
+
ignore_args=p.args.ignore_args,
|
|
38
|
+
ignore_kwargs=p.args.ignore_kwargs,
|
|
39
|
+
no_ansi=p.args.no_ansi,
|
|
40
|
+
summary=p.args.summary,
|
|
41
|
+
verbose=p.args.verbose,
|
|
42
|
+
targets=p.args.target,
|
|
43
|
+
disable=p.args.disable,
|
|
44
|
+
exclude=p.args.exclude,
|
|
45
|
+
)
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""
|
|
2
|
+
docsig._report
|
|
3
|
+
==============
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations as _
|
|
7
|
+
|
|
8
|
+
import typing as _t
|
|
9
|
+
|
|
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
|
+
from ._utils import almost_equal as _almost_equal
|
|
15
|
+
from .messages import TEMPLATE as _TEMPLATE
|
|
16
|
+
from .messages import E as _E
|
|
17
|
+
|
|
18
|
+
_MIN_MATCH = 0.8
|
|
19
|
+
_MAX_MATCH = 1.0
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Report(_t.List[str]):
|
|
23
|
+
"""Compile and produce report.
|
|
24
|
+
|
|
25
|
+
:param func: Function object.
|
|
26
|
+
:param targets: List of errors to target.
|
|
27
|
+
:param disable: List of errors to disable.
|
|
28
|
+
:param check_property_returns: Run return checks on properties.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
func: _Function,
|
|
34
|
+
targets: list[_Message],
|
|
35
|
+
disable: list[_Message],
|
|
36
|
+
check_property_returns: bool,
|
|
37
|
+
) -> None:
|
|
38
|
+
super().__init__()
|
|
39
|
+
self._disable = list(disable)
|
|
40
|
+
if targets:
|
|
41
|
+
errors = list(_E.all(1))
|
|
42
|
+
for target in targets:
|
|
43
|
+
errors.remove(target)
|
|
44
|
+
|
|
45
|
+
self._disable.extend(errors)
|
|
46
|
+
|
|
47
|
+
self._errors: list[_Message] = []
|
|
48
|
+
self._func = func
|
|
49
|
+
self._no_prop_return = func.isproperty and not check_property_returns
|
|
50
|
+
self._no_returns = func.isinit or self._no_prop_return
|
|
51
|
+
self._invalid_directive()
|
|
52
|
+
self._invalid_directive_options()
|
|
53
|
+
self._missing_class_docstring()
|
|
54
|
+
self._missing_func_docstring()
|
|
55
|
+
if func.docstring.string is not None:
|
|
56
|
+
self._return_not_typed()
|
|
57
|
+
self._exists()
|
|
58
|
+
self._missing()
|
|
59
|
+
self._duplicates()
|
|
60
|
+
self._extra_return()
|
|
61
|
+
self._missing_return()
|
|
62
|
+
self._property_return()
|
|
63
|
+
self._class_return()
|
|
64
|
+
for index in range(len(func)):
|
|
65
|
+
arg = func.signature.args.get(index)
|
|
66
|
+
doc = func.docstring.args.get(index)
|
|
67
|
+
self._description_syntax(doc)
|
|
68
|
+
self._indent_syntax(doc)
|
|
69
|
+
if arg != doc:
|
|
70
|
+
self._order(arg, doc)
|
|
71
|
+
self._incorrect(arg, doc)
|
|
72
|
+
self._misspelled(arg, doc)
|
|
73
|
+
self._not_equal(arg, doc)
|
|
74
|
+
|
|
75
|
+
self.sort()
|
|
76
|
+
|
|
77
|
+
def _add(self, value: _Message, hint: bool = False, **kwargs) -> None:
|
|
78
|
+
self._errors.append(value)
|
|
79
|
+
message = value.fstring(_TEMPLATE)
|
|
80
|
+
if kwargs:
|
|
81
|
+
message = message.format(**kwargs)
|
|
82
|
+
|
|
83
|
+
if hint:
|
|
84
|
+
message += f"\nhint: {value.hint}"
|
|
85
|
+
|
|
86
|
+
if value not in self._disable and message not in self:
|
|
87
|
+
super().append(message)
|
|
88
|
+
|
|
89
|
+
def _order(self, sig: _Param, doc: _Param) -> None:
|
|
90
|
+
if any(sig.name == i.name for i in self._func.docstring.args) or any(
|
|
91
|
+
doc.name == i.name for i in self._func.signature.args
|
|
92
|
+
):
|
|
93
|
+
self._add(_E[101])
|
|
94
|
+
|
|
95
|
+
def _exists(self) -> None:
|
|
96
|
+
if len(self._func.docstring.args) > len(self._func.signature.args):
|
|
97
|
+
self._add(_E[102])
|
|
98
|
+
|
|
99
|
+
def _missing_func_docstring(self) -> None:
|
|
100
|
+
if not self._func.isinit and self._func.docstring.string is None:
|
|
101
|
+
self._add(_E[113])
|
|
102
|
+
|
|
103
|
+
def _missing_class_docstring(self) -> None:
|
|
104
|
+
if self._func.isinit and self._func.docstring.string is None:
|
|
105
|
+
self._add(_E[114])
|
|
106
|
+
|
|
107
|
+
def _missing(self) -> None:
|
|
108
|
+
if len(self._func.signature.args) > len(self._func.docstring.args):
|
|
109
|
+
self._add(_E[103])
|
|
110
|
+
|
|
111
|
+
def _duplicates(self) -> None:
|
|
112
|
+
if self._func.docstring.args.duplicated:
|
|
113
|
+
self._add(_E[106])
|
|
114
|
+
|
|
115
|
+
def _extra_return(self) -> None:
|
|
116
|
+
if (
|
|
117
|
+
self._func.docstring.returns
|
|
118
|
+
and self._func.signature.rettype == "None"
|
|
119
|
+
and not self._no_returns
|
|
120
|
+
):
|
|
121
|
+
self._add(_E[104])
|
|
122
|
+
|
|
123
|
+
def _property_return(self) -> None:
|
|
124
|
+
if self._func.docstring.returns and self._no_prop_return:
|
|
125
|
+
self._add(_E[108], hint=True)
|
|
126
|
+
|
|
127
|
+
def _return_not_typed(self) -> None:
|
|
128
|
+
if self._func.signature.rettype is None and not self._no_returns:
|
|
129
|
+
self._add(_E[109])
|
|
130
|
+
|
|
131
|
+
def _missing_return(self) -> None:
|
|
132
|
+
hint = False
|
|
133
|
+
if (
|
|
134
|
+
self._func.signature.returns
|
|
135
|
+
and not self._func.docstring.returns
|
|
136
|
+
and not self._no_returns
|
|
137
|
+
):
|
|
138
|
+
docstring = self._func.docstring.string
|
|
139
|
+
if docstring is not None and _RETURN in docstring:
|
|
140
|
+
hint = True
|
|
141
|
+
|
|
142
|
+
self._add(_E[105], hint=hint)
|
|
143
|
+
|
|
144
|
+
def _incorrect(self, sig: _Param, doc: _Param) -> None:
|
|
145
|
+
if sig.name is None and doc.name is None:
|
|
146
|
+
self._add(_E[107])
|
|
147
|
+
|
|
148
|
+
# final catch-all
|
|
149
|
+
def _not_equal(self, sig: _Param, doc: _Param) -> None:
|
|
150
|
+
if sig.name is not None and doc.name is not None and not self._errors:
|
|
151
|
+
self._add(_E[110])
|
|
152
|
+
|
|
153
|
+
def _class_return(self) -> None:
|
|
154
|
+
if self._func.docstring.returns and self._func.isinit:
|
|
155
|
+
self._add(_E[111], hint=True)
|
|
156
|
+
|
|
157
|
+
def _misspelled(self, sig: _Param, doc: _Param) -> None:
|
|
158
|
+
if (
|
|
159
|
+
sig.name is not None
|
|
160
|
+
and doc.name is not None
|
|
161
|
+
and not self._errors
|
|
162
|
+
and _almost_equal(sig.name, doc.name, _MIN_MATCH, _MAX_MATCH)
|
|
163
|
+
):
|
|
164
|
+
self._add(_E[112])
|
|
165
|
+
|
|
166
|
+
def _description_syntax(self, doc: _Param) -> None:
|
|
167
|
+
if doc.description is not None and not doc.description.startswith(" "):
|
|
168
|
+
self._add(_E[115])
|
|
169
|
+
|
|
170
|
+
def _indent_syntax(self, doc: _Param) -> None:
|
|
171
|
+
if doc.indent > 0:
|
|
172
|
+
self._add(_E[116])
|
|
173
|
+
|
|
174
|
+
def _invalid_directive(self) -> None:
|
|
175
|
+
for directive in self._func.directives:
|
|
176
|
+
if not directive.isvalid:
|
|
177
|
+
err = _E[int(f"20{1 if directive.ismodule else 2}")]
|
|
178
|
+
self._add(err, directive=directive.kind)
|
|
179
|
+
|
|
180
|
+
def _invalid_directive_options(self) -> None:
|
|
181
|
+
for directive in self._func.directives:
|
|
182
|
+
if directive.rules.unknown:
|
|
183
|
+
err = _E[int(f"20{3 if directive.ismodule else 4}")]
|
|
184
|
+
for rule in directive.rules.unknown:
|
|
185
|
+
self._add(
|
|
186
|
+
err, directive=directive.kind, option=rule.description
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def get_report(self, prefix: str = "") -> str:
|
|
190
|
+
"""Get report compiled as a string.
|
|
191
|
+
|
|
192
|
+
:param prefix: Prefix report.
|
|
193
|
+
:return: Current report.
|
|
194
|
+
"""
|
|
195
|
+
report = f"\n{prefix}".join(self)
|
|
196
|
+
return f"{report}\n"
|
|
@@ -72,7 +72,7 @@ maintainers = [
|
|
|
72
72
|
name = "docsig"
|
|
73
73
|
readme = "README.rst"
|
|
74
74
|
repository = "https://github.com/jshwi/docsig"
|
|
75
|
-
version = "0.
|
|
75
|
+
version = "0.48.0"
|
|
76
76
|
|
|
77
77
|
[tool.poetry.dependencies]
|
|
78
78
|
Pygments = "^2.13.0"
|
|
@@ -81,7 +81,6 @@ arcon = ">=0.4.0"
|
|
|
81
81
|
astroid = "^3.0.1"
|
|
82
82
|
object-colors = "^2.1.0"
|
|
83
83
|
python = "^3.8"
|
|
84
|
-
typing-extensions = "^4.8.0"
|
|
85
84
|
|
|
86
85
|
[tool.poetry.dev-dependencies]
|
|
87
86
|
bump2version = "^1.0.1"
|
docsig-0.47.0/docsig/_main.py
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
docsig._main
|
|
3
|
-
============
|
|
4
|
-
|
|
5
|
-
Contains package entry point.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations as _
|
|
9
|
-
|
|
10
|
-
from ._config import Parser as _Parser
|
|
11
|
-
from ._core import docsig as _docsig
|
|
12
|
-
from ._hooks import pretty_print_error as _pretty_print_error
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def main() -> str | int:
|
|
16
|
-
"""Main function for package.
|
|
17
|
-
|
|
18
|
-
Collect config and arguments for the commandline.
|
|
19
|
-
|
|
20
|
-
:return: Exit status for whether test failed or not.
|
|
21
|
-
"""
|
|
22
|
-
parser = _Parser()
|
|
23
|
-
_pretty_print_error()
|
|
24
|
-
return _docsig(
|
|
25
|
-
*parser.args.path,
|
|
26
|
-
string=parser.args.string,
|
|
27
|
-
list_checks=parser.args.list_checks,
|
|
28
|
-
check_class=parser.args.check_class,
|
|
29
|
-
check_class_constructor=parser.args.check_class_constructor,
|
|
30
|
-
check_dunders=parser.args.check_dunders,
|
|
31
|
-
check_protected_class_methods=(
|
|
32
|
-
parser.args.check_protected_class_methods
|
|
33
|
-
),
|
|
34
|
-
check_nested=parser.args.check_nested,
|
|
35
|
-
check_overridden=parser.args.check_overridden,
|
|
36
|
-
check_protected=parser.args.check_protected,
|
|
37
|
-
check_property_returns=parser.args.check_property_returns,
|
|
38
|
-
ignore_no_params=parser.args.ignore_no_params,
|
|
39
|
-
ignore_args=parser.args.ignore_args,
|
|
40
|
-
ignore_kwargs=parser.args.ignore_kwargs,
|
|
41
|
-
no_ansi=parser.args.no_ansi,
|
|
42
|
-
summary=parser.args.summary,
|
|
43
|
-
verbose=parser.args.verbose,
|
|
44
|
-
targets=parser.args.target,
|
|
45
|
-
disable=parser.args.disable,
|
|
46
|
-
exclude=parser.args.exclude,
|
|
47
|
-
)
|
docsig-0.47.0/docsig/_report.py
DELETED
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
docsig._report
|
|
3
|
-
==============
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations as _
|
|
7
|
-
|
|
8
|
-
import typing as _t
|
|
9
|
-
|
|
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
|
-
from ._utils import almost_equal as _almost_equal
|
|
15
|
-
from .messages import TEMPLATE as _TEMPLATE
|
|
16
|
-
from .messages import E as _E
|
|
17
|
-
|
|
18
|
-
_MIN_MATCH = 0.8
|
|
19
|
-
_MAX_MATCH = 1.0
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class _MessageSequence(_t.List[str]):
|
|
23
|
-
def __init__(
|
|
24
|
-
self,
|
|
25
|
-
targets: list[_Message],
|
|
26
|
-
disable: list[_Message],
|
|
27
|
-
) -> None:
|
|
28
|
-
super().__init__()
|
|
29
|
-
self._disable = list(disable)
|
|
30
|
-
if targets:
|
|
31
|
-
errors = list(_E.all(1))
|
|
32
|
-
for target in targets:
|
|
33
|
-
errors.remove(target)
|
|
34
|
-
|
|
35
|
-
self._disable.extend(errors)
|
|
36
|
-
|
|
37
|
-
self._errors: list[_Message] = []
|
|
38
|
-
|
|
39
|
-
def add(self, value: _Message, hint: bool = False, **kwargs) -> None:
|
|
40
|
-
"""Add an error to the container.
|
|
41
|
-
|
|
42
|
-
:param value: Value to add.
|
|
43
|
-
:param hint: Whether to print a hint or not.
|
|
44
|
-
:param kwargs: Variable(s) if format string.
|
|
45
|
-
"""
|
|
46
|
-
self._errors.append(value)
|
|
47
|
-
message = value.fstring(_TEMPLATE)
|
|
48
|
-
if kwargs:
|
|
49
|
-
message = message.format(**kwargs)
|
|
50
|
-
|
|
51
|
-
if hint:
|
|
52
|
-
message += f"\nhint: {value.hint}"
|
|
53
|
-
|
|
54
|
-
if value not in self._disable and message not in self:
|
|
55
|
-
super().append(message)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class Report(_MessageSequence):
|
|
59
|
-
"""Compile and produce report.
|
|
60
|
-
|
|
61
|
-
:param func: Function object.
|
|
62
|
-
:param targets: List of errors to target.
|
|
63
|
-
:param disable: List of errors to disable.
|
|
64
|
-
:param check_property_returns: Run return checks on properties.
|
|
65
|
-
"""
|
|
66
|
-
|
|
67
|
-
def __init__(
|
|
68
|
-
self,
|
|
69
|
-
func: _Function,
|
|
70
|
-
targets: list[_Message],
|
|
71
|
-
disable: list[_Message],
|
|
72
|
-
check_property_returns: bool,
|
|
73
|
-
) -> None:
|
|
74
|
-
super().__init__(targets, disable)
|
|
75
|
-
self._func = func
|
|
76
|
-
self._no_prop_return = func.isproperty and not check_property_returns
|
|
77
|
-
self._no_returns = func.isinit or self._no_prop_return
|
|
78
|
-
|
|
79
|
-
def order(self, sig: _Param, doc: _Param) -> None:
|
|
80
|
-
"""Test for documented parameters and their order.
|
|
81
|
-
|
|
82
|
-
:param sig: Signature argument.
|
|
83
|
-
:param doc: Docstring argument.
|
|
84
|
-
"""
|
|
85
|
-
if any(sig.name == i.name for i in self._func.docstring.args) or any(
|
|
86
|
-
doc.name == i.name for i in self._func.signature.args
|
|
87
|
-
):
|
|
88
|
-
self.add(_E[101])
|
|
89
|
-
|
|
90
|
-
def exists(self) -> None:
|
|
91
|
-
"""Test that non-existing parameter is not documented."""
|
|
92
|
-
if len(self._func.docstring.args) > len(self._func.signature.args):
|
|
93
|
-
self.add(_E[102])
|
|
94
|
-
|
|
95
|
-
def missing_func_docstring(self) -> None:
|
|
96
|
-
"""Test that docstring is not missing from func."""
|
|
97
|
-
if not self._func.isinit and self._func.docstring.string is None:
|
|
98
|
-
self.add(_E[113])
|
|
99
|
-
|
|
100
|
-
def missing_class_docstring(self) -> None:
|
|
101
|
-
"""Test that docstring is not missing from class."""
|
|
102
|
-
if self._func.isinit and self._func.docstring.string is None:
|
|
103
|
-
self.add(_E[114])
|
|
104
|
-
|
|
105
|
-
def missing(self) -> None:
|
|
106
|
-
"""Test that parameter is not missing from documentation."""
|
|
107
|
-
if len(self._func.signature.args) > len(self._func.docstring.args):
|
|
108
|
-
self.add(_E[103])
|
|
109
|
-
|
|
110
|
-
def duplicates(self) -> None:
|
|
111
|
-
"""Test that there are no duplicate parameters in docstring."""
|
|
112
|
-
if self._func.docstring.args.duplicated:
|
|
113
|
-
self.add(_E[106])
|
|
114
|
-
|
|
115
|
-
def extra_return(self) -> None:
|
|
116
|
-
"""Check that return is not documented when there is none."""
|
|
117
|
-
if (
|
|
118
|
-
self._func.docstring.returns
|
|
119
|
-
and self._func.signature.rettype == "None"
|
|
120
|
-
and not self._no_returns
|
|
121
|
-
):
|
|
122
|
-
self.add(_E[104])
|
|
123
|
-
|
|
124
|
-
def property_return(self) -> None:
|
|
125
|
-
"""Check that return is not documented for property."""
|
|
126
|
-
if self._func.docstring.returns and self._no_prop_return:
|
|
127
|
-
self.add(_E[108], hint=True)
|
|
128
|
-
|
|
129
|
-
def return_not_typed(self) -> None:
|
|
130
|
-
"""Check that return is not documented when no type provided."""
|
|
131
|
-
if self._func.signature.rettype is None and not self._no_returns:
|
|
132
|
-
self.add(_E[109])
|
|
133
|
-
|
|
134
|
-
def missing_return(self) -> None:
|
|
135
|
-
"""Check that return is documented when func returns value."""
|
|
136
|
-
hint = False
|
|
137
|
-
if (
|
|
138
|
-
self._func.signature.returns
|
|
139
|
-
and not self._func.docstring.returns
|
|
140
|
-
and not self._no_returns
|
|
141
|
-
):
|
|
142
|
-
docstring = self._func.docstring.string
|
|
143
|
-
if docstring is not None and _RETURN in docstring:
|
|
144
|
-
hint = True
|
|
145
|
-
|
|
146
|
-
self.add(_E[105], hint=hint)
|
|
147
|
-
|
|
148
|
-
def incorrect(self, sig: _Param, doc: _Param) -> None:
|
|
149
|
-
"""Test that proper syntax is used when documenting parameters.
|
|
150
|
-
|
|
151
|
-
:param sig: Signature argument.
|
|
152
|
-
:param doc: Docstring argument.
|
|
153
|
-
"""
|
|
154
|
-
if sig.name is None and doc.name is None:
|
|
155
|
-
self.add(_E[107])
|
|
156
|
-
|
|
157
|
-
def not_equal(self, sig: _Param, doc: _Param) -> None:
|
|
158
|
-
"""Final catch-all.
|
|
159
|
-
|
|
160
|
-
Only applies if no other errors, including disabled, have been
|
|
161
|
-
triggered
|
|
162
|
-
|
|
163
|
-
:param sig: Signature argument.
|
|
164
|
-
:param doc: Docstring argument.
|
|
165
|
-
"""
|
|
166
|
-
if sig.name is not None and doc.name is not None and not self._errors:
|
|
167
|
-
self.add(_E[110])
|
|
168
|
-
|
|
169
|
-
def class_return(self) -> None:
|
|
170
|
-
"""Check that return is not documented for __init__."""
|
|
171
|
-
if self._func.docstring.returns and self._func.isinit:
|
|
172
|
-
self.add(_E[111], hint=True)
|
|
173
|
-
|
|
174
|
-
def misspelled(self, sig: _Param, doc: _Param) -> None:
|
|
175
|
-
"""Test whether there is a spelling error in documentation.
|
|
176
|
-
|
|
177
|
-
To avoid false positives also check whether doc param is almost
|
|
178
|
-
equal amongst its sibling params. If params are too similarly
|
|
179
|
-
named then this error won't be raised.
|
|
180
|
-
|
|
181
|
-
:param sig: Signature argument.
|
|
182
|
-
:param doc: Docstring argument.
|
|
183
|
-
"""
|
|
184
|
-
if (
|
|
185
|
-
sig.name is not None
|
|
186
|
-
and doc.name is not None
|
|
187
|
-
and not self._errors
|
|
188
|
-
and _almost_equal(sig.name, doc.name, _MIN_MATCH, _MAX_MATCH)
|
|
189
|
-
):
|
|
190
|
-
self.add(_E[112])
|
|
191
|
-
|
|
192
|
-
def description_syntax(self, doc: _Param) -> None:
|
|
193
|
-
"""Test whether docstring description has correct spacing.
|
|
194
|
-
|
|
195
|
-
:param doc: Docstring argument.
|
|
196
|
-
"""
|
|
197
|
-
if doc.description is not None and not doc.description.startswith(" "):
|
|
198
|
-
self.add(_E[115])
|
|
199
|
-
|
|
200
|
-
def indent_syntax(self, doc: _Param) -> None:
|
|
201
|
-
"""Test whether docstring description is indented correctly.
|
|
202
|
-
|
|
203
|
-
:param doc: Docstring argument.
|
|
204
|
-
"""
|
|
205
|
-
if doc.indent > 0:
|
|
206
|
-
self.add(_E[116])
|
|
207
|
-
|
|
208
|
-
def invalid_directive(self) -> None:
|
|
209
|
-
"""Report on any invalid directives belonging to this func."""
|
|
210
|
-
for directive in self._func.directives:
|
|
211
|
-
if not directive.isvalid:
|
|
212
|
-
err = _E[int(f"20{1 if directive.ismodule else 2}")]
|
|
213
|
-
self.add(err, directive=directive.kind)
|
|
214
|
-
|
|
215
|
-
def invalid_directive_options(self) -> None:
|
|
216
|
-
"""Report on any invalid directive options belonging to this."""
|
|
217
|
-
for directive in self._func.directives:
|
|
218
|
-
if directive.rules.unknown:
|
|
219
|
-
err = _E[int(f"20{3 if directive.ismodule else 4}")]
|
|
220
|
-
for rule in directive.rules.unknown:
|
|
221
|
-
self.add(
|
|
222
|
-
err, directive=directive.kind, option=rule.description
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
def get_report(self, prefix: str = "") -> str:
|
|
226
|
-
"""Get report compiled as a string.
|
|
227
|
-
|
|
228
|
-
:param prefix: Prefix report.
|
|
229
|
-
:return: Current report.
|
|
230
|
-
"""
|
|
231
|
-
report = f"\n{prefix}".join(self)
|
|
232
|
-
return f"{report}\n"
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
def generate_report(
|
|
236
|
-
func: _Function,
|
|
237
|
-
targets: list[_Message],
|
|
238
|
-
disable: list[_Message],
|
|
239
|
-
check_property_returns: bool,
|
|
240
|
-
) -> Report:
|
|
241
|
-
"""Generate report if function or method has failed.
|
|
242
|
-
|
|
243
|
-
:param func: Function object.
|
|
244
|
-
:param targets: List of errors to target.
|
|
245
|
-
:param disable: List of errors to disable.
|
|
246
|
-
:param check_property_returns: Run return checks on properties.
|
|
247
|
-
:return: Compiled report.
|
|
248
|
-
"""
|
|
249
|
-
report = Report(func, targets, disable, check_property_returns)
|
|
250
|
-
report.invalid_directive()
|
|
251
|
-
report.invalid_directive_options()
|
|
252
|
-
report.missing_class_docstring()
|
|
253
|
-
report.missing_func_docstring()
|
|
254
|
-
if func.docstring.string is not None:
|
|
255
|
-
report.return_not_typed()
|
|
256
|
-
report.exists()
|
|
257
|
-
report.missing()
|
|
258
|
-
report.duplicates()
|
|
259
|
-
report.extra_return()
|
|
260
|
-
report.missing_return()
|
|
261
|
-
report.property_return()
|
|
262
|
-
report.class_return()
|
|
263
|
-
for index in range(len(func)):
|
|
264
|
-
arg = func.signature.args.get(index)
|
|
265
|
-
doc = func.docstring.args.get(index)
|
|
266
|
-
report.description_syntax(doc)
|
|
267
|
-
report.indent_syntax(doc)
|
|
268
|
-
if arg != doc:
|
|
269
|
-
report.order(arg, doc)
|
|
270
|
-
report.incorrect(arg, doc)
|
|
271
|
-
report.misspelled(arg, doc)
|
|
272
|
-
report.not_equal(arg, doc)
|
|
273
|
-
|
|
274
|
-
report.sort()
|
|
275
|
-
return report
|
|
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
|
|
File without changes
|