docsig 0.51.0__tar.gz → 0.52.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.51.0 → docsig-0.52.0}/PKG-INFO +19 -17
- {docsig-0.51.0 → docsig-0.52.0}/README.rst +18 -16
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_core.py +9 -16
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_decorators.py +2 -2
- docsig-0.52.0/docsig/_directives.py +134 -0
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_hooks.py +2 -2
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_module.py +55 -45
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_report.py +15 -13
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_stub.py +10 -0
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_utils.py +9 -0
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_version.py +1 -1
- {docsig-0.51.0 → docsig-0.52.0}/docsig/messages.py +103 -23
- {docsig-0.51.0 → docsig-0.52.0}/pyproject.toml +1 -2
- docsig-0.51.0/docsig/_directives.py +0 -159
- docsig-0.51.0/docsig/_message.py +0 -70
- {docsig-0.51.0 → docsig-0.52.0}/LICENSE +0 -0
- {docsig-0.51.0 → docsig-0.52.0}/docsig/__init__.py +0 -0
- {docsig-0.51.0 → docsig-0.52.0}/docsig/__main__.py +0 -0
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_config.py +0 -0
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_display.py +0 -0
- {docsig-0.51.0 → docsig-0.52.0}/docsig/_main.py +0 -0
- {docsig-0.51.0 → docsig-0.52.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.52.0
|
|
4
4
|
Summary: Check signature params for proper documentation
|
|
5
5
|
Home-page: https://pypi.org/project/docsig/
|
|
6
6
|
License: MIT
|
|
@@ -36,49 +36,51 @@ Description-Content-Type: text/x-rst
|
|
|
36
36
|
|
|
37
37
|
|
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
|License| |PyPI| |CI| |CodeQL| |pre-commit.ci status| |codecov.io| |readthedocs.org| |python3.8| |Black| |isort| |docformatter| |pylint| |Security Status| |Known Vulnerabilities| |docsig|
|
|
40
|
+
|
|
41
|
+
.. |License| image:: https://img.shields.io/badge/License-MIT-yellow.svg
|
|
40
42
|
:target: https://opensource.org/licenses/MIT
|
|
41
43
|
:alt: License
|
|
42
|
-
.. image:: https://img.shields.io/pypi/v/docsig
|
|
44
|
+
.. |PyPI| image:: https://img.shields.io/pypi/v/docsig
|
|
43
45
|
:target: https://pypi.org/project/docsig/
|
|
44
46
|
:alt: PyPI
|
|
45
|
-
.. image:: https://github.com/jshwi/docsig/actions/workflows/build.yaml/badge.svg
|
|
47
|
+
.. |CI| image:: https://github.com/jshwi/docsig/actions/workflows/build.yaml/badge.svg
|
|
46
48
|
:target: https://github.com/jshwi/docsig/actions/workflows/build.yaml
|
|
47
49
|
:alt: CI
|
|
48
|
-
.. image:: https://github.com/jshwi/docsig/actions/workflows/codeql-analysis.yml/badge.svg
|
|
50
|
+
.. |CodeQL| image:: https://github.com/jshwi/docsig/actions/workflows/codeql-analysis.yml/badge.svg
|
|
49
51
|
:target: https://github.com/jshwi/docsig/actions/workflows/codeql-analysis.yml
|
|
50
52
|
:alt: CodeQL
|
|
51
|
-
.. image:: https://results.pre-commit.ci/badge/github/jshwi/docsig/master.svg
|
|
53
|
+
.. |pre-commit.ci status| image:: https://results.pre-commit.ci/badge/github/jshwi/docsig/master.svg
|
|
52
54
|
:target: https://results.pre-commit.ci/latest/github/jshwi/docsig/master
|
|
53
55
|
:alt: pre-commit.ci status
|
|
54
|
-
.. image:: https://codecov.io/gh/jshwi/docsig/branch/master/graph/badge.svg
|
|
56
|
+
.. |codecov.io| image:: https://codecov.io/gh/jshwi/docsig/branch/master/graph/badge.svg
|
|
55
57
|
:target: https://codecov.io/gh/jshwi/docsig
|
|
56
58
|
:alt: codecov.io
|
|
57
|
-
.. image:: https://readthedocs.org/projects/docsig/badge/?version=latest
|
|
59
|
+
.. |readthedocs.org| image:: https://readthedocs.org/projects/docsig/badge/?version=latest
|
|
58
60
|
:target: https://docsig.readthedocs.io/en/latest/?badge=latest
|
|
59
61
|
:alt: readthedocs.org
|
|
60
|
-
.. image:: https://img.shields.io/badge/python-3.8-blue.svg
|
|
62
|
+
.. |python3.8| image:: https://img.shields.io/badge/python-3.8-blue.svg
|
|
61
63
|
:target: https://www.python.org/downloads/release/python-380
|
|
62
64
|
:alt: python3.8
|
|
63
|
-
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
|
65
|
+
.. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
|
64
66
|
:target: https://github.com/psf/black
|
|
65
67
|
:alt: Black
|
|
66
|
-
.. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336
|
|
68
|
+
.. |isort| image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336
|
|
67
69
|
:target: https://pycqa.github.io/isort/
|
|
68
70
|
:alt: isort
|
|
69
|
-
.. image:: https://img.shields.io/badge/%20formatter-docformatter-fedcba.svg
|
|
71
|
+
.. |docformatter| image:: https://img.shields.io/badge/%20formatter-docformatter-fedcba.svg
|
|
70
72
|
:target: https://github.com/PyCQA/docformatter
|
|
71
73
|
:alt: docformatter
|
|
72
|
-
.. image:: https://img.shields.io/badge/linting-pylint-yellowgreen
|
|
74
|
+
.. |pylint| image:: https://img.shields.io/badge/linting-pylint-yellowgreen
|
|
73
75
|
:target: https://github.com/PyCQA/pylint
|
|
74
76
|
:alt: pylint
|
|
75
|
-
.. image:: https://img.shields.io/badge/security-bandit-yellow.svg
|
|
77
|
+
.. |Security Status| image:: https://img.shields.io/badge/security-bandit-yellow.svg
|
|
76
78
|
:target: https://github.com/PyCQA/bandit
|
|
77
79
|
:alt: Security Status
|
|
78
|
-
.. image:: https://snyk.io/test/github/jshwi/docsig/badge.svg
|
|
80
|
+
.. |Known Vulnerabilities| image:: https://snyk.io/test/github/jshwi/docsig/badge.svg
|
|
79
81
|
:target: https://snyk.io/test/github/jshwi/docsig/badge.svg
|
|
80
82
|
:alt: Known Vulnerabilities
|
|
81
|
-
.. image:: https://snyk.io/advisor/python/docsig/badge.svg
|
|
83
|
+
.. |docsig| image:: https://snyk.io/advisor/python/docsig/badge.svg
|
|
82
84
|
:target: https://snyk.io/advisor/python/docsig
|
|
83
85
|
:alt: docsig
|
|
84
86
|
|
|
@@ -227,7 +229,7 @@ It can be added to your .pre-commit-config.yaml as follows:
|
|
|
227
229
|
|
|
228
230
|
repos:
|
|
229
231
|
- repo: https://github.com/jshwi/docsig
|
|
230
|
-
rev: v0.
|
|
232
|
+
rev: v0.52.0
|
|
231
233
|
hooks:
|
|
232
234
|
- id: docsig
|
|
233
235
|
args:
|
|
@@ -7,49 +7,51 @@
|
|
|
7
7
|
|
|
8
8
|
|
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
|License| |PyPI| |CI| |CodeQL| |pre-commit.ci status| |codecov.io| |readthedocs.org| |python3.8| |Black| |isort| |docformatter| |pylint| |Security Status| |Known Vulnerabilities| |docsig|
|
|
11
|
+
|
|
12
|
+
.. |License| image:: https://img.shields.io/badge/License-MIT-yellow.svg
|
|
11
13
|
:target: https://opensource.org/licenses/MIT
|
|
12
14
|
:alt: License
|
|
13
|
-
.. image:: https://img.shields.io/pypi/v/docsig
|
|
15
|
+
.. |PyPI| image:: https://img.shields.io/pypi/v/docsig
|
|
14
16
|
:target: https://pypi.org/project/docsig/
|
|
15
17
|
:alt: PyPI
|
|
16
|
-
.. image:: https://github.com/jshwi/docsig/actions/workflows/build.yaml/badge.svg
|
|
18
|
+
.. |CI| image:: https://github.com/jshwi/docsig/actions/workflows/build.yaml/badge.svg
|
|
17
19
|
:target: https://github.com/jshwi/docsig/actions/workflows/build.yaml
|
|
18
20
|
:alt: CI
|
|
19
|
-
.. image:: https://github.com/jshwi/docsig/actions/workflows/codeql-analysis.yml/badge.svg
|
|
21
|
+
.. |CodeQL| image:: https://github.com/jshwi/docsig/actions/workflows/codeql-analysis.yml/badge.svg
|
|
20
22
|
:target: https://github.com/jshwi/docsig/actions/workflows/codeql-analysis.yml
|
|
21
23
|
:alt: CodeQL
|
|
22
|
-
.. image:: https://results.pre-commit.ci/badge/github/jshwi/docsig/master.svg
|
|
24
|
+
.. |pre-commit.ci status| image:: https://results.pre-commit.ci/badge/github/jshwi/docsig/master.svg
|
|
23
25
|
:target: https://results.pre-commit.ci/latest/github/jshwi/docsig/master
|
|
24
26
|
:alt: pre-commit.ci status
|
|
25
|
-
.. image:: https://codecov.io/gh/jshwi/docsig/branch/master/graph/badge.svg
|
|
27
|
+
.. |codecov.io| image:: https://codecov.io/gh/jshwi/docsig/branch/master/graph/badge.svg
|
|
26
28
|
:target: https://codecov.io/gh/jshwi/docsig
|
|
27
29
|
:alt: codecov.io
|
|
28
|
-
.. image:: https://readthedocs.org/projects/docsig/badge/?version=latest
|
|
30
|
+
.. |readthedocs.org| image:: https://readthedocs.org/projects/docsig/badge/?version=latest
|
|
29
31
|
:target: https://docsig.readthedocs.io/en/latest/?badge=latest
|
|
30
32
|
:alt: readthedocs.org
|
|
31
|
-
.. image:: https://img.shields.io/badge/python-3.8-blue.svg
|
|
33
|
+
.. |python3.8| image:: https://img.shields.io/badge/python-3.8-blue.svg
|
|
32
34
|
:target: https://www.python.org/downloads/release/python-380
|
|
33
35
|
:alt: python3.8
|
|
34
|
-
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
|
36
|
+
.. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
|
35
37
|
:target: https://github.com/psf/black
|
|
36
38
|
:alt: Black
|
|
37
|
-
.. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336
|
|
39
|
+
.. |isort| image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336
|
|
38
40
|
:target: https://pycqa.github.io/isort/
|
|
39
41
|
:alt: isort
|
|
40
|
-
.. image:: https://img.shields.io/badge/%20formatter-docformatter-fedcba.svg
|
|
42
|
+
.. |docformatter| image:: https://img.shields.io/badge/%20formatter-docformatter-fedcba.svg
|
|
41
43
|
:target: https://github.com/PyCQA/docformatter
|
|
42
44
|
:alt: docformatter
|
|
43
|
-
.. image:: https://img.shields.io/badge/linting-pylint-yellowgreen
|
|
45
|
+
.. |pylint| image:: https://img.shields.io/badge/linting-pylint-yellowgreen
|
|
44
46
|
:target: https://github.com/PyCQA/pylint
|
|
45
47
|
:alt: pylint
|
|
46
|
-
.. image:: https://img.shields.io/badge/security-bandit-yellow.svg
|
|
48
|
+
.. |Security Status| image:: https://img.shields.io/badge/security-bandit-yellow.svg
|
|
47
49
|
:target: https://github.com/PyCQA/bandit
|
|
48
50
|
:alt: Security Status
|
|
49
|
-
.. image:: https://snyk.io/test/github/jshwi/docsig/badge.svg
|
|
51
|
+
.. |Known Vulnerabilities| image:: https://snyk.io/test/github/jshwi/docsig/badge.svg
|
|
50
52
|
:target: https://snyk.io/test/github/jshwi/docsig/badge.svg
|
|
51
53
|
:alt: Known Vulnerabilities
|
|
52
|
-
.. image:: https://snyk.io/advisor/python/docsig/badge.svg
|
|
54
|
+
.. |docsig| image:: https://snyk.io/advisor/python/docsig/badge.svg
|
|
53
55
|
:target: https://snyk.io/advisor/python/docsig
|
|
54
56
|
:alt: docsig
|
|
55
57
|
|
|
@@ -198,7 +200,7 @@ It can be added to your .pre-commit-config.yaml as follows:
|
|
|
198
200
|
|
|
199
201
|
repos:
|
|
200
202
|
- repo: https://github.com/jshwi/docsig
|
|
201
|
-
rev: v0.
|
|
203
|
+
rev: v0.52.0
|
|
202
204
|
hooks:
|
|
203
205
|
- id: docsig
|
|
204
206
|
args:
|
|
@@ -7,20 +7,17 @@ from __future__ import annotations as _
|
|
|
7
7
|
|
|
8
8
|
from pathlib import Path as _Path
|
|
9
9
|
|
|
10
|
-
import click as _click
|
|
11
|
-
|
|
12
10
|
from . import _decorators
|
|
13
11
|
from ._display import Display as _Display
|
|
14
12
|
from ._display import Failure as _Failure
|
|
15
13
|
from ._display import Failures as _Failures
|
|
16
14
|
from ._display import FuncStr as _FuncStr
|
|
17
|
-
from ._message import Message as _Message
|
|
18
15
|
from ._module import Function as _Function
|
|
19
16
|
from ._module import Modules as _Modules
|
|
20
17
|
from ._module import Parent as _Parent
|
|
21
18
|
from ._report import Report as _Report
|
|
22
|
-
from .
|
|
23
|
-
from .messages import
|
|
19
|
+
from ._utils import print_checks as _print_checks
|
|
20
|
+
from .messages import Messages as _Messages
|
|
24
21
|
|
|
25
22
|
_DEFAULT_EXCLUDES = """\
|
|
26
23
|
(?x)^(
|
|
@@ -42,11 +39,6 @@ _DEFAULT_EXCLUDES = """\
|
|
|
42
39
|
"""
|
|
43
40
|
|
|
44
41
|
|
|
45
|
-
def _print_checks() -> None:
|
|
46
|
-
for msg in _E.values():
|
|
47
|
-
_click.echo(msg.fstring(_TEMPLATE))
|
|
48
|
-
|
|
49
|
-
|
|
50
42
|
def _run_check( # pylint: disable=too-many-arguments
|
|
51
43
|
child: _Parent,
|
|
52
44
|
parent: _Parent,
|
|
@@ -59,7 +51,7 @@ def _run_check( # pylint: disable=too-many-arguments
|
|
|
59
51
|
check_property_returns: bool,
|
|
60
52
|
ignore_no_params: bool,
|
|
61
53
|
no_ansi: bool,
|
|
62
|
-
targets:
|
|
54
|
+
targets: _Messages,
|
|
63
55
|
failures: _Failures,
|
|
64
56
|
) -> None:
|
|
65
57
|
if isinstance(child, _Function):
|
|
@@ -76,7 +68,7 @@ def _run_check( # pylint: disable=too-many-arguments
|
|
|
76
68
|
and not (child.docstring.bare and ignore_no_params)
|
|
77
69
|
):
|
|
78
70
|
report = _Report(
|
|
79
|
-
child, targets, child.
|
|
71
|
+
child, targets, child.messages, check_property_returns
|
|
80
72
|
)
|
|
81
73
|
if report:
|
|
82
74
|
failures.append(_Failure(child, _FuncStr(child), report))
|
|
@@ -99,6 +91,7 @@ def _run_check( # pylint: disable=too-many-arguments
|
|
|
99
91
|
failures,
|
|
100
92
|
)
|
|
101
93
|
else:
|
|
94
|
+
# this is a class
|
|
102
95
|
for func in child:
|
|
103
96
|
_run_check(
|
|
104
97
|
func,
|
|
@@ -138,8 +131,8 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
138
131
|
no_ansi: bool = False,
|
|
139
132
|
summary: bool = False,
|
|
140
133
|
verbose: bool = False,
|
|
141
|
-
targets:
|
|
142
|
-
disable:
|
|
134
|
+
targets: _Messages | None = None,
|
|
135
|
+
disable: _Messages | None = None,
|
|
143
136
|
exclude: str | None = None,
|
|
144
137
|
) -> int:
|
|
145
138
|
"""Package's core functionality.
|
|
@@ -188,7 +181,7 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
188
181
|
|
|
189
182
|
modules = _Modules(
|
|
190
183
|
*tuple(_Path(i) for i in path),
|
|
191
|
-
|
|
184
|
+
messages=disable or _Messages(),
|
|
192
185
|
string=string,
|
|
193
186
|
excludes=excludes,
|
|
194
187
|
include_ignored=include_ignored,
|
|
@@ -219,7 +212,7 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
|
|
|
219
212
|
check_property_returns,
|
|
220
213
|
ignore_no_params,
|
|
221
214
|
no_ansi,
|
|
222
|
-
targets or
|
|
215
|
+
targets or _Messages(),
|
|
223
216
|
failures,
|
|
224
217
|
)
|
|
225
218
|
if failures:
|
|
@@ -25,8 +25,8 @@ def parse_msgs(func: _WrappedFuncType) -> _WrappedFuncType:
|
|
|
25
25
|
|
|
26
26
|
@_functools.wraps(func)
|
|
27
27
|
def _wrapper(*args: str | _Path, **kwargs: _t.Any) -> str | int:
|
|
28
|
-
disable =
|
|
29
|
-
targets =
|
|
28
|
+
disable = _E.from_codes(kwargs.get("disable", [])) or None
|
|
29
|
+
targets = _E.from_codes(kwargs.get("targets", [])) or None
|
|
30
30
|
kwargs["disable"] = disable
|
|
31
31
|
kwargs["targets"] = targets
|
|
32
32
|
return func(*args, **kwargs)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""
|
|
2
|
+
docsig._disable
|
|
3
|
+
===============
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations as _
|
|
7
|
+
|
|
8
|
+
import tokenize as _tokenize
|
|
9
|
+
import typing as _t
|
|
10
|
+
from io import StringIO as _StringIO
|
|
11
|
+
|
|
12
|
+
from .messages import E as _E
|
|
13
|
+
from .messages import Messages as _Messages
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Comment(_Messages):
|
|
17
|
+
"""Represents a comment directive.
|
|
18
|
+
|
|
19
|
+
:param string: Text to construct comment from.
|
|
20
|
+
:param col: The column this directive is positioned at.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
_valid_kinds = "enable", "disable"
|
|
24
|
+
|
|
25
|
+
def __init__(self, string: str, col: int) -> None:
|
|
26
|
+
super().__init__()
|
|
27
|
+
self._ismodule = col == 0
|
|
28
|
+
parts = string.split("=")
|
|
29
|
+
self._kind = parts[0]
|
|
30
|
+
if len(parts) == 1:
|
|
31
|
+
self.extend(_E.all(1))
|
|
32
|
+
else:
|
|
33
|
+
self.extend(_E.from_ref(i) for i in parts[1].split(","))
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def kind(self) -> str:
|
|
37
|
+
"""The type of this directive."""
|
|
38
|
+
return self._kind
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def isvalid(self) -> bool:
|
|
42
|
+
"""Whether this directive is valid or not."""
|
|
43
|
+
return self._kind in self._valid_kinds
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def ismodule(self) -> bool:
|
|
47
|
+
"""Whether this is a module level directive or not."""
|
|
48
|
+
return self._ismodule
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def enable(self) -> bool:
|
|
52
|
+
"""Whether this is an enable directive or not."""
|
|
53
|
+
return self._kind == self._valid_kinds[0]
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def disable(self) -> bool:
|
|
57
|
+
"""Whether this is a disable directive or not."""
|
|
58
|
+
return self._kind == self._valid_kinds[1]
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def parse(cls, comment: str, col: int) -> Comment | None:
|
|
62
|
+
"""Parse string into directive object if possible.
|
|
63
|
+
|
|
64
|
+
:param comment: Comment to parse.
|
|
65
|
+
:param col: Column of comment to instantiate directive.
|
|
66
|
+
:return: Instantiated directive object if valid directive or
|
|
67
|
+
None if not a valid directive.
|
|
68
|
+
"""
|
|
69
|
+
if comment[1:].strip().startswith(f"{__package__}:"):
|
|
70
|
+
return cls(comment.split(":")[1].strip(), col)
|
|
71
|
+
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class _Comments(_t.List[Comment]):
|
|
76
|
+
"""List of comments."""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class Directives(_t.Dict[int, _t.Tuple[_Comments, _Messages]]):
|
|
80
|
+
"""Data for directives:
|
|
81
|
+
|
|
82
|
+
Dict like object with the line number of directive as the key a
|
|
83
|
+
tuple containing comments and messages.
|
|
84
|
+
|
|
85
|
+
Comments can be either disable or enable comments, and messages are
|
|
86
|
+
what messages are to be disabled.
|
|
87
|
+
|
|
88
|
+
Comments influence what messages can be added to the list, but are
|
|
89
|
+
different in that they communicate the directive, but the messages
|
|
90
|
+
are the final product of messages to disable.
|
|
91
|
+
|
|
92
|
+
Comments are collected here for later analysis.
|
|
93
|
+
|
|
94
|
+
:param text: Python code.
|
|
95
|
+
:param messages: List of checks to disable.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def __init__(self, text: str, messages: _Messages) -> None:
|
|
99
|
+
super().__init__()
|
|
100
|
+
fin = _StringIO(text)
|
|
101
|
+
comments = _Comments()
|
|
102
|
+
for line in _tokenize.generate_tokens(fin.readline):
|
|
103
|
+
# do nothing for these lines types
|
|
104
|
+
if line.type in (_tokenize.NAME, _tokenize.OP, _tokenize.DEDENT):
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
# inherit the comments and messages defined in the global
|
|
108
|
+
# scope, but do not update the global comments and messages
|
|
109
|
+
# unless it is confirmed that the comment is a module level
|
|
110
|
+
# directive
|
|
111
|
+
scoped_comments = _Comments(comments)
|
|
112
|
+
scoped_messages = _Messages(messages)
|
|
113
|
+
lineno, col = line.start
|
|
114
|
+
if line.type == _tokenize.COMMENT:
|
|
115
|
+
comment = Comment.parse(line.string, col)
|
|
116
|
+
if comment is not None:
|
|
117
|
+
scoped_comments.append(comment)
|
|
118
|
+
if comment.disable:
|
|
119
|
+
scoped_messages.extend(comment)
|
|
120
|
+
elif comment.enable:
|
|
121
|
+
scoped_messages = _Messages(
|
|
122
|
+
i for i in messages if i not in comment
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# if module level directive then make changes
|
|
126
|
+
# globally
|
|
127
|
+
if comment.ismodule:
|
|
128
|
+
messages = scoped_messages
|
|
129
|
+
comments = scoped_comments
|
|
130
|
+
|
|
131
|
+
# check that a scoped message has not updated this first, as
|
|
132
|
+
# they take precedence over global messages
|
|
133
|
+
if lineno not in self:
|
|
134
|
+
self[lineno] = scoped_comments, scoped_messages
|
|
@@ -6,7 +6,7 @@ docsig._hooks
|
|
|
6
6
|
import sys as _sys
|
|
7
7
|
from os import environ as _e
|
|
8
8
|
|
|
9
|
-
from ._utils import pretty_print_error
|
|
9
|
+
from ._utils import pretty_print_error as _pretty_print_error
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def excepthook(no_ansi: bool = False) -> None:
|
|
@@ -15,6 +15,6 @@ def excepthook(no_ansi: bool = False) -> None:
|
|
|
15
15
|
:param no_ansi: Disable ANSI output.
|
|
16
16
|
"""
|
|
17
17
|
if _e.get("DOCSIG_DEBUG", None) != "1":
|
|
18
|
-
_sys.excepthook = lambda x, y, _:
|
|
18
|
+
_sys.excepthook = lambda x, y, _: _pretty_print_error(
|
|
19
19
|
x, str(y), no_ansi
|
|
20
20
|
)
|
|
@@ -17,13 +17,13 @@ from astroid import AstroidSyntaxError as _AstroidSyntaxError
|
|
|
17
17
|
from pathspec import PathSpec as _PathSpec
|
|
18
18
|
from pathspec.patterns import GitWildMatchPattern as _GitWildMatchPattern
|
|
19
19
|
|
|
20
|
-
from ._directives import
|
|
20
|
+
from ._directives import Comment as _Comment
|
|
21
21
|
from ._directives import Directives as _Directives
|
|
22
|
-
from ._message import Message as _Message
|
|
23
22
|
from ._stub import Docstring as _Docstring
|
|
24
23
|
from ._stub import Signature as _Signature
|
|
25
|
-
from ._utils import pretty_print_error
|
|
24
|
+
from ._utils import pretty_print_error as _pretty_print_error
|
|
26
25
|
from ._utils import vprint as _vprint
|
|
26
|
+
from .messages import Messages as _Messages
|
|
27
27
|
|
|
28
28
|
_FILE_INFO = "{path}: {msg}"
|
|
29
29
|
|
|
@@ -84,6 +84,7 @@ class Parent(_t.List["Parent"]):
|
|
|
84
84
|
:param check_class_constructor: Check the class constructor's
|
|
85
85
|
docstring. Otherwise, expect the constructor's documentation to
|
|
86
86
|
be on the class level docstring.
|
|
87
|
+
:param imports: Imports within this scope.
|
|
87
88
|
"""
|
|
88
89
|
|
|
89
90
|
def __init__( # pylint: disable=too-many-arguments
|
|
@@ -94,12 +95,13 @@ class Parent(_t.List["Parent"]):
|
|
|
94
95
|
ignore_args: bool = False,
|
|
95
96
|
ignore_kwargs: bool = False,
|
|
96
97
|
check_class_constructor: bool = False,
|
|
98
|
+
imports: dict[str, str] | None = None,
|
|
97
99
|
) -> None:
|
|
98
100
|
super().__init__()
|
|
99
101
|
self._name = node.name
|
|
100
102
|
self._path = f"{path}:" if path is not None else ""
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
self._overloads: dict[str, Function] = {}
|
|
104
|
+
self._imports = imports or {}
|
|
103
105
|
self._parse_ast(
|
|
104
106
|
node,
|
|
105
107
|
directives,
|
|
@@ -107,10 +109,13 @@ class Parent(_t.List["Parent"]):
|
|
|
107
109
|
ignore_args,
|
|
108
110
|
ignore_kwargs,
|
|
109
111
|
check_class_constructor,
|
|
110
|
-
overloads,
|
|
111
|
-
returns,
|
|
112
112
|
)
|
|
113
113
|
|
|
114
|
+
def _parse_imports(self, names: list[tuple[str, str | None]]) -> None:
|
|
115
|
+
for name in names:
|
|
116
|
+
original, alias = name
|
|
117
|
+
self._imports[original] = alias or original
|
|
118
|
+
|
|
114
119
|
def _parse_ast( # pylint: disable=protected-access,too-many-arguments
|
|
115
120
|
self,
|
|
116
121
|
node,
|
|
@@ -119,9 +124,10 @@ class Parent(_t.List["Parent"]):
|
|
|
119
124
|
ignore_args,
|
|
120
125
|
ignore_kwargs,
|
|
121
126
|
check_class_constructor,
|
|
122
|
-
overloads,
|
|
123
|
-
returns,
|
|
124
127
|
) -> None:
|
|
128
|
+
# need to keep track of `comments` as, even though they are
|
|
129
|
+
# resolved in directives object, they are needed to notify user
|
|
130
|
+
# in the case that they are invalid
|
|
125
131
|
parent_comments, parent_disabled = directives.get(
|
|
126
132
|
node.lineno, ([], [])
|
|
127
133
|
)
|
|
@@ -130,7 +136,9 @@ class Parent(_t.List["Parent"]):
|
|
|
130
136
|
comments, disabled = directives.get(subnode.lineno, ([], []))
|
|
131
137
|
comments.extend(parent_comments)
|
|
132
138
|
disabled.extend(parent_disabled)
|
|
133
|
-
if isinstance(subnode, _ast.
|
|
139
|
+
if isinstance(subnode, (_ast.Import, _ast.ImportFrom)):
|
|
140
|
+
self._parse_imports(subnode.names)
|
|
141
|
+
elif isinstance(subnode, _ast.FunctionDef):
|
|
134
142
|
func = Function(
|
|
135
143
|
subnode,
|
|
136
144
|
comments,
|
|
@@ -140,22 +148,14 @@ class Parent(_t.List["Parent"]):
|
|
|
140
148
|
ignore_args,
|
|
141
149
|
ignore_kwargs,
|
|
142
150
|
check_class_constructor,
|
|
151
|
+
self._imports,
|
|
143
152
|
)
|
|
144
153
|
if func.isoverloaded:
|
|
145
|
-
|
|
146
|
-
returns = func.signature.rettype
|
|
154
|
+
self._overloads[func.name] = func
|
|
147
155
|
else:
|
|
148
|
-
if func.name in
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
func._signature._rettype = (
|
|
152
|
-
returns
|
|
153
|
-
if isinstance(returns, str)
|
|
154
|
-
else func._signature._get_rettype(returns)
|
|
155
|
-
)
|
|
156
|
-
# noinspection PyProtectedMember
|
|
157
|
-
func._signature._returns = (
|
|
158
|
-
str(func._signature._rettype) != "None"
|
|
156
|
+
if func.name in self._overloads:
|
|
157
|
+
func.overload(
|
|
158
|
+
self._overloads[func.name].signature.rettype
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
self.append(func)
|
|
@@ -168,6 +168,7 @@ class Parent(_t.List["Parent"]):
|
|
|
168
168
|
ignore_args,
|
|
169
169
|
ignore_kwargs,
|
|
170
170
|
check_class_constructor,
|
|
171
|
+
self._imports,
|
|
171
172
|
)
|
|
172
173
|
)
|
|
173
174
|
else:
|
|
@@ -178,8 +179,6 @@ class Parent(_t.List["Parent"]):
|
|
|
178
179
|
ignore_args,
|
|
179
180
|
ignore_kwargs,
|
|
180
181
|
check_class_constructor,
|
|
181
|
-
overloads,
|
|
182
|
-
returns,
|
|
183
182
|
)
|
|
184
183
|
|
|
185
184
|
@property
|
|
@@ -199,25 +198,27 @@ class Function(Parent):
|
|
|
199
198
|
:param node: Function's abstract syntax tree.
|
|
200
199
|
:param comments: Comments in list form containing directives.
|
|
201
200
|
:param directives: Directive, if any, belonging to this function.
|
|
202
|
-
:param
|
|
201
|
+
:param messages: List of disabled checks specific to this function.
|
|
203
202
|
:param path: Path to base path representation on.
|
|
204
203
|
:param ignore_args: Ignore args prefixed with an asterisk.
|
|
205
204
|
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
|
|
206
205
|
:param check_class_constructor: If the function is the class
|
|
207
206
|
constructor, use its own docstring. Otherwise, use the class
|
|
208
207
|
level docstring for the constructor function.
|
|
208
|
+
:param imports: Imports within this scope.
|
|
209
209
|
"""
|
|
210
210
|
|
|
211
211
|
def __init__( # pylint: disable=too-many-arguments
|
|
212
212
|
self,
|
|
213
213
|
node: _ast.FunctionDef,
|
|
214
|
-
comments:
|
|
214
|
+
comments: list[_Comment],
|
|
215
215
|
directives: _Directives,
|
|
216
|
-
|
|
216
|
+
messages: _Messages,
|
|
217
217
|
path: _Path | None = None,
|
|
218
218
|
ignore_args: bool = False,
|
|
219
219
|
ignore_kwargs: bool = False,
|
|
220
220
|
check_class_constructor: bool = False,
|
|
221
|
+
imports: dict[str, str] | None = None,
|
|
221
222
|
) -> None:
|
|
222
223
|
super().__init__(
|
|
223
224
|
node,
|
|
@@ -226,10 +227,11 @@ class Function(Parent):
|
|
|
226
227
|
ignore_args,
|
|
227
228
|
ignore_kwargs,
|
|
228
229
|
check_class_constructor,
|
|
230
|
+
imports,
|
|
229
231
|
)
|
|
230
232
|
self._node = node
|
|
231
|
-
self.
|
|
232
|
-
self.
|
|
233
|
+
self._comments = comments
|
|
234
|
+
self._messages = messages
|
|
233
235
|
self._parent = node.parent.frame()
|
|
234
236
|
self._signature = _Signature(
|
|
235
237
|
node.args,
|
|
@@ -251,6 +253,7 @@ class Function(Parent):
|
|
|
251
253
|
return max([len(self.signature.args), len(self.docstring.args)])
|
|
252
254
|
|
|
253
255
|
def _decorated_with(self, name: str) -> bool:
|
|
256
|
+
name = self._imports.get(name, name)
|
|
254
257
|
if self._node.decorators is not None:
|
|
255
258
|
for dec in self._node.decorators.nodes:
|
|
256
259
|
return (isinstance(dec, _ast.Name) and dec.name == name) or (
|
|
@@ -344,14 +347,21 @@ class Function(Parent):
|
|
|
344
347
|
return self._docstring
|
|
345
348
|
|
|
346
349
|
@property
|
|
347
|
-
def
|
|
350
|
+
def messages(self) -> _Messages:
|
|
348
351
|
"""List of disabled checks specific to this function."""
|
|
349
|
-
return self.
|
|
352
|
+
return self._messages
|
|
350
353
|
|
|
351
354
|
@property
|
|
352
|
-
def
|
|
353
|
-
"""
|
|
354
|
-
return self.
|
|
355
|
+
def comments(self) -> list[_Comment]:
|
|
356
|
+
"""Comments, if any, belonging to this function."""
|
|
357
|
+
return self._comments
|
|
358
|
+
|
|
359
|
+
def overload(self, rettype: str | None) -> None:
|
|
360
|
+
"""Overload function with new signature return type.
|
|
361
|
+
|
|
362
|
+
:param rettype: Return type of overloaded signature.
|
|
363
|
+
"""
|
|
364
|
+
self._signature.overload(rettype)
|
|
355
365
|
|
|
356
366
|
|
|
357
367
|
class Modules(_t.List[Parent]): # pylint: disable=too-many-instance-attributes
|
|
@@ -363,7 +373,7 @@ class Modules(_t.List[Parent]): # pylint: disable=too-many-instance-attributes
|
|
|
363
373
|
If string is provided, ignore paths.
|
|
364
374
|
|
|
365
375
|
:param paths: Path(s) to parse ``Module``(s) from.
|
|
366
|
-
:param
|
|
376
|
+
:param messages: List of checks to disable.
|
|
367
377
|
:param excludes: List pf regular expression of files and dirs to
|
|
368
378
|
exclude from checks.
|
|
369
379
|
:param string: String to parse if provided.
|
|
@@ -381,7 +391,7 @@ class Modules(_t.List[Parent]): # pylint: disable=too-many-instance-attributes
|
|
|
381
391
|
# handle errors here before appending a module
|
|
382
392
|
def _add_module( # pylint: disable=too-many-arguments
|
|
383
393
|
self,
|
|
384
|
-
|
|
394
|
+
messages: _Messages,
|
|
385
395
|
string: str | None = None,
|
|
386
396
|
root: _Path | None = None,
|
|
387
397
|
ignore_args: bool = False,
|
|
@@ -398,7 +408,7 @@ class Modules(_t.List[Parent]): # pylint: disable=too-many-instance-attributes
|
|
|
398
408
|
self.append(
|
|
399
409
|
Parent(
|
|
400
410
|
_ast.parse(string),
|
|
401
|
-
_Directives(string,
|
|
411
|
+
_Directives(string, messages),
|
|
402
412
|
root,
|
|
403
413
|
ignore_args,
|
|
404
414
|
ignore_kwargs,
|
|
@@ -418,7 +428,7 @@ class Modules(_t.List[Parent]): # pylint: disable=too-many-instance-attributes
|
|
|
418
428
|
# may result in a 123 syntax error exit status in the
|
|
419
429
|
# future
|
|
420
430
|
_click.echo(root, file=_sys.stderr)
|
|
421
|
-
|
|
431
|
+
_pretty_print_error(type(err), msg, no_ansi=self._no_ansi)
|
|
422
432
|
self._retcode = 1
|
|
423
433
|
|
|
424
434
|
_vprint(
|
|
@@ -429,7 +439,7 @@ class Modules(_t.List[Parent]): # pylint: disable=too-many-instance-attributes
|
|
|
429
439
|
def __init__( # pylint: disable=too-many-arguments
|
|
430
440
|
self,
|
|
431
441
|
*paths: _Path,
|
|
432
|
-
|
|
442
|
+
messages: _Messages,
|
|
433
443
|
excludes: list[str],
|
|
434
444
|
string: str | None = None,
|
|
435
445
|
include_ignored: bool = False,
|
|
@@ -440,19 +450,19 @@ class Modules(_t.List[Parent]): # pylint: disable=too-many-instance-attributes
|
|
|
440
450
|
verbose: bool = False,
|
|
441
451
|
) -> None:
|
|
442
452
|
super().__init__()
|
|
443
|
-
self.
|
|
453
|
+
self._messages = messages
|
|
444
454
|
self._excludes = excludes
|
|
445
455
|
self._include_ignored = include_ignored
|
|
446
456
|
self._ignore_args = ignore_args
|
|
447
457
|
self._ignore_kwargs = ignore_kwargs
|
|
448
|
-
self.
|
|
458
|
+
self._check_class_constructor = check_class_constructor
|
|
449
459
|
self._no_ansi = no_ansi
|
|
450
460
|
self._verbose = verbose
|
|
451
461
|
self._retcode = 0
|
|
452
462
|
self._gitignore = _Gitignore()
|
|
453
463
|
if string is not None:
|
|
454
464
|
self._add_module(
|
|
455
|
-
|
|
465
|
+
messages,
|
|
456
466
|
string=string,
|
|
457
467
|
ignore_args=ignore_args,
|
|
458
468
|
ignore_kwargs=ignore_kwargs,
|
|
@@ -484,11 +494,11 @@ class Modules(_t.List[Parent]): # pylint: disable=too-many-instance-attributes
|
|
|
484
494
|
|
|
485
495
|
if root.is_file():
|
|
486
496
|
self._add_module(
|
|
487
|
-
self.
|
|
497
|
+
self._messages,
|
|
488
498
|
root=root,
|
|
489
499
|
ignore_args=self._ignore_args,
|
|
490
500
|
ignore_kwargs=self._ignore_kwargs,
|
|
491
|
-
check_class_constructor=self.
|
|
501
|
+
check_class_constructor=self._check_class_constructor,
|
|
492
502
|
)
|
|
493
503
|
|
|
494
504
|
if root.is_dir():
|
|
@@ -7,13 +7,14 @@ from __future__ import annotations as _
|
|
|
7
7
|
|
|
8
8
|
import typing as _t
|
|
9
9
|
|
|
10
|
-
from ._message import Message as _Message
|
|
11
10
|
from ._module import Function as _Function
|
|
12
11
|
from ._stub import RETURN as _RETURN
|
|
13
12
|
from ._stub import Param as _Param
|
|
14
13
|
from ._utils import almost_equal as _almost_equal
|
|
15
14
|
from .messages import TEMPLATE as _TEMPLATE
|
|
16
15
|
from .messages import E as _E
|
|
16
|
+
from .messages import Message as _Message
|
|
17
|
+
from .messages import Messages as _Messages
|
|
17
18
|
|
|
18
19
|
_MIN_MATCH = 0.8
|
|
19
20
|
_MAX_MATCH = 1.0
|
|
@@ -31,8 +32,8 @@ class Report(_t.List[str]):
|
|
|
31
32
|
def __init__(
|
|
32
33
|
self,
|
|
33
34
|
func: _Function,
|
|
34
|
-
targets:
|
|
35
|
-
disable:
|
|
35
|
+
targets: _Messages,
|
|
36
|
+
disable: _Messages,
|
|
36
37
|
check_property_returns: bool,
|
|
37
38
|
) -> None:
|
|
38
39
|
super().__init__()
|
|
@@ -44,7 +45,7 @@ class Report(_t.List[str]):
|
|
|
44
45
|
|
|
45
46
|
self._disable.extend(errors)
|
|
46
47
|
|
|
47
|
-
self._errors
|
|
48
|
+
self._errors = _Messages()
|
|
48
49
|
self._func = func
|
|
49
50
|
self._no_prop_return = func.isproperty and not check_property_returns
|
|
50
51
|
self._no_returns = func.isinit or self._no_prop_return
|
|
@@ -172,18 +173,19 @@ class Report(_t.List[str]):
|
|
|
172
173
|
self._add(_E[116])
|
|
173
174
|
|
|
174
175
|
def _invalid_directive(self) -> None:
|
|
175
|
-
for
|
|
176
|
-
if not
|
|
177
|
-
err = _E[int(f"20{1 if
|
|
178
|
-
self._add(err, directive=
|
|
176
|
+
for comment in self._func.comments:
|
|
177
|
+
if not comment.isvalid:
|
|
178
|
+
err = _E[int(f"20{1 if comment.ismodule else 2}")]
|
|
179
|
+
self._add(err, directive=comment.kind)
|
|
179
180
|
|
|
180
181
|
def _invalid_directive_options(self) -> None:
|
|
181
|
-
for
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
for rule in directive.rules.unknown:
|
|
182
|
+
for comment in self._func.comments:
|
|
183
|
+
for rule in comment:
|
|
184
|
+
if not rule.isknown:
|
|
185
185
|
self._add(
|
|
186
|
-
|
|
186
|
+
_E[int(f"20{3 if comment.ismodule else 4}")],
|
|
187
|
+
directive=comment.kind,
|
|
188
|
+
option=rule.description,
|
|
187
189
|
)
|
|
188
190
|
|
|
189
191
|
def get_report(self, prefix: str = "") -> str:
|
|
@@ -249,6 +249,16 @@ class Signature(_Stub):
|
|
|
249
249
|
"""
|
|
250
250
|
return self._rettype
|
|
251
251
|
|
|
252
|
+
def overload(self, rettype: str | None) -> None:
|
|
253
|
+
"""Overload signature with a ret type.
|
|
254
|
+
|
|
255
|
+
:param rettype: Return type of overloaded signature.
|
|
256
|
+
"""
|
|
257
|
+
self._rettype = (
|
|
258
|
+
rettype if isinstance(rettype, str) else self._get_rettype(rettype)
|
|
259
|
+
)
|
|
260
|
+
self._returns = str(rettype) != "None"
|
|
261
|
+
|
|
252
262
|
|
|
253
263
|
class Docstring(_Stub):
|
|
254
264
|
"""Represents a function docstring.
|
|
@@ -11,6 +11,9 @@ from difflib import SequenceMatcher as _SequenceMatcher
|
|
|
11
11
|
|
|
12
12
|
import click as _click
|
|
13
13
|
|
|
14
|
+
from .messages import TEMPLATE as _TEMPLATE
|
|
15
|
+
from .messages import E as _E
|
|
16
|
+
|
|
14
17
|
|
|
15
18
|
def almost_equal(str1: str, str2: str, mini: float, maxi: float) -> bool:
|
|
16
19
|
"""Show result for more than the minimum but less than the maximum.
|
|
@@ -49,3 +52,9 @@ def pretty_print_error(
|
|
|
49
52
|
file=_sys.stderr,
|
|
50
53
|
color=not no_ansi and _sys.stderr.isatty(),
|
|
51
54
|
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def print_checks() -> None:
|
|
58
|
+
"""Print all available checks."""
|
|
59
|
+
for msg in _E.values():
|
|
60
|
+
_click.echo(msg.fstring(_TEMPLATE))
|
|
@@ -23,116 +23,196 @@ docsig.messages
|
|
|
23
23
|
| E204: unknown inline comment option for {directive} '{option}'
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
|
-
from
|
|
27
|
-
from ._message import Messages as _Messages
|
|
26
|
+
from __future__ import annotations
|
|
28
27
|
|
|
28
|
+
import typing as _t
|
|
29
|
+
|
|
30
|
+
#: Error code for unknown errors.
|
|
31
|
+
UNKNOWN = "E000"
|
|
32
|
+
|
|
33
|
+
#: Default template to format message strings.
|
|
29
34
|
TEMPLATE = "{code}: {description} ({symbolic})"
|
|
30
35
|
|
|
31
36
|
|
|
37
|
+
class Message(_t.NamedTuple):
|
|
38
|
+
"""Represents an error message."""
|
|
39
|
+
|
|
40
|
+
#: An error code the message can be referenced by.
|
|
41
|
+
code: str
|
|
42
|
+
|
|
43
|
+
#: A description of the error.
|
|
44
|
+
description: str
|
|
45
|
+
|
|
46
|
+
#: A shortened description the message can be referenced by.
|
|
47
|
+
symbolic: str = ""
|
|
48
|
+
|
|
49
|
+
#: A hint, if any, suggesting why the error may have occurred.
|
|
50
|
+
hint: _t.Optional[str] = None
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def isknown(self) -> bool:
|
|
54
|
+
"""Whether this is a known error.
|
|
55
|
+
|
|
56
|
+
This might exist due to a typo or an attempt to retrieve an
|
|
57
|
+
error that does not exist.
|
|
58
|
+
"""
|
|
59
|
+
return self.code != UNKNOWN
|
|
60
|
+
|
|
61
|
+
def fstring(self, template: str) -> str:
|
|
62
|
+
"""Return message values as a string.
|
|
63
|
+
|
|
64
|
+
:param template: String to interpolate values.
|
|
65
|
+
:return: Formatted string.
|
|
66
|
+
"""
|
|
67
|
+
return template.format(
|
|
68
|
+
code=self.code,
|
|
69
|
+
description=self.description,
|
|
70
|
+
symbolic=self.symbolic,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class Messages(_t.List[Message]):
|
|
75
|
+
"""List of messages."""
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class MessageMap(_t.Dict[int, Message]):
|
|
79
|
+
"""Messages mapped under an integer version of their codes.."""
|
|
80
|
+
|
|
81
|
+
def from_ref(self, ref: str) -> Message:
|
|
82
|
+
"""Get a message by its code or symbolic reference.
|
|
83
|
+
|
|
84
|
+
:param ref: Code or symbolic reference.
|
|
85
|
+
:return: Message if valid ref else an unknown message type.
|
|
86
|
+
"""
|
|
87
|
+
for value in self.values():
|
|
88
|
+
if ref in (value.code, value.symbolic):
|
|
89
|
+
return value
|
|
90
|
+
|
|
91
|
+
return Message(UNKNOWN, ref)
|
|
92
|
+
|
|
93
|
+
def from_codes(self, refs: list[str]) -> Messages:
|
|
94
|
+
"""Get list of message types from codes or symbolic references.
|
|
95
|
+
|
|
96
|
+
:param refs: List of codes or symbolic references.
|
|
97
|
+
:return: List of message types.
|
|
98
|
+
"""
|
|
99
|
+
return Messages(self.from_ref(i) for i in refs)
|
|
100
|
+
|
|
101
|
+
def all(self, category: int) -> Messages:
|
|
102
|
+
"""Get all messages belonging to a category.
|
|
103
|
+
|
|
104
|
+
:param category: Index of message category.
|
|
105
|
+
:return: List of all message objects belonging to category.
|
|
106
|
+
"""
|
|
107
|
+
return Messages(
|
|
108
|
+
v for k, v in self.items() if str(k).startswith(str(category))
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
32
112
|
# Exxx: Error
|
|
33
|
-
E =
|
|
113
|
+
E = MessageMap(
|
|
34
114
|
{
|
|
35
115
|
# E1xx: Docstring
|
|
36
|
-
101:
|
|
116
|
+
101: Message(
|
|
37
117
|
"E101",
|
|
38
118
|
"parameters out of order",
|
|
39
119
|
"params-out-of-order",
|
|
40
120
|
),
|
|
41
|
-
102:
|
|
121
|
+
102: Message(
|
|
42
122
|
"E102",
|
|
43
123
|
"includes parameters that do not exist",
|
|
44
124
|
"params-do-not-exist",
|
|
45
125
|
),
|
|
46
|
-
103:
|
|
126
|
+
103: Message(
|
|
47
127
|
"E103",
|
|
48
128
|
"parameters missing",
|
|
49
129
|
"params-missing",
|
|
50
130
|
),
|
|
51
|
-
104:
|
|
131
|
+
104: Message(
|
|
52
132
|
"E104",
|
|
53
133
|
"return statement documented for None",
|
|
54
134
|
"return-documented-for-none",
|
|
55
135
|
),
|
|
56
|
-
105:
|
|
136
|
+
105: Message(
|
|
57
137
|
"E105",
|
|
58
138
|
"return missing from docstring",
|
|
59
139
|
"return-missing",
|
|
60
140
|
"it is possible a syntax error could be causing this",
|
|
61
141
|
),
|
|
62
|
-
106:
|
|
142
|
+
106: Message(
|
|
63
143
|
"E106",
|
|
64
144
|
"duplicate parameters found",
|
|
65
145
|
"duplicate-params-found",
|
|
66
146
|
),
|
|
67
|
-
107:
|
|
147
|
+
107: Message(
|
|
68
148
|
"E107",
|
|
69
149
|
"parameter appears to be incorrectly documented",
|
|
70
150
|
"param-incorrectly-documented",
|
|
71
151
|
),
|
|
72
|
-
108:
|
|
152
|
+
108: Message(
|
|
73
153
|
"E108",
|
|
74
154
|
"return statement documented for property",
|
|
75
155
|
"return-documented-for-property",
|
|
76
156
|
"documentation is sufficient as a getter is the value returned",
|
|
77
157
|
),
|
|
78
|
-
109:
|
|
158
|
+
109: Message(
|
|
79
159
|
"E109",
|
|
80
160
|
"cannot determine whether a return statement should exist or not",
|
|
81
161
|
"confirm-return-needed",
|
|
82
162
|
),
|
|
83
|
-
110:
|
|
163
|
+
110: Message(
|
|
84
164
|
"E110",
|
|
85
165
|
"documented parameter not equal to its respective argument",
|
|
86
166
|
"param-not-equal-to-arg",
|
|
87
167
|
),
|
|
88
|
-
111:
|
|
168
|
+
111: Message(
|
|
89
169
|
"E111",
|
|
90
170
|
"return statement documented for class",
|
|
91
171
|
"class-return-documented",
|
|
92
172
|
"a class does not return a value during instantiation",
|
|
93
173
|
),
|
|
94
|
-
112:
|
|
174
|
+
112: Message(
|
|
95
175
|
"E112",
|
|
96
176
|
"spelling error found in documented parameter",
|
|
97
177
|
"spelling-error",
|
|
98
178
|
),
|
|
99
|
-
113:
|
|
179
|
+
113: Message(
|
|
100
180
|
"E113",
|
|
101
181
|
"function is missing a docstring",
|
|
102
182
|
"function-doc-missing",
|
|
103
183
|
),
|
|
104
|
-
114:
|
|
184
|
+
114: Message(
|
|
105
185
|
"E114",
|
|
106
186
|
"class is missing a docstring",
|
|
107
187
|
"class-doc-missing",
|
|
108
188
|
),
|
|
109
|
-
115:
|
|
189
|
+
115: Message(
|
|
110
190
|
"E115",
|
|
111
191
|
"syntax error in description",
|
|
112
192
|
"syntax-error-in-description",
|
|
113
193
|
),
|
|
114
|
-
116:
|
|
194
|
+
116: Message(
|
|
115
195
|
"E116",
|
|
116
196
|
"param not indented correctly",
|
|
117
197
|
"incorrect-indent",
|
|
118
198
|
),
|
|
119
199
|
# E2xx: Config
|
|
120
|
-
201:
|
|
200
|
+
201: Message(
|
|
121
201
|
"E201",
|
|
122
202
|
"unknown module comment directive '{directive}'",
|
|
123
203
|
"unknown-module-directive",
|
|
124
204
|
),
|
|
125
|
-
202:
|
|
205
|
+
202: Message(
|
|
126
206
|
"E202",
|
|
127
207
|
"unknown inline comment directive '{directive}'",
|
|
128
208
|
"unknown-inline-directive",
|
|
129
209
|
),
|
|
130
|
-
203:
|
|
210
|
+
203: Message(
|
|
131
211
|
"E203",
|
|
132
212
|
"unknown module comment option for {directive} '{option}'",
|
|
133
213
|
"unknown-module-directive-option",
|
|
134
214
|
),
|
|
135
|
-
204:
|
|
215
|
+
204: Message(
|
|
136
216
|
"E204",
|
|
137
217
|
"unknown inline comment option for {directive} '{option}'",
|
|
138
218
|
"unknown-inline-directive-option",
|
|
@@ -63,7 +63,7 @@ maintainers = [
|
|
|
63
63
|
name = "docsig"
|
|
64
64
|
readme = "README.rst"
|
|
65
65
|
repository = "https://github.com/jshwi/docsig"
|
|
66
|
-
version = "0.
|
|
66
|
+
version = "0.52.0"
|
|
67
67
|
|
|
68
68
|
[tool.poetry.dependencies]
|
|
69
69
|
Pygments = "^2.13.0"
|
|
@@ -96,7 +96,6 @@ audit = [
|
|
|
96
96
|
"about-tests",
|
|
97
97
|
"commit-policy",
|
|
98
98
|
"copyright-year",
|
|
99
|
-
"docs",
|
|
100
99
|
"files",
|
|
101
100
|
"format",
|
|
102
101
|
"format-docs",
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
docsig._disable
|
|
3
|
-
===============
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations as _
|
|
7
|
-
|
|
8
|
-
import re as _re
|
|
9
|
-
import tokenize as _tokenize
|
|
10
|
-
import typing as _t
|
|
11
|
-
from io import StringIO as _StringIO
|
|
12
|
-
|
|
13
|
-
from ._message import Message as _Message
|
|
14
|
-
from .messages import E as _E
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class _Rules(_t.List[_Message]):
|
|
18
|
-
def __init__(self, kind: str) -> None:
|
|
19
|
-
super().__init__()
|
|
20
|
-
self._unknown = []
|
|
21
|
-
self._kind = kind
|
|
22
|
-
delimiter = _re.search(r"\W+", kind)
|
|
23
|
-
if delimiter and delimiter[0] == "=":
|
|
24
|
-
self._kind, option = kind.split("=")
|
|
25
|
-
message = _E.fromref(option)
|
|
26
|
-
if "," in option:
|
|
27
|
-
values = option.split(",")
|
|
28
|
-
for value in values:
|
|
29
|
-
message = _E.fromref(value)
|
|
30
|
-
if message.isknown:
|
|
31
|
-
self.append(message)
|
|
32
|
-
else:
|
|
33
|
-
self._unknown.append(message)
|
|
34
|
-
elif message.isknown:
|
|
35
|
-
self.append(message)
|
|
36
|
-
else:
|
|
37
|
-
self._unknown.append(message)
|
|
38
|
-
else:
|
|
39
|
-
self.extend(_E.all(1))
|
|
40
|
-
|
|
41
|
-
@property
|
|
42
|
-
def kind(self) -> str:
|
|
43
|
-
"""The type of the directive these rules belong to."""
|
|
44
|
-
return self._kind
|
|
45
|
-
|
|
46
|
-
@property
|
|
47
|
-
def unknown(self) -> list[_Message]:
|
|
48
|
-
"""List of unknown directive options if any."""
|
|
49
|
-
return self._unknown
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class Directive:
|
|
53
|
-
"""Represents a comment directive.
|
|
54
|
-
|
|
55
|
-
:param kind: The type of this directive.
|
|
56
|
-
:param col: The column this directive is positioned at.
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
_valid_kinds = "enable", "disable"
|
|
60
|
-
|
|
61
|
-
def __init__(self, kind: str, col: int) -> None:
|
|
62
|
-
self._ismodule = col == 0
|
|
63
|
-
self._rules = _Rules(kind)
|
|
64
|
-
self._kind = self._rules.kind
|
|
65
|
-
|
|
66
|
-
@property
|
|
67
|
-
def kind(self) -> str:
|
|
68
|
-
"""The type of this directive."""
|
|
69
|
-
return self._kind
|
|
70
|
-
|
|
71
|
-
@property
|
|
72
|
-
def isvalid(self) -> bool:
|
|
73
|
-
"""Whether this directive is valid or not."""
|
|
74
|
-
return self._kind in self._valid_kinds
|
|
75
|
-
|
|
76
|
-
@property
|
|
77
|
-
def rules(self) -> _Rules:
|
|
78
|
-
"""The rules, if any, associated with this directive."""
|
|
79
|
-
return self._rules
|
|
80
|
-
|
|
81
|
-
@property
|
|
82
|
-
def ismodule(self) -> bool:
|
|
83
|
-
"""Whether this is a module level directive or not."""
|
|
84
|
-
return self._ismodule
|
|
85
|
-
|
|
86
|
-
@property
|
|
87
|
-
def enable(self) -> bool:
|
|
88
|
-
"""Whether this is a enable directive or not."""
|
|
89
|
-
return self._kind == self._valid_kinds[0]
|
|
90
|
-
|
|
91
|
-
@property
|
|
92
|
-
def disable(self) -> bool:
|
|
93
|
-
"""Whether this is a disable directive or not."""
|
|
94
|
-
return self._kind == self._valid_kinds[1]
|
|
95
|
-
|
|
96
|
-
@classmethod
|
|
97
|
-
def parse(cls, comment: str, col: int) -> Directive | None:
|
|
98
|
-
"""Parse string into directive object if possible.
|
|
99
|
-
|
|
100
|
-
:param comment: Comment to parse.
|
|
101
|
-
:param col: Column of comment to instantiate directive.
|
|
102
|
-
:return: Instantiated directive object if valid directive or
|
|
103
|
-
None if not a valid directive.
|
|
104
|
-
"""
|
|
105
|
-
if comment[1:].strip().startswith(f"{__package__}:"):
|
|
106
|
-
return cls(comment.split(":")[1].strip(), col)
|
|
107
|
-
|
|
108
|
-
return None
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
class Directives(
|
|
112
|
-
_t.Dict[int, _t.Tuple[_t.List[Directive], _t.List[_Message]]]
|
|
113
|
-
):
|
|
114
|
-
"""Data for directives:
|
|
115
|
-
|
|
116
|
-
Dict like object with the line number of directive as the key and
|
|
117
|
-
total errors which are excluded from function checks.
|
|
118
|
-
|
|
119
|
-
:param text: Python code.
|
|
120
|
-
:param disable: List of checks to disable.
|
|
121
|
-
"""
|
|
122
|
-
|
|
123
|
-
def __init__(self, text: str, disable: list[_Message]) -> None:
|
|
124
|
-
super().__init__()
|
|
125
|
-
fin = _StringIO(text)
|
|
126
|
-
module_disables = list(disable)
|
|
127
|
-
module_directives: list[Directive] = []
|
|
128
|
-
directive = None
|
|
129
|
-
for line in _tokenize.generate_tokens(fin.readline):
|
|
130
|
-
if line.type in (_tokenize.NAME, _tokenize.OP, _tokenize.DEDENT):
|
|
131
|
-
continue
|
|
132
|
-
|
|
133
|
-
lineno, col = line.start
|
|
134
|
-
if line.type == _tokenize.COMMENT:
|
|
135
|
-
# ensure previous directive as backup assignment because
|
|
136
|
-
# if this is just a regular comment it will override a
|
|
137
|
-
# valid module directive, making it None
|
|
138
|
-
directive = Directive.parse(line.string, col) or directive
|
|
139
|
-
if directive is not None:
|
|
140
|
-
update_directives = [directive] + module_directives
|
|
141
|
-
update = module_disables
|
|
142
|
-
if directive.isvalid:
|
|
143
|
-
if directive.disable:
|
|
144
|
-
update = directive.rules + module_disables
|
|
145
|
-
elif directive.enable:
|
|
146
|
-
update = [
|
|
147
|
-
i
|
|
148
|
-
for i in module_disables
|
|
149
|
-
if i not in directive.rules
|
|
150
|
-
]
|
|
151
|
-
|
|
152
|
-
if directive.ismodule:
|
|
153
|
-
module_disables = update
|
|
154
|
-
module_directives = update_directives
|
|
155
|
-
else:
|
|
156
|
-
self[lineno] = update_directives, update
|
|
157
|
-
|
|
158
|
-
if lineno not in self:
|
|
159
|
-
self[lineno] = list(module_directives), list(module_disables)
|
docsig-0.51.0/docsig/_message.py
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
docsig._message
|
|
3
|
-
===============
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations as _
|
|
7
|
-
|
|
8
|
-
import typing as _t
|
|
9
|
-
|
|
10
|
-
UNKNOWN = "E000"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Message(_t.NamedTuple):
|
|
14
|
-
"""Message type for errors."""
|
|
15
|
-
|
|
16
|
-
code: str
|
|
17
|
-
description: str
|
|
18
|
-
symbolic: str = ""
|
|
19
|
-
hint: _t.Optional[str] = None
|
|
20
|
-
|
|
21
|
-
@property
|
|
22
|
-
def isknown(self) -> bool:
|
|
23
|
-
"""Whether this is a known error."""
|
|
24
|
-
return self.code != UNKNOWN
|
|
25
|
-
|
|
26
|
-
def fstring(self, template: str) -> str:
|
|
27
|
-
"""Return values as a format string.
|
|
28
|
-
|
|
29
|
-
:param template: String to interpolate values.
|
|
30
|
-
:return: Formatted string.
|
|
31
|
-
"""
|
|
32
|
-
return template.format(
|
|
33
|
-
code=self.code,
|
|
34
|
-
description=self.description,
|
|
35
|
-
symbolic=self.symbolic,
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class Messages(_t.Dict[int, Message]):
|
|
40
|
-
"""Object for storing and retrieving message objects."""
|
|
41
|
-
|
|
42
|
-
def fromref(self, ref: str) -> Message:
|
|
43
|
-
"""Get a message by its code or symbolic reference.
|
|
44
|
-
|
|
45
|
-
:param ref: Code or symbolic reference.
|
|
46
|
-
:return: Message if valid ref else an unknown message type.
|
|
47
|
-
"""
|
|
48
|
-
for value in self.values():
|
|
49
|
-
if ref in (value.code, value.symbolic):
|
|
50
|
-
return value
|
|
51
|
-
|
|
52
|
-
return Message(UNKNOWN, ref)
|
|
53
|
-
|
|
54
|
-
def fromcodes(self, refs: list[str]) -> tuple[Message, ...]:
|
|
55
|
-
"""Get tuple of message types from codes or symbolic references.
|
|
56
|
-
|
|
57
|
-
:param refs: Tuple of codes or symbolic references.
|
|
58
|
-
:return: Tuple of message types.
|
|
59
|
-
"""
|
|
60
|
-
return tuple(self.fromref(i) for i in refs)
|
|
61
|
-
|
|
62
|
-
def all(self, category: int) -> tuple[Message, ...]:
|
|
63
|
-
"""Get all messages belonging to a category.
|
|
64
|
-
|
|
65
|
-
:param category: Index of message category.
|
|
66
|
-
:return: Tuple of all message objects belonging to category.
|
|
67
|
-
"""
|
|
68
|
-
return tuple(
|
|
69
|
-
v for k, v in self.items() if str(k).startswith(str(category))
|
|
70
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|