docsig 0.80.0__tar.gz → 0.80.1__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.80.0 → docsig-0.80.1}/PKG-INFO +6 -6
- {docsig-0.80.0 → docsig-0.80.1}/README.rst +5 -5
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_config.py +75 -7
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_core.py +105 -35
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_directives.py +8 -6
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_files.py +5 -25
- docsig-0.80.1/docsig/_main.py +62 -0
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_module.py +27 -19
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_report.py +27 -32
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_stub.py +6 -31
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_utils.py +19 -0
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_version.py +1 -1
- {docsig-0.80.0 → docsig-0.80.1}/docsig/messages.py +8 -7
- {docsig-0.80.0 → docsig-0.80.1}/docsig/plugin.py +52 -42
- {docsig-0.80.0 → docsig-0.80.1}/pyproject.toml +3 -2
- docsig-0.80.0/docsig/_main.py +0 -26
- {docsig-0.80.0 → docsig-0.80.1}/LICENSE +0 -0
- {docsig-0.80.0 → docsig-0.80.1}/docsig/__init__.py +0 -0
- {docsig-0.80.0 → docsig-0.80.1}/docsig/__main__.py +0 -0
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_decorators.py +0 -0
- {docsig-0.80.0 → docsig-0.80.1}/docsig/_hooks.py +0 -0
- {docsig-0.80.0 → docsig-0.80.1}/docsig/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docsig
|
|
3
|
-
Version: 0.80.
|
|
3
|
+
Version: 0.80.1
|
|
4
4
|
Summary: Check signature params for proper documentation
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -116,7 +116,7 @@ Commandline
|
|
|
116
116
|
[--check-property-returns] [--check-protected]
|
|
117
117
|
[--check-protected-class-methods] [--ignore-args] [--ignore-kwargs]
|
|
118
118
|
[--ignore-no-params] [-d LIST] [-t LIST] [-e PATTERN] [-E PATH [PATH ...]]
|
|
119
|
-
[-
|
|
119
|
+
[-I] [-s STR]
|
|
120
120
|
[path [path ...]]
|
|
121
121
|
|
|
122
122
|
Check signature params for proper documentation
|
|
@@ -152,7 +152,7 @@ Commandline
|
|
|
152
152
|
regular expression of files or dirs to exclude from checks
|
|
153
153
|
-E PATH [PATH ...], --excludes PATH [PATH ...]
|
|
154
154
|
path glob patterns to exclude from checks
|
|
155
|
-
-
|
|
155
|
+
-I, --include-ignored
|
|
156
156
|
check files even if they match a gitignore pattern
|
|
157
157
|
-s STR, --string STR string to parse instead of files
|
|
158
158
|
|
|
@@ -184,7 +184,7 @@ ensure your installation has registered `docsig`
|
|
|
184
184
|
.. code-block:: console
|
|
185
185
|
|
|
186
186
|
$ flake8 --version
|
|
187
|
-
7.3.0 (docsig: 0.80.
|
|
187
|
+
7.3.0 (docsig: 0.80.1, mccabe: 0.7.0, pycodestyle: 2.14.0, pyflakes: 3.4.0) CPython 3.10.19 on Darwin
|
|
188
188
|
|
|
189
189
|
And now use `flake8` to lint your files
|
|
190
190
|
|
|
@@ -270,7 +270,7 @@ Standalone
|
|
|
270
270
|
|
|
271
271
|
repos:
|
|
272
272
|
- repo: https://github.com/jshwi/docsig
|
|
273
|
-
rev: v0.80.
|
|
273
|
+
rev: v0.80.1
|
|
274
274
|
hooks:
|
|
275
275
|
- id: docsig
|
|
276
276
|
args:
|
|
@@ -289,7 +289,7 @@ or integrated with ``flake8``
|
|
|
289
289
|
hooks:
|
|
290
290
|
- id: flake8
|
|
291
291
|
additional_dependencies:
|
|
292
|
-
- docsig==0.80.
|
|
292
|
+
- docsig==0.80.1
|
|
293
293
|
args:
|
|
294
294
|
- "--sig-check-class"
|
|
295
295
|
- "--sig-check-dunders"
|
|
@@ -87,7 +87,7 @@ Commandline
|
|
|
87
87
|
[--check-property-returns] [--check-protected]
|
|
88
88
|
[--check-protected-class-methods] [--ignore-args] [--ignore-kwargs]
|
|
89
89
|
[--ignore-no-params] [-d LIST] [-t LIST] [-e PATTERN] [-E PATH [PATH ...]]
|
|
90
|
-
[-
|
|
90
|
+
[-I] [-s STR]
|
|
91
91
|
[path [path ...]]
|
|
92
92
|
|
|
93
93
|
Check signature params for proper documentation
|
|
@@ -123,7 +123,7 @@ Commandline
|
|
|
123
123
|
regular expression of files or dirs to exclude from checks
|
|
124
124
|
-E PATH [PATH ...], --excludes PATH [PATH ...]
|
|
125
125
|
path glob patterns to exclude from checks
|
|
126
|
-
-
|
|
126
|
+
-I, --include-ignored
|
|
127
127
|
check files even if they match a gitignore pattern
|
|
128
128
|
-s STR, --string STR string to parse instead of files
|
|
129
129
|
|
|
@@ -155,7 +155,7 @@ ensure your installation has registered `docsig`
|
|
|
155
155
|
.. code-block:: console
|
|
156
156
|
|
|
157
157
|
$ flake8 --version
|
|
158
|
-
7.3.0 (docsig: 0.80.
|
|
158
|
+
7.3.0 (docsig: 0.80.1, mccabe: 0.7.0, pycodestyle: 2.14.0, pyflakes: 3.4.0) CPython 3.10.19 on Darwin
|
|
159
159
|
|
|
160
160
|
And now use `flake8` to lint your files
|
|
161
161
|
|
|
@@ -241,7 +241,7 @@ Standalone
|
|
|
241
241
|
|
|
242
242
|
repos:
|
|
243
243
|
- repo: https://github.com/jshwi/docsig
|
|
244
|
-
rev: v0.80.
|
|
244
|
+
rev: v0.80.1
|
|
245
245
|
hooks:
|
|
246
246
|
- id: docsig
|
|
247
247
|
args:
|
|
@@ -260,7 +260,7 @@ or integrated with ``flake8``
|
|
|
260
260
|
hooks:
|
|
261
261
|
- id: flake8
|
|
262
262
|
additional_dependencies:
|
|
263
|
-
- docsig==0.80.
|
|
263
|
+
- docsig==0.80.1
|
|
264
264
|
args:
|
|
265
265
|
- "--sig-check-class"
|
|
266
266
|
- "--sig-check-dunders"
|
|
@@ -16,7 +16,7 @@ from pathlib import Path as _Path
|
|
|
16
16
|
import tomli as _tomli
|
|
17
17
|
|
|
18
18
|
from ._version import __version__
|
|
19
|
-
from .messages import Messages
|
|
19
|
+
from .messages import Messages
|
|
20
20
|
|
|
21
21
|
PYPROJECT_TOML = "pyproject.toml"
|
|
22
22
|
|
|
@@ -133,45 +133,101 @@ def parse_args(args: _t.Sequence[str] | None = None) -> _argparse.Namespace:
|
|
|
133
133
|
help="increase output verbosity",
|
|
134
134
|
)
|
|
135
135
|
group = parser.add_mutually_exclusive_group(required=False)
|
|
136
|
+
group.add_argument(
|
|
137
|
+
"-c",
|
|
138
|
+
action="store_true",
|
|
139
|
+
help=_argparse.SUPPRESS,
|
|
140
|
+
dest="check_class",
|
|
141
|
+
)
|
|
136
142
|
group.add_argument(
|
|
137
143
|
"--check-class",
|
|
138
144
|
action="store_true",
|
|
139
145
|
help="check class docstrings",
|
|
146
|
+
dest="check_class",
|
|
147
|
+
)
|
|
148
|
+
group.add_argument(
|
|
149
|
+
"-C",
|
|
150
|
+
action="store_true",
|
|
151
|
+
help=_argparse.SUPPRESS,
|
|
152
|
+
dest="check_class_constructor",
|
|
140
153
|
)
|
|
141
154
|
group.add_argument(
|
|
142
155
|
"--check-class-constructor",
|
|
143
156
|
action="store_true",
|
|
144
157
|
help="check __init__ methods",
|
|
158
|
+
dest="check_class_constructor",
|
|
159
|
+
)
|
|
160
|
+
parser.add_argument(
|
|
161
|
+
"-D",
|
|
162
|
+
action="store_true",
|
|
163
|
+
help=_argparse.SUPPRESS,
|
|
164
|
+
dest="check_dunders",
|
|
145
165
|
)
|
|
146
166
|
parser.add_argument(
|
|
147
167
|
"--check-dunders",
|
|
148
168
|
action="store_true",
|
|
149
169
|
help="check dunder methods",
|
|
170
|
+
dest="check_dunders",
|
|
171
|
+
)
|
|
172
|
+
parser.add_argument(
|
|
173
|
+
"-N",
|
|
174
|
+
action="store_true",
|
|
175
|
+
help=_argparse.SUPPRESS,
|
|
176
|
+
dest="check_nested",
|
|
150
177
|
)
|
|
151
178
|
parser.add_argument(
|
|
152
179
|
"--check-nested",
|
|
153
180
|
action="store_true",
|
|
154
181
|
help="check nested functions and classes",
|
|
182
|
+
dest="check_nested",
|
|
183
|
+
)
|
|
184
|
+
parser.add_argument(
|
|
185
|
+
"-o",
|
|
186
|
+
action="store_true",
|
|
187
|
+
help=_argparse.SUPPRESS,
|
|
188
|
+
dest="check_overridden",
|
|
155
189
|
)
|
|
156
190
|
parser.add_argument(
|
|
157
191
|
"--check-overridden",
|
|
158
192
|
action="store_true",
|
|
159
193
|
help="check overridden methods",
|
|
194
|
+
dest="check_overridden",
|
|
195
|
+
)
|
|
196
|
+
parser.add_argument(
|
|
197
|
+
"-P",
|
|
198
|
+
action="store_true",
|
|
199
|
+
help=_argparse.SUPPRESS,
|
|
200
|
+
dest="check_property_returns",
|
|
160
201
|
)
|
|
161
202
|
parser.add_argument(
|
|
162
203
|
"--check-property-returns",
|
|
163
204
|
action="store_true",
|
|
164
205
|
help="check property return values",
|
|
206
|
+
dest="check_property_returns",
|
|
207
|
+
)
|
|
208
|
+
parser.add_argument(
|
|
209
|
+
"-p",
|
|
210
|
+
action="store_true",
|
|
211
|
+
help=_argparse.SUPPRESS,
|
|
212
|
+
dest="check_protected",
|
|
165
213
|
)
|
|
166
214
|
parser.add_argument(
|
|
167
215
|
"--check-protected",
|
|
168
216
|
action="store_true",
|
|
169
217
|
help="check protected functions and classes",
|
|
218
|
+
dest="check_protected",
|
|
219
|
+
)
|
|
220
|
+
parser.add_argument(
|
|
221
|
+
"-m",
|
|
222
|
+
action="store_true",
|
|
223
|
+
help=_argparse.SUPPRESS,
|
|
224
|
+
dest="check_protected_class_methods",
|
|
170
225
|
)
|
|
171
226
|
parser.add_argument(
|
|
172
227
|
"--check-protected-class-methods",
|
|
173
228
|
action="store_true",
|
|
174
229
|
help="check public methods belonging to protected classes",
|
|
230
|
+
dest="check_protected_class_methods",
|
|
175
231
|
)
|
|
176
232
|
parser.add_argument(
|
|
177
233
|
"--ignore-args",
|
|
@@ -183,10 +239,22 @@ def parse_args(args: _t.Sequence[str] | None = None) -> _argparse.Namespace:
|
|
|
183
239
|
action="store_true",
|
|
184
240
|
help="ignore kwargs prefixed with two asterisks",
|
|
185
241
|
)
|
|
242
|
+
parser.add_argument(
|
|
243
|
+
"-i",
|
|
244
|
+
action="store_true",
|
|
245
|
+
help=_argparse.SUPPRESS,
|
|
246
|
+
dest="ignore_no_params",
|
|
247
|
+
)
|
|
186
248
|
parser.add_argument(
|
|
187
249
|
"--ignore-no-params",
|
|
188
250
|
action="store_true",
|
|
189
251
|
help="ignore docstrings where parameters are not documented",
|
|
252
|
+
dest="ignore_no_params",
|
|
253
|
+
)
|
|
254
|
+
parser.add_argument(
|
|
255
|
+
"--ignore-typechecker",
|
|
256
|
+
action="store_true",
|
|
257
|
+
help=_argparse.SUPPRESS,
|
|
190
258
|
)
|
|
191
259
|
parser.add_argument(
|
|
192
260
|
"-d",
|
|
@@ -220,7 +288,7 @@ def parse_args(args: _t.Sequence[str] | None = None) -> _argparse.Namespace:
|
|
|
220
288
|
help="path glob patterns to exclude from checks",
|
|
221
289
|
)
|
|
222
290
|
parser.add_argument(
|
|
223
|
-
"-
|
|
291
|
+
"-I",
|
|
224
292
|
"--include-ignored",
|
|
225
293
|
action="store_true",
|
|
226
294
|
help="check files even if they match a gitignore pattern",
|
|
@@ -287,11 +355,11 @@ class Config:
|
|
|
287
355
|
takes a single config object instead of many parameters.
|
|
288
356
|
"""
|
|
289
357
|
|
|
290
|
-
check: Check
|
|
291
|
-
ignore: Ignore
|
|
292
|
-
target:
|
|
293
|
-
disable:
|
|
294
|
-
exclude: str
|
|
358
|
+
check: Check = _field(default_factory=Check)
|
|
359
|
+
ignore: Ignore = _field(default_factory=Ignore)
|
|
360
|
+
target: Messages = _field(default_factory=Messages)
|
|
361
|
+
disable: Messages = _field(default_factory=Messages)
|
|
362
|
+
exclude: list[str] = _field(default_factory=list)
|
|
295
363
|
excludes: list[str] | None = None
|
|
296
364
|
list_checks: bool = False
|
|
297
365
|
include_ignored: bool = False
|
|
@@ -9,6 +9,7 @@ import logging as _logging
|
|
|
9
9
|
import os as _os
|
|
10
10
|
import sys as _sys
|
|
11
11
|
import typing as _t
|
|
12
|
+
import warnings as _warnings
|
|
12
13
|
from pathlib import Path as _Path
|
|
13
14
|
|
|
14
15
|
import astroid as _ast
|
|
@@ -27,8 +28,28 @@ from ._report import Failure as _Failure
|
|
|
27
28
|
from ._report import Failures as _Failures
|
|
28
29
|
from ._utils import print_checks as _print_checks
|
|
29
30
|
from .messages import TEMPLATE as _TEMPLATE
|
|
31
|
+
from .messages import E as _E
|
|
30
32
|
from .messages import Messages as _Messages
|
|
31
33
|
|
|
34
|
+
_DEFAULT_EXCLUDES = """\
|
|
35
|
+
(?x)^(
|
|
36
|
+
|\\.?venv[\\\\/].*
|
|
37
|
+
|\\.git[\\\\/].*
|
|
38
|
+
|\\.hg[\\\\/].*
|
|
39
|
+
|\\.idea[\\\\/].*
|
|
40
|
+
|\\.mypy_cache[\\\\/].*
|
|
41
|
+
|\\.nox[\\\\/].*
|
|
42
|
+
|\\.pytest_cache[\\\\/].*
|
|
43
|
+
|\\.svn[\\\\/].*
|
|
44
|
+
|\\.tox[\\\\/].*
|
|
45
|
+
|\\.vscode[\\\\/].*
|
|
46
|
+
|_?build[\\\\/].*
|
|
47
|
+
|.*[\\\\/]__pycache__[\\\\/].*
|
|
48
|
+
|dist[\\\\/].*
|
|
49
|
+
|node_modules[\\\\/].*
|
|
50
|
+
)$
|
|
51
|
+
"""
|
|
52
|
+
|
|
32
53
|
|
|
33
54
|
def setup_logger(verbose: bool) -> None:
|
|
34
55
|
"""Setup docsig logger.
|
|
@@ -96,17 +117,10 @@ def _run_check(
|
|
|
96
117
|
_run_check(func, child, config, failures)
|
|
97
118
|
|
|
98
119
|
|
|
99
|
-
def _derive_module_name(file_path: str | _Path) -> str:
|
|
100
|
-
converted = _os.path.splitext(str(file_path))[0]
|
|
101
|
-
converted = converted.replace(_os.sep, ".")
|
|
102
|
-
converted = converted.replace("-", "_")
|
|
103
|
-
return converted
|
|
104
|
-
|
|
105
|
-
|
|
106
120
|
def _from_file(path: _Path, config: _Config) -> _Parent:
|
|
107
121
|
try:
|
|
108
122
|
code = path.read_text(encoding="utf-8")
|
|
109
|
-
parent =
|
|
123
|
+
parent = _from_str(
|
|
110
124
|
context={
|
|
111
125
|
"code": code,
|
|
112
126
|
"module_name": _derive_module_name(path),
|
|
@@ -126,7 +140,7 @@ def _from_file(path: _Path, config: _Config) -> _Parent:
|
|
|
126
140
|
return parent
|
|
127
141
|
|
|
128
142
|
|
|
129
|
-
def
|
|
143
|
+
def _from_str(
|
|
130
144
|
context: dict[str, _t.Any],
|
|
131
145
|
config: _Config,
|
|
132
146
|
path: _Path | None = None,
|
|
@@ -150,8 +164,8 @@ def _parse_from_string(
|
|
|
150
164
|
return parent
|
|
151
165
|
|
|
152
166
|
|
|
153
|
-
def
|
|
154
|
-
failures
|
|
167
|
+
def _get_failures(module: _Parent, config: _Config) -> _Failures:
|
|
168
|
+
failures = _Failures()
|
|
155
169
|
for top_level in module.children:
|
|
156
170
|
if (
|
|
157
171
|
not top_level.isprotected
|
|
@@ -192,6 +206,56 @@ def _report(
|
|
|
192
206
|
return max(retcodes)
|
|
193
207
|
|
|
194
208
|
|
|
209
|
+
def _run_docsig(
|
|
210
|
+
*path: str | _Path,
|
|
211
|
+
string: str | None = None,
|
|
212
|
+
config: _Config,
|
|
213
|
+
) -> int:
|
|
214
|
+
setup_logger(config.verbose)
|
|
215
|
+
if config.list_checks:
|
|
216
|
+
return int(bool(_print_checks())) # type: ignore
|
|
217
|
+
|
|
218
|
+
if string is None:
|
|
219
|
+
retcodes = [0]
|
|
220
|
+
paths = _Paths(
|
|
221
|
+
*path,
|
|
222
|
+
patterns=config.exclude,
|
|
223
|
+
excludes=config.excludes,
|
|
224
|
+
include_ignored=config.include_ignored,
|
|
225
|
+
)
|
|
226
|
+
for path_ in paths:
|
|
227
|
+
failures = runner(path_, config)
|
|
228
|
+
retcodes.append(_report(failures, config, str(path_)))
|
|
229
|
+
|
|
230
|
+
return max(retcodes)
|
|
231
|
+
|
|
232
|
+
module = _from_str({"code": string}, config)
|
|
233
|
+
failures = _get_failures(module, config)
|
|
234
|
+
return _report(failures, config)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def handle_deprecations(
|
|
238
|
+
ignore_typechecker: bool,
|
|
239
|
+
disable: list,
|
|
240
|
+
messages: list,
|
|
241
|
+
stacklevel: int,
|
|
242
|
+
) -> None:
|
|
243
|
+
"""Warn for deprecated arguments.
|
|
244
|
+
|
|
245
|
+
:param ignore_typechecker: Whether using or not.
|
|
246
|
+
:param disable: List to add messages to.
|
|
247
|
+
:param messages: Messages.
|
|
248
|
+
:param stacklevel: Warning stacklevel.
|
|
249
|
+
"""
|
|
250
|
+
if ignore_typechecker:
|
|
251
|
+
_warnings.warn(
|
|
252
|
+
"ignore-typechecker is deprecated, use disable for SIG5xx instead",
|
|
253
|
+
category=FutureWarning,
|
|
254
|
+
stacklevel=stacklevel,
|
|
255
|
+
)
|
|
256
|
+
disable.extend(messages)
|
|
257
|
+
|
|
258
|
+
|
|
195
259
|
def runner(path: _Path, config: _Config) -> _Failures:
|
|
196
260
|
"""Per path runner.
|
|
197
261
|
|
|
@@ -200,7 +264,7 @@ def runner(path: _Path, config: _Config) -> _Failures:
|
|
|
200
264
|
:return: Exit status for whether the test failed or not.
|
|
201
265
|
"""
|
|
202
266
|
module = _from_file(path, config)
|
|
203
|
-
return
|
|
267
|
+
return _get_failures(module, config)
|
|
204
268
|
|
|
205
269
|
|
|
206
270
|
@_decorators.parse_msgs
|
|
@@ -221,6 +285,7 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
221
285
|
ignore_no_params: bool = False,
|
|
222
286
|
ignore_args: bool = False,
|
|
223
287
|
ignore_kwargs: bool = False,
|
|
288
|
+
ignore_typechecker: bool = False, # deprecated
|
|
224
289
|
no_ansi: bool = False,
|
|
225
290
|
verbose: bool = False,
|
|
226
291
|
target: _Messages | None = None,
|
|
@@ -256,6 +321,7 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
256
321
|
documented
|
|
257
322
|
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
258
323
|
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
324
|
+
:param ignore_typechecker: Ignore checking return values.
|
|
259
325
|
:param no_ansi: Disable ANSI output.
|
|
260
326
|
:param verbose: Increase output verbosity.
|
|
261
327
|
:param target: List of errors to target.
|
|
@@ -265,6 +331,24 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
265
331
|
:param excludes: Files or dirs to exclude from checks.
|
|
266
332
|
:return: Exit status for whether a test failed or not.
|
|
267
333
|
"""
|
|
334
|
+
disable = disable or _Messages()
|
|
335
|
+
handle_deprecations(
|
|
336
|
+
ignore_typechecker,
|
|
337
|
+
disable,
|
|
338
|
+
[
|
|
339
|
+
_E[501],
|
|
340
|
+
_E[502],
|
|
341
|
+
_E[503],
|
|
342
|
+
_E[504],
|
|
343
|
+
_E[505],
|
|
344
|
+
_E[506],
|
|
345
|
+
],
|
|
346
|
+
stacklevel=5,
|
|
347
|
+
)
|
|
348
|
+
exclude_ = [_DEFAULT_EXCLUDES]
|
|
349
|
+
if exclude is not None:
|
|
350
|
+
exclude_.append(exclude)
|
|
351
|
+
|
|
268
352
|
check = _Check(
|
|
269
353
|
class_=check_class,
|
|
270
354
|
class_constructor=check_class_constructor,
|
|
@@ -287,30 +371,16 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
287
371
|
ignore=ignore,
|
|
288
372
|
no_ansi=no_ansi,
|
|
289
373
|
verbose=verbose,
|
|
290
|
-
target=target or
|
|
291
|
-
disable=disable
|
|
292
|
-
exclude=
|
|
374
|
+
target=target or _Messages(),
|
|
375
|
+
disable=disable,
|
|
376
|
+
exclude=exclude_,
|
|
293
377
|
excludes=excludes,
|
|
294
378
|
)
|
|
295
|
-
|
|
296
|
-
if config.list_checks:
|
|
297
|
-
return int(bool(_print_checks())) # type: ignore
|
|
379
|
+
return _run_docsig(*path, string=string, config=config)
|
|
298
380
|
|
|
299
|
-
if string:
|
|
300
|
-
module = _parse_from_string({"code": string}, config)
|
|
301
|
-
failures = _run_checks(module, config)
|
|
302
|
-
return _report(failures, config)
|
|
303
381
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
include_ignored=config.include_ignored,
|
|
310
|
-
)
|
|
311
|
-
for path_ in paths:
|
|
312
|
-
failures = runner(path_, config)
|
|
313
|
-
retcode = _report(failures, config, str(path_))
|
|
314
|
-
retcodes.append(retcode)
|
|
315
|
-
|
|
316
|
-
return max(retcodes)
|
|
382
|
+
def _derive_module_name(file_path: str | _Path) -> str:
|
|
383
|
+
converted = _os.path.splitext(str(file_path))[0]
|
|
384
|
+
converted = converted.replace(_os.sep, ".")
|
|
385
|
+
converted = converted.replace("-", "_")
|
|
386
|
+
return converted
|
|
@@ -12,8 +12,6 @@ from io import StringIO as _StringIO
|
|
|
12
12
|
from .messages import E as _E
|
|
13
13
|
from .messages import Messages as _Messages
|
|
14
14
|
|
|
15
|
-
Comments: _t.TypeAlias = _t.List["Comment"]
|
|
16
|
-
|
|
17
15
|
|
|
18
16
|
class Comment(_Messages):
|
|
19
17
|
"""Represents a comment directive.
|
|
@@ -74,6 +72,10 @@ class Comment(_Messages):
|
|
|
74
72
|
return None
|
|
75
73
|
|
|
76
74
|
|
|
75
|
+
class Comments(_t.List[Comment]):
|
|
76
|
+
"""List of comments."""
|
|
77
|
+
|
|
78
|
+
|
|
77
79
|
class Directives(_t.Dict[int, _t.Tuple[Comments, _Messages]]):
|
|
78
80
|
"""Data for directives:
|
|
79
81
|
|
|
@@ -100,7 +102,7 @@ class Directives(_t.Dict[int, _t.Tuple[Comments, _Messages]]):
|
|
|
100
102
|
"""
|
|
101
103
|
directives = cls()
|
|
102
104
|
fin = _StringIO(text)
|
|
103
|
-
comments
|
|
105
|
+
comments = Comments()
|
|
104
106
|
for line in _tokenize.generate_tokens(fin.readline):
|
|
105
107
|
# do nothing for these line types
|
|
106
108
|
if line.type in (_tokenize.NAME, _tokenize.OP, _tokenize.DEDENT):
|
|
@@ -110,8 +112,8 @@ class Directives(_t.Dict[int, _t.Tuple[Comments, _Messages]]):
|
|
|
110
112
|
# scope, but do not update the global comments and messages
|
|
111
113
|
# unless it is confirmed that the comment is a module level
|
|
112
114
|
# directive
|
|
113
|
-
scoped_comments
|
|
114
|
-
scoped_messages =
|
|
115
|
+
scoped_comments = Comments(comments)
|
|
116
|
+
scoped_messages = _Messages(messages)
|
|
115
117
|
lineno, col = line.start
|
|
116
118
|
if line.type == _tokenize.COMMENT:
|
|
117
119
|
comment = Comment.parse(line.string, col)
|
|
@@ -120,7 +122,7 @@ class Directives(_t.Dict[int, _t.Tuple[Comments, _Messages]]):
|
|
|
120
122
|
if comment.disable:
|
|
121
123
|
scoped_messages.extend(comment)
|
|
122
124
|
elif comment.enable:
|
|
123
|
-
scoped_messages =
|
|
125
|
+
scoped_messages = _Messages(
|
|
124
126
|
i for i in messages if i not in comment
|
|
125
127
|
)
|
|
126
128
|
|
|
@@ -16,24 +16,6 @@ from pathspec.patterns import GitWildMatchPattern as _GitWildMatchPattern
|
|
|
16
16
|
from wcmatch.pathlib import Path as _WcPath
|
|
17
17
|
|
|
18
18
|
FILE_INFO = "%s: %s"
|
|
19
|
-
_DEFAULT_EXCLUDES = """\
|
|
20
|
-
(?x)^(
|
|
21
|
-
|\\.?venv[\\\\/].*
|
|
22
|
-
|\\.git[\\\\/].*
|
|
23
|
-
|\\.hg[\\\\/].*
|
|
24
|
-
|\\.idea[\\\\/].*
|
|
25
|
-
|\\.mypy_cache[\\\\/].*
|
|
26
|
-
|\\.nox[\\\\/].*
|
|
27
|
-
|\\.pytest_cache[\\\\/].*
|
|
28
|
-
|\\.svn[\\\\/].*
|
|
29
|
-
|\\.tox[\\\\/].*
|
|
30
|
-
|\\.vscode[\\\\/].*
|
|
31
|
-
|_?build[\\\\/].*
|
|
32
|
-
|.*[\\\\/]__pycache__[\\\\/].*
|
|
33
|
-
|dist[\\\\/].*
|
|
34
|
-
|node_modules[\\\\/].*
|
|
35
|
-
)$
|
|
36
|
-
"""
|
|
37
19
|
|
|
38
20
|
|
|
39
21
|
class _Gitignore(_PathSpec):
|
|
@@ -99,15 +81,13 @@ class Paths(_t.List[_Path]):
|
|
|
99
81
|
def __init__(
|
|
100
82
|
self,
|
|
101
83
|
*paths: _Path | str,
|
|
102
|
-
patterns: str
|
|
84
|
+
patterns: list[str],
|
|
103
85
|
excludes: list[str] | None = None,
|
|
104
86
|
include_ignored: bool = False,
|
|
105
87
|
) -> None:
|
|
106
88
|
super().__init__()
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
exclude.append(patterns)
|
|
110
|
-
|
|
89
|
+
self._patterns = patterns
|
|
90
|
+
self._excludes = excludes or []
|
|
111
91
|
self._include_ignored = include_ignored
|
|
112
92
|
self._gitignore = _Gitignore()
|
|
113
93
|
self._logger = _logging.getLogger(__package__)
|
|
@@ -116,8 +96,8 @@ class Paths(_t.List[_Path]):
|
|
|
116
96
|
|
|
117
97
|
for path in list(self):
|
|
118
98
|
if str(path) != "." and (
|
|
119
|
-
any(_re.match(i, str(path)) for i in
|
|
120
|
-
or any(_glob(path, i) for i in
|
|
99
|
+
any(_re.match(i, str(path)) for i in self._patterns)
|
|
100
|
+
or any(_glob(path, i) for i in self._excludes)
|
|
121
101
|
):
|
|
122
102
|
self._logger.debug(
|
|
123
103
|
FILE_INFO,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
docsig._main
|
|
3
|
+
============
|
|
4
|
+
|
|
5
|
+
Contains package entry point.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations as _
|
|
9
|
+
|
|
10
|
+
import sys as _sys
|
|
11
|
+
import warnings as _warnings
|
|
12
|
+
|
|
13
|
+
from ._config import parse_args as _parse_args
|
|
14
|
+
from ._core import docsig as _docsig
|
|
15
|
+
from ._hooks import excepthook as _excepthook
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _warn_on_deprecated_short_flags() -> None:
|
|
19
|
+
deprecated_short_flags = {
|
|
20
|
+
"-c": "--check-class",
|
|
21
|
+
"-C": "--check-class-constructor",
|
|
22
|
+
"-D": "--check-dunders",
|
|
23
|
+
"-m": "--check-protected-class-methods",
|
|
24
|
+
"-N": "--check-nested",
|
|
25
|
+
"-o": "--check-overridden",
|
|
26
|
+
"-p": "--check-protected",
|
|
27
|
+
"-P": "--check-property-returns",
|
|
28
|
+
"-i": "--ignore-no-params",
|
|
29
|
+
}
|
|
30
|
+
raw_args = _sys.argv[1:]
|
|
31
|
+
expanded_flags = []
|
|
32
|
+
for arg in raw_args:
|
|
33
|
+
if arg.startswith("--") or not arg.startswith("-") or arg == "-":
|
|
34
|
+
expanded_flags.append(arg)
|
|
35
|
+
elif len(arg) > 2:
|
|
36
|
+
expanded_flags.extend([f"-{ch}" for ch in arg[1:]])
|
|
37
|
+
else:
|
|
38
|
+
expanded_flags.append(arg)
|
|
39
|
+
|
|
40
|
+
used_flags = set(expanded_flags)
|
|
41
|
+
for short, long in deprecated_short_flags.items():
|
|
42
|
+
if short in used_flags:
|
|
43
|
+
_warnings.warn(
|
|
44
|
+
f"short option '{short}' is deprecated, use '{long}' instead",
|
|
45
|
+
category=FutureWarning,
|
|
46
|
+
stacklevel=2,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def main() -> str | int:
|
|
51
|
+
"""Main function for package.
|
|
52
|
+
|
|
53
|
+
Collect config and arguments for the commandline.
|
|
54
|
+
|
|
55
|
+
:return: Exit status for whether the test failed or not.
|
|
56
|
+
"""
|
|
57
|
+
_warn_on_deprecated_short_flags()
|
|
58
|
+
a = _parse_args()
|
|
59
|
+
_excepthook(a.no_ansi)
|
|
60
|
+
kwargs = vars(a)
|
|
61
|
+
path = kwargs.pop("path")
|
|
62
|
+
return _docsig(*path, **kwargs)
|
|
@@ -19,10 +19,6 @@ from ._stub import RetType as _RetType
|
|
|
19
19
|
from ._stub import Signature as _Signature
|
|
20
20
|
from .messages import Messages as _Messages
|
|
21
21
|
|
|
22
|
-
_Imports: _t.TypeAlias = dict[str, str]
|
|
23
|
-
_Overloads: _t.TypeAlias = _t.Dict[str, "Function"]
|
|
24
|
-
_Children: _t.TypeAlias = _t.List[_t.Union["Parent", "Function"]]
|
|
25
|
-
|
|
26
22
|
|
|
27
23
|
class Error(_Enum):
|
|
28
24
|
"""Represents an unrecoverable error."""
|
|
@@ -31,6 +27,10 @@ class Error(_Enum):
|
|
|
31
27
|
UNICODE = 2
|
|
32
28
|
|
|
33
29
|
|
|
30
|
+
class _Imports(_t.Dict[str, str]):
|
|
31
|
+
"""Represents python imports."""
|
|
32
|
+
|
|
33
|
+
|
|
34
34
|
class Parent: # pylint: disable=too-many-instance-attributes
|
|
35
35
|
"""Represents an object that contains functions or methods.
|
|
36
36
|
|
|
@@ -66,21 +66,20 @@ class Parent: # pylint: disable=too-many-instance-attributes
|
|
|
66
66
|
error: Error | None = None,
|
|
67
67
|
) -> None:
|
|
68
68
|
super().__init__()
|
|
69
|
+
self._name = "module"
|
|
69
70
|
self._error = error
|
|
70
|
-
self._directives = directives or _Directives()
|
|
71
71
|
self._ignore_args = ignore_args
|
|
72
72
|
self._ignore_kwargs = ignore_kwargs
|
|
73
73
|
self._check_class_constructor = check_class_constructor
|
|
74
|
-
self._children
|
|
75
|
-
self._imports
|
|
76
|
-
self._overloads
|
|
74
|
+
self._children = _Children()
|
|
75
|
+
self._imports = imports or _Imports()
|
|
76
|
+
self._overloads = _Overloads()
|
|
77
77
|
if node is None:
|
|
78
|
-
self._name = "module"
|
|
79
78
|
if not isinstance(self, Function) and error is not None:
|
|
80
79
|
self._children.append(Function(path, error=error))
|
|
81
80
|
else:
|
|
82
81
|
self._name = node.name
|
|
83
|
-
self._parse_ast(node, path)
|
|
82
|
+
self._parse_ast(node, directives or _Directives(), path)
|
|
84
83
|
|
|
85
84
|
def _parse_ast(
|
|
86
85
|
self,
|
|
@@ -90,20 +89,21 @@ class Parent: # pylint: disable=too-many-instance-attributes
|
|
|
90
89
|
| _ast.nodes.FunctionDef
|
|
91
90
|
| _ast.nodes.NodeNG
|
|
92
91
|
),
|
|
92
|
+
directives: _Directives,
|
|
93
93
|
path: _Path | None = None,
|
|
94
94
|
) -> None:
|
|
95
95
|
# need to keep track of `comments` as, even though they are
|
|
96
96
|
# resolved in the directive object, they are needed to notify
|
|
97
97
|
# the user in the case that they are invalid
|
|
98
|
-
parent_comments, parent_disabled =
|
|
98
|
+
parent_comments, parent_disabled = directives.get(
|
|
99
99
|
node.lineno,
|
|
100
|
-
(
|
|
100
|
+
(_Comments(), _Messages()),
|
|
101
101
|
)
|
|
102
102
|
if hasattr(node, "body"):
|
|
103
103
|
for subnode in node.body:
|
|
104
|
-
comments, disabled =
|
|
104
|
+
comments, disabled = directives.get(
|
|
105
105
|
subnode.lineno,
|
|
106
|
-
(
|
|
106
|
+
(_Comments(), _Messages()),
|
|
107
107
|
)
|
|
108
108
|
comments.extend(parent_comments)
|
|
109
109
|
disabled.extend(parent_disabled)
|
|
@@ -118,7 +118,7 @@ class Parent: # pylint: disable=too-many-instance-attributes
|
|
|
118
118
|
func = Function(
|
|
119
119
|
subnode,
|
|
120
120
|
comments,
|
|
121
|
-
|
|
121
|
+
directives,
|
|
122
122
|
disabled,
|
|
123
123
|
path,
|
|
124
124
|
self._ignore_args,
|
|
@@ -144,7 +144,7 @@ class Parent: # pylint: disable=too-many-instance-attributes
|
|
|
144
144
|
self._children.append(
|
|
145
145
|
Parent(
|
|
146
146
|
subnode,
|
|
147
|
-
|
|
147
|
+
directives,
|
|
148
148
|
path,
|
|
149
149
|
self._ignore_args,
|
|
150
150
|
self._ignore_kwargs,
|
|
@@ -153,7 +153,7 @@ class Parent: # pylint: disable=too-many-instance-attributes
|
|
|
153
153
|
),
|
|
154
154
|
)
|
|
155
155
|
else:
|
|
156
|
-
self._parse_ast(subnode, path)
|
|
156
|
+
self._parse_ast(subnode, directives, path)
|
|
157
157
|
|
|
158
158
|
@property
|
|
159
159
|
def isprotected(self) -> bool:
|
|
@@ -211,8 +211,8 @@ class Function(Parent): # pylint: disable=too-many-instance-attributes
|
|
|
211
211
|
check_class_constructor,
|
|
212
212
|
imports,
|
|
213
213
|
)
|
|
214
|
-
self._comments = comments or
|
|
215
|
-
self._messages = messages or
|
|
214
|
+
self._comments = comments or _Comments()
|
|
215
|
+
self._messages = messages or _Messages()
|
|
216
216
|
self._parent = None
|
|
217
217
|
self._decorators = None
|
|
218
218
|
self._signature = _Signature()
|
|
@@ -366,3 +366,11 @@ class Function(Parent): # pylint: disable=too-many-instance-attributes
|
|
|
366
366
|
:param rettype: The return type of the overloaded signature.
|
|
367
367
|
"""
|
|
368
368
|
self._signature.overload(rettype)
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class _Overloads(_t.Dict[str, Function]):
|
|
372
|
+
"""Represents overloaded methods."""
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class _Children(_t.List[_t.Union[Parent, Function]]):
|
|
376
|
+
"""Represents children of an object."""
|
|
@@ -18,6 +18,7 @@ from ._stub import Param as _Param
|
|
|
18
18
|
from ._stub import Params as _Params
|
|
19
19
|
from ._stub import RetType as _RetType
|
|
20
20
|
from ._utils import almost_equal as _almost_equal
|
|
21
|
+
from ._utils import has_bad_return as _has_bad_return
|
|
21
22
|
from ._utils import sentence_tokenizer as _sentence_tokenizer
|
|
22
23
|
from .messages import E as _E
|
|
23
24
|
from .messages import Message as _Message
|
|
@@ -27,9 +28,6 @@ _MIN_MATCH = 0.8
|
|
|
27
28
|
_MAX_MATCH = 1.0
|
|
28
29
|
|
|
29
30
|
|
|
30
|
-
Failures: _t.TypeAlias = _t.List["Failure"]
|
|
31
|
-
|
|
32
|
-
|
|
33
31
|
class Failed(_t.NamedTuple):
|
|
34
32
|
"""Report info object."""
|
|
35
33
|
|
|
@@ -58,9 +56,19 @@ class Failure(_t.List[Failed]):
|
|
|
58
56
|
super().__init__()
|
|
59
57
|
self._retcode = 0
|
|
60
58
|
self._func = func
|
|
59
|
+
self._docstring_len = len(self._func.docstring.args)
|
|
61
60
|
if target:
|
|
62
61
|
self._func.messages.extend(i for i in _E.all if i not in target)
|
|
63
62
|
|
|
63
|
+
self._name = self._func.name
|
|
64
|
+
if (
|
|
65
|
+
self._func.parent is not None
|
|
66
|
+
and self._func.parent.name
|
|
67
|
+
and not isinstance(self._func.parent, _scoped_nodes.Module)
|
|
68
|
+
):
|
|
69
|
+
self._name = f"{self._func.parent.name}.{self._func.name}"
|
|
70
|
+
|
|
71
|
+
self._check_property_returns = check_property_returns
|
|
64
72
|
if self._func.error is not None:
|
|
65
73
|
self._sig9xx_error()
|
|
66
74
|
else:
|
|
@@ -75,23 +83,18 @@ class Failure(_t.List[Failed]):
|
|
|
75
83
|
sig = self._func.signature.args.get(index)
|
|
76
84
|
self._sig4xx_parameters(doc, sig)
|
|
77
85
|
|
|
78
|
-
self._sig5xx_returns(
|
|
86
|
+
self._sig5xx_returns()
|
|
79
87
|
|
|
80
88
|
self.sort()
|
|
81
89
|
|
|
82
|
-
def _add(
|
|
83
|
-
self,
|
|
84
|
-
value: _Message,
|
|
85
|
-
hint: bool = False,
|
|
86
|
-
**kwargs: _t.Any,
|
|
87
|
-
) -> None:
|
|
90
|
+
def _add(self, value: _Message, hint: bool = False, **kwargs) -> None:
|
|
88
91
|
self._retcode = 1
|
|
89
92
|
failed = Failed(
|
|
90
|
-
self.
|
|
93
|
+
self._name,
|
|
91
94
|
value.ref,
|
|
92
95
|
value.description.format(**kwargs),
|
|
93
96
|
value.symbolic,
|
|
94
|
-
self.lineno,
|
|
97
|
+
self._func.lineno,
|
|
95
98
|
value.hint if hint else None,
|
|
96
99
|
)
|
|
97
100
|
if value not in self._func.messages and failed not in self:
|
|
@@ -216,9 +219,9 @@ class Failure(_t.List[Failed]):
|
|
|
216
219
|
# bad-closing-token
|
|
217
220
|
self._add(_E[304], token=doc.closing_token, hint=True)
|
|
218
221
|
if doc.description is not None and not all(
|
|
219
|
-
|
|
222
|
+
stripped[0].isupper()
|
|
220
223
|
for i in _sentence_tokenizer(doc.description)
|
|
221
|
-
if i and
|
|
224
|
+
if i and (stripped := i.strip())[0].isalpha()
|
|
222
225
|
):
|
|
223
226
|
# description is not capitalized
|
|
224
227
|
self._add(_E[305])
|
|
@@ -231,7 +234,7 @@ class Failure(_t.List[Failed]):
|
|
|
231
234
|
if (
|
|
232
235
|
sig.name in self._func.docstring.args.names
|
|
233
236
|
or doc.name in self._func.signature.args.names
|
|
234
|
-
) and
|
|
237
|
+
) and self._docstring_len > 1:
|
|
235
238
|
# params-out-of-order
|
|
236
239
|
self._add(_E[402])
|
|
237
240
|
elif (
|
|
@@ -246,9 +249,9 @@ class Failure(_t.List[Failed]):
|
|
|
246
249
|
# param-not-equal-to-arg
|
|
247
250
|
self._add(_E[404])
|
|
248
251
|
|
|
249
|
-
def _sig5xx_returns(self
|
|
252
|
+
def _sig5xx_returns(self) -> None:
|
|
250
253
|
if not self._func.isinit and not (
|
|
251
|
-
self._func.isproperty and not
|
|
254
|
+
self._func.isproperty and not self._check_property_returns
|
|
252
255
|
):
|
|
253
256
|
# no types, cannot know either way
|
|
254
257
|
if self._func.signature.rettype == _RetType.UNTYPED:
|
|
@@ -264,14 +267,9 @@ class Failure(_t.List[Failed]):
|
|
|
264
267
|
# return-type is some, so return should be documented
|
|
265
268
|
elif self._func.signature.returns:
|
|
266
269
|
# return-missing
|
|
267
|
-
lines = str(self._func.docstring.string).splitlines()
|
|
268
270
|
self._add(
|
|
269
271
|
_E[503],
|
|
270
|
-
hint=(
|
|
271
|
-
len(lines) > 1
|
|
272
|
-
and "return" in lines[-1]
|
|
273
|
-
and ":param" not in lines[-1]
|
|
274
|
-
),
|
|
272
|
+
hint=_has_bad_return(str(self._func.docstring.string)),
|
|
275
273
|
)
|
|
276
274
|
elif self._func.docstring.returns:
|
|
277
275
|
# this method is init, so no return should be documented
|
|
@@ -279,7 +277,7 @@ class Failure(_t.List[Failed]):
|
|
|
279
277
|
# class-return-documented
|
|
280
278
|
self._add(_E[504], hint=True)
|
|
281
279
|
# method is property and not set to document property
|
|
282
|
-
elif self._func.isproperty and not
|
|
280
|
+
elif self._func.isproperty and not self._check_property_returns:
|
|
283
281
|
# return-documented-for-property
|
|
284
282
|
self._add(_E[505], hint=True)
|
|
285
283
|
|
|
@@ -294,14 +292,7 @@ class Failure(_t.List[Failed]):
|
|
|
294
292
|
@property
|
|
295
293
|
def name(self) -> str:
|
|
296
294
|
"""Function name."""
|
|
297
|
-
|
|
298
|
-
self._func.parent is not None
|
|
299
|
-
and self._func.parent.name
|
|
300
|
-
and not isinstance(self._func.parent, _scoped_nodes.Module)
|
|
301
|
-
):
|
|
302
|
-
return f"{self._func.parent.name}.{self._func.name}"
|
|
303
|
-
|
|
304
|
-
return self._func.name
|
|
295
|
+
return self._name
|
|
305
296
|
|
|
306
297
|
@property
|
|
307
298
|
def lineno(self) -> int:
|
|
@@ -312,3 +303,7 @@ class Failure(_t.List[Failed]):
|
|
|
312
303
|
def retcode(self) -> int:
|
|
313
304
|
"""How to exit the program."""
|
|
314
305
|
return self._retcode
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class Failures(_t.List[Failure]):
|
|
309
|
+
"""Sequence of failed functions."""
|
|
@@ -80,7 +80,7 @@ class DocType(_Enum):
|
|
|
80
80
|
# todo: consider a parent object that can be used for returns that do
|
|
81
81
|
# todo: not include the name attribute
|
|
82
82
|
class Param:
|
|
83
|
-
"""
|
|
83
|
+
"""A tuple of param types and their names.
|
|
84
84
|
|
|
85
85
|
:param kind: The type of the parameter.
|
|
86
86
|
:param name: The name of the parameter.
|
|
@@ -98,11 +98,11 @@ class Param:
|
|
|
98
98
|
indent: int = 0,
|
|
99
99
|
closing_token: str = ":",
|
|
100
100
|
) -> None:
|
|
101
|
-
self.
|
|
102
|
-
self.
|
|
103
|
-
self.
|
|
104
|
-
self.
|
|
105
|
-
self.
|
|
101
|
+
self.kind = kind
|
|
102
|
+
self.name = name
|
|
103
|
+
self.description = description
|
|
104
|
+
self.indent = indent
|
|
105
|
+
self.closing_token = closing_token
|
|
106
106
|
|
|
107
107
|
def __eq__(self, other: object) -> bool:
|
|
108
108
|
iseq = False
|
|
@@ -123,31 +123,6 @@ class Param:
|
|
|
123
123
|
"""Boolean value for whether this parameter is protected."""
|
|
124
124
|
return str(self.name).startswith("_")
|
|
125
125
|
|
|
126
|
-
@property
|
|
127
|
-
def kind(self) -> DocType:
|
|
128
|
-
"""Type of the param."""
|
|
129
|
-
return self._kind
|
|
130
|
-
|
|
131
|
-
@property
|
|
132
|
-
def name(self) -> str | None:
|
|
133
|
-
"""Name of the param."""
|
|
134
|
-
return self._name
|
|
135
|
-
|
|
136
|
-
@property
|
|
137
|
-
def description(self) -> str | None:
|
|
138
|
-
"""Description of param."""
|
|
139
|
-
return self._description
|
|
140
|
-
|
|
141
|
-
@property
|
|
142
|
-
def indent(self) -> int:
|
|
143
|
-
"""Number of spaces in the indent."""
|
|
144
|
-
return self._indent
|
|
145
|
-
|
|
146
|
-
@property
|
|
147
|
-
def closing_token(self) -> str:
|
|
148
|
-
"""Token used to terminate the param name definition."""
|
|
149
|
-
return self._closing_token
|
|
150
|
-
|
|
151
126
|
|
|
152
127
|
class Params(_t.List[Param]):
|
|
153
128
|
"""A list-like collection of params.
|
|
@@ -54,6 +54,25 @@ def print_checks() -> None:
|
|
|
54
54
|
print(msg.fstring(_TEMPLATE))
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
def has_bad_return(string: str) -> bool:
|
|
58
|
+
"""Search for return documented with poor syntax.
|
|
59
|
+
|
|
60
|
+
Put this here in case the function increases in complexity.
|
|
61
|
+
|
|
62
|
+
Do more than search the docstring for the word return as return
|
|
63
|
+
statements come last, so only search the last line params can also
|
|
64
|
+
come last, so make sure it is not a param declaration.
|
|
65
|
+
|
|
66
|
+
:param string: Docstring to check.
|
|
67
|
+
:return: Boolean value indicating if a function has a bad return
|
|
68
|
+
statement.
|
|
69
|
+
"""
|
|
70
|
+
lines = string.splitlines()
|
|
71
|
+
return (
|
|
72
|
+
len(lines) > 1 and "return" in lines[-1] and ":param" not in lines[-1]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
57
76
|
def sentence_tokenizer(text: str) -> list[str]:
|
|
58
77
|
"""Split text into sentences.
|
|
59
78
|
|
|
@@ -17,9 +17,6 @@ TEMPLATE = "{ref}: {description} ({symbolic})"
|
|
|
17
17
|
FLAKE8 = "{ref} {description} ({symbolic})"
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
Messages: _t.TypeAlias = _t.List["Message"]
|
|
21
|
-
|
|
22
|
-
|
|
23
20
|
class Message(_t.NamedTuple):
|
|
24
21
|
"""Represents an error message."""
|
|
25
22
|
|
|
@@ -57,6 +54,10 @@ class Message(_t.NamedTuple):
|
|
|
57
54
|
)
|
|
58
55
|
|
|
59
56
|
|
|
57
|
+
class Messages(_t.List[Message]):
|
|
58
|
+
"""List of messages."""
|
|
59
|
+
|
|
60
|
+
|
|
60
61
|
class MessageMap(_t.Dict[int, Message]):
|
|
61
62
|
"""Messages mapped under an integer version of their codes."""
|
|
62
63
|
|
|
@@ -78,12 +79,12 @@ class MessageMap(_t.Dict[int, Message]):
|
|
|
78
79
|
:param refs: List of codes or symbolic references.
|
|
79
80
|
:return: List of message types.
|
|
80
81
|
"""
|
|
81
|
-
return
|
|
82
|
+
return Messages(self.from_ref(i) for i in refs)
|
|
82
83
|
|
|
83
84
|
@property
|
|
84
85
|
def all(self) -> Messages:
|
|
85
86
|
"""Get all messages that aren't a config error."""
|
|
86
|
-
return
|
|
87
|
+
return Messages(v for k, v in self.items() if len(str(k)) > 1)
|
|
87
88
|
|
|
88
89
|
|
|
89
90
|
# SIGxxx: Error
|
|
@@ -142,7 +143,7 @@ E = MessageMap(
|
|
|
142
143
|
"parameters missing",
|
|
143
144
|
"params-missing",
|
|
144
145
|
),
|
|
145
|
-
#: SIG3xx
|
|
146
|
+
#: SIG3xx Description
|
|
146
147
|
301: Message(
|
|
147
148
|
"SIG301",
|
|
148
149
|
"description missing from parameter",
|
|
@@ -169,7 +170,7 @@ E = MessageMap(
|
|
|
169
170
|
"description does not begin with a capital letter",
|
|
170
171
|
"description-not-capitalized",
|
|
171
172
|
),
|
|
172
|
-
#: SIG4xx
|
|
173
|
+
#: SIG4xx Parameters
|
|
173
174
|
401: Message(
|
|
174
175
|
"SIG401",
|
|
175
176
|
"param not indented correctly",
|
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
"""Flake8 implementation of docsig."""
|
|
2
2
|
|
|
3
|
-
import ast
|
|
4
|
-
import os
|
|
5
|
-
import sys
|
|
6
|
-
import typing as
|
|
7
|
-
from argparse import Namespace
|
|
8
|
-
from pathlib import Path
|
|
3
|
+
import ast
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import typing as t
|
|
7
|
+
from argparse import SUPPRESS, Namespace
|
|
8
|
+
from pathlib import Path
|
|
9
9
|
|
|
10
10
|
from ._config import Check as _Check
|
|
11
11
|
from ._config import Config as _Config
|
|
12
12
|
from ._config import Ignore as _Ignore
|
|
13
13
|
from ._config import get_config as _get_config
|
|
14
14
|
from ._config import merge_configs as _merge_configs
|
|
15
|
-
from ._core import runner
|
|
16
|
-
from ._core import setup_logger as _setup_logger
|
|
15
|
+
from ._core import handle_deprecations, runner, setup_logger
|
|
17
16
|
from ._version import __version__
|
|
18
|
-
from .messages import FLAKE8
|
|
19
|
-
from .messages import E as _E
|
|
17
|
+
from .messages import FLAKE8, E
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
Flake8Error = t.Tuple[int, int, str, t.Type]
|
|
20
|
+
sys.path.append(os.path.abspath(os.getcwd()))
|
|
23
21
|
|
|
24
22
|
|
|
25
23
|
class Docsig:
|
|
@@ -32,9 +30,9 @@ class Docsig:
|
|
|
32
30
|
off_by_default = False
|
|
33
31
|
name = __package__
|
|
34
32
|
version = __version__
|
|
35
|
-
a =
|
|
33
|
+
a = Namespace()
|
|
36
34
|
|
|
37
|
-
def __init__(self, tree:
|
|
35
|
+
def __init__(self, tree: ast.Module, filename: str) -> None:
|
|
38
36
|
_tree = tree # noqa
|
|
39
37
|
self.filename = filename
|
|
40
38
|
|
|
@@ -43,17 +41,11 @@ class Docsig:
|
|
|
43
41
|
# might require that flake8 actually be installed, which is not a
|
|
44
42
|
# requirement for this package
|
|
45
43
|
@classmethod
|
|
46
|
-
def add_options(cls, parser:
|
|
44
|
+
def add_options(cls, parser: t.Any) -> None:
|
|
47
45
|
"""Add flake8 commandline and config options.
|
|
48
46
|
|
|
49
47
|
:param parser: Flake8 option manager.
|
|
50
48
|
"""
|
|
51
|
-
parser.add_option(
|
|
52
|
-
"--sig-verbose",
|
|
53
|
-
action="store_true",
|
|
54
|
-
parse_from_config=True,
|
|
55
|
-
help="increase output verbosity",
|
|
56
|
-
)
|
|
57
49
|
parser.add_option(
|
|
58
50
|
"--sig-check-class",
|
|
59
51
|
action="store_true",
|
|
@@ -64,10 +56,7 @@ class Docsig:
|
|
|
64
56
|
"--sig-check-class-constructor",
|
|
65
57
|
action="store_true",
|
|
66
58
|
parse_from_config=True,
|
|
67
|
-
help=
|
|
68
|
-
"check __init__ methods (mutually incompatible with"
|
|
69
|
-
" --sig-check-class)"
|
|
70
|
-
),
|
|
59
|
+
help="check __init__ methods. Note: mutually incompatible with -c",
|
|
71
60
|
)
|
|
72
61
|
parser.add_option(
|
|
73
62
|
"--sig-check-dunders",
|
|
@@ -75,6 +64,12 @@ class Docsig:
|
|
|
75
64
|
parse_from_config=True,
|
|
76
65
|
help="check dunder methods",
|
|
77
66
|
)
|
|
67
|
+
parser.add_option(
|
|
68
|
+
"--sig-check-protected-class-methods",
|
|
69
|
+
action="store_true",
|
|
70
|
+
parse_from_config=True,
|
|
71
|
+
help="check public methods belonging to protected classes",
|
|
72
|
+
)
|
|
78
73
|
parser.add_option(
|
|
79
74
|
"--sig-check-nested",
|
|
80
75
|
action="store_true",
|
|
@@ -88,22 +83,22 @@ class Docsig:
|
|
|
88
83
|
help="check overridden methods",
|
|
89
84
|
)
|
|
90
85
|
parser.add_option(
|
|
91
|
-
"--sig-check-
|
|
86
|
+
"--sig-check-protected",
|
|
92
87
|
action="store_true",
|
|
93
88
|
parse_from_config=True,
|
|
94
|
-
help="check
|
|
89
|
+
help="check protected functions and classes",
|
|
95
90
|
)
|
|
96
91
|
parser.add_option(
|
|
97
|
-
"--sig-check-
|
|
92
|
+
"--sig-check-property-returns",
|
|
98
93
|
action="store_true",
|
|
99
94
|
parse_from_config=True,
|
|
100
|
-
help="check
|
|
95
|
+
help="check property return values",
|
|
101
96
|
)
|
|
102
97
|
parser.add_option(
|
|
103
|
-
"--sig-
|
|
98
|
+
"--sig-ignore-no-params",
|
|
104
99
|
action="store_true",
|
|
105
100
|
parse_from_config=True,
|
|
106
|
-
help="
|
|
101
|
+
help="ignore docstrings where parameters are not documented",
|
|
107
102
|
)
|
|
108
103
|
parser.add_option(
|
|
109
104
|
"--sig-ignore-args",
|
|
@@ -118,39 +113,54 @@ class Docsig:
|
|
|
118
113
|
help="ignore kwargs prefixed with two asterisks",
|
|
119
114
|
)
|
|
120
115
|
parser.add_option(
|
|
121
|
-
"--sig-ignore-
|
|
116
|
+
"--sig-ignore-typechecker",
|
|
122
117
|
action="store_true",
|
|
123
118
|
parse_from_config=True,
|
|
124
|
-
help=
|
|
119
|
+
help=SUPPRESS,
|
|
120
|
+
)
|
|
121
|
+
parser.add_option(
|
|
122
|
+
"--sig-verbose",
|
|
123
|
+
action="store_true",
|
|
124
|
+
parse_from_config=True,
|
|
125
|
+
help="increase output verbosity",
|
|
125
126
|
)
|
|
126
127
|
|
|
127
128
|
@classmethod
|
|
128
|
-
def parse_options(cls, a:
|
|
129
|
+
def parse_options(cls, a: Namespace) -> None:
|
|
129
130
|
"""Parse flake8 options into an instance-accessible dict.
|
|
130
131
|
|
|
131
132
|
:param a: Argparse namespace.
|
|
132
133
|
"""
|
|
134
|
+
if getattr(a, "sig_ignore_typechecker", False):
|
|
135
|
+
a.extend_ignore = list(a.extend_ignore or [])
|
|
136
|
+
handle_deprecations(
|
|
137
|
+
getattr(a, "sig_ignore_typechecker", False),
|
|
138
|
+
a.extend_ignore,
|
|
139
|
+
["SIG501", "SIG502", "SIG503", "SIG504", "SIG505", "SIG506"],
|
|
140
|
+
stacklevel=8,
|
|
141
|
+
)
|
|
142
|
+
|
|
133
143
|
cls.a.__dict__ = _merge_configs(
|
|
134
144
|
{k.replace("sig_", ""): v for k, v in a.__dict__.items()},
|
|
135
145
|
_get_config(__package__),
|
|
136
146
|
)
|
|
137
147
|
|
|
138
|
-
def run(self) ->
|
|
148
|
+
def run(self) -> t.Generator[Flake8Error, None, None]:
|
|
139
149
|
"""Run docsig and possibly yield a flake8 error.
|
|
140
150
|
|
|
141
151
|
:return: Flake8 error, if there is one.
|
|
142
152
|
"""
|
|
143
153
|
if self.a.check_class and self.a.check_class_constructor:
|
|
144
154
|
line = "{msg}".format(
|
|
145
|
-
msg=
|
|
146
|
-
ref=
|
|
147
|
-
description=
|
|
148
|
-
symbolic=
|
|
155
|
+
msg=FLAKE8.format(
|
|
156
|
+
ref=E[5].ref,
|
|
157
|
+
description=E[5].description,
|
|
158
|
+
symbolic=E[5].symbolic,
|
|
149
159
|
),
|
|
150
160
|
)
|
|
151
161
|
yield 0, 0, line, self.__class__
|
|
152
162
|
else:
|
|
153
|
-
|
|
163
|
+
setup_logger(self.a.verbose)
|
|
154
164
|
check = _Check(
|
|
155
165
|
class_=self.a.check_class,
|
|
156
166
|
class_constructor=self.a.check_class_constructor,
|
|
@@ -171,11 +181,11 @@ class Docsig:
|
|
|
171
181
|
ignore=ignore,
|
|
172
182
|
verbose=self.a.verbose,
|
|
173
183
|
)
|
|
174
|
-
results =
|
|
184
|
+
results = runner(Path(self.filename), config)
|
|
175
185
|
for result in results:
|
|
176
186
|
for info in result:
|
|
177
187
|
line = "{msg} '{name}'".format(
|
|
178
|
-
msg=
|
|
188
|
+
msg=FLAKE8.format(
|
|
179
189
|
ref=info.ref,
|
|
180
190
|
description=info.description,
|
|
181
191
|
symbolic=info.symbolic,
|
|
@@ -11,7 +11,7 @@ line-length = 79
|
|
|
11
11
|
allow_dirty = true
|
|
12
12
|
commit = true
|
|
13
13
|
commit_args = "-sS"
|
|
14
|
-
current_version = "0.80.
|
|
14
|
+
current_version = "0.80.1"
|
|
15
15
|
message = "bump: version {current_version} → {new_version}"
|
|
16
16
|
sign_tags = true
|
|
17
17
|
tag = true
|
|
@@ -61,6 +61,7 @@ fail_under = 100
|
|
|
61
61
|
|
|
62
62
|
[tool.coverage.run]
|
|
63
63
|
omit = [
|
|
64
|
+
"*/sitecustomize.py",
|
|
64
65
|
"docs/conf.py",
|
|
65
66
|
"docsig/__main__.py",
|
|
66
67
|
"whitelist.py"
|
|
@@ -121,7 +122,7 @@ maintainers = [
|
|
|
121
122
|
name = "docsig"
|
|
122
123
|
readme = "README.rst"
|
|
123
124
|
repository = "https://github.com/jshwi/docsig"
|
|
124
|
-
version = "0.80.
|
|
125
|
+
version = "0.80.1"
|
|
125
126
|
|
|
126
127
|
[tool.poetry.dependencies]
|
|
127
128
|
Sphinx = ">=7,<9"
|
docsig-0.80.0/docsig/_main.py
DELETED
|
@@ -1,26 +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 parse_args as _parse_args
|
|
11
|
-
from ._core import docsig as _docsig
|
|
12
|
-
from ._hooks import excepthook as _excepthook
|
|
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 the test failed or not.
|
|
21
|
-
"""
|
|
22
|
-
a = _parse_args()
|
|
23
|
-
_excepthook(a.no_ansi)
|
|
24
|
-
kwargs = vars(a)
|
|
25
|
-
path = kwargs.pop("path")
|
|
26
|
-
return _docsig(*path, **kwargs)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|