docsig 0.55.0__tar.gz → 0.57.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.55.0 → docsig-0.57.0}/PKG-INFO +46 -11
- {docsig-0.55.0 → docsig-0.57.0}/README.rst +44 -8
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_hooks.py +1 -1
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_report.py +21 -21
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_version.py +1 -1
- {docsig-0.55.0 → docsig-0.57.0}/docsig/messages.py +42 -29
- docsig-0.57.0/docsig/plugin.py +165 -0
- {docsig-0.55.0 → docsig-0.57.0}/pyproject.toml +95 -5
- {docsig-0.55.0 → docsig-0.57.0}/LICENSE +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/__init__.py +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/__main__.py +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_config.py +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_core.py +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_decorators.py +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_directives.py +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_main.py +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_module.py +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_stub.py +0 -0
- {docsig-0.55.0 → docsig-0.57.0}/docsig/_utils.py +0 -0
- {docsig-0.55.0 → docsig-0.57.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.57.0
|
|
4
4
|
Summary: Check signature params for proper documentation
|
|
5
5
|
Home-page: https://pypi.org/project/docsig/
|
|
6
6
|
License: MIT
|
|
@@ -9,10 +9,9 @@ Author: jshwi
|
|
|
9
9
|
Author-email: stephen@jshwisolutions.com
|
|
10
10
|
Maintainer: jshwi
|
|
11
11
|
Maintainer-email: stephen@jshwisolutions.com
|
|
12
|
-
Requires-Python: >=3.8,<4.0
|
|
12
|
+
Requires-Python: >=3.8.1,<4.0.0
|
|
13
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -152,16 +151,49 @@ Options can also be configured with the pyproject.toml file
|
|
|
152
151
|
check-overridden = false
|
|
153
152
|
check-protected = false
|
|
154
153
|
disable = [
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
154
|
+
"SIG101",
|
|
155
|
+
"SIG102",
|
|
156
|
+
"SIG402",
|
|
158
157
|
]
|
|
159
158
|
target = [
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
159
|
+
"SIG202",
|
|
160
|
+
"SIG203",
|
|
161
|
+
"SIG201",
|
|
163
162
|
]
|
|
164
163
|
|
|
164
|
+
Flake8
|
|
165
|
+
******
|
|
166
|
+
|
|
167
|
+
``docsig`` can also be used as a ``flake8`` plugin. Install ``flake8`` and
|
|
168
|
+
ensure your installation has registered `docsig`
|
|
169
|
+
|
|
170
|
+
.. code-block:: console
|
|
171
|
+
|
|
172
|
+
$ flake8 --version
|
|
173
|
+
7.1.0 (docsig: 0.57.0, mccabe: 0.7.0, pycodestyle: 2.12.0, pyflakes: 3.2.0) CPython 3.8.13 on Darwin
|
|
174
|
+
|
|
175
|
+
And now use `flake8` to lint your files
|
|
176
|
+
|
|
177
|
+
.. code-block:: console
|
|
178
|
+
|
|
179
|
+
$ flake8 example.py
|
|
180
|
+
example.py:1:1: SIG202 includes parameters that do not exist (params-do-not-exist) 'function'
|
|
181
|
+
|
|
182
|
+
With ``flake8`` the pyproject.toml config will still be the base config, though the
|
|
183
|
+
`ini files <https://flake8.pycqa.org/en/latest/user/configuration.html#configuration-locations>`_ ``flake8`` gets it config from will override the pyproject.toml config.
|
|
184
|
+
For ``flake8`` all args and config options are prefixed with ``sig`` to
|
|
185
|
+
avoid any potential conflicts with other plugins
|
|
186
|
+
|
|
187
|
+
.. code-block:: ini
|
|
188
|
+
|
|
189
|
+
[flake8]
|
|
190
|
+
sig-check-dunders = True
|
|
191
|
+
sig-check-overridden = True
|
|
192
|
+
sig-check-protected = True
|
|
193
|
+
|
|
194
|
+
..
|
|
195
|
+
end flake8
|
|
196
|
+
|
|
165
197
|
API
|
|
166
198
|
***
|
|
167
199
|
|
|
@@ -196,7 +228,7 @@ API
|
|
|
196
228
|
... """
|
|
197
229
|
>>> docsig(string=string, no_ansi=True)
|
|
198
230
|
2 in function
|
|
199
|
-
|
|
231
|
+
SIG202: includes parameters that do not exist (params-do-not-exist)
|
|
200
232
|
1
|
|
201
233
|
|
|
202
234
|
A full list of checks can be found `here <https://docsig.readthedocs.io/en/latest/usage/messages.html>`__
|
|
@@ -204,6 +236,9 @@ A full list of checks can be found `here <https://docsig.readthedocs.io/en/lates
|
|
|
204
236
|
Message Control
|
|
205
237
|
***************
|
|
206
238
|
|
|
239
|
+
If you have been using ``docsig`` prior to ``v0.56.0``, please see
|
|
240
|
+
`updated messages <https://docsig.readthedocs.io/en/latest/deprecated/messages.html>`_
|
|
241
|
+
|
|
207
242
|
`Documentation on message control <https://docsig.readthedocs.io/en/latest/usage/message-control.html>`_
|
|
208
243
|
|
|
209
244
|
Classes
|
|
@@ -222,7 +257,7 @@ It can be added to your .pre-commit-config.yaml as follows:
|
|
|
222
257
|
|
|
223
258
|
repos:
|
|
224
259
|
- repo: https://github.com/jshwi/docsig
|
|
225
|
-
rev: v0.
|
|
260
|
+
rev: v0.57.0
|
|
226
261
|
hooks:
|
|
227
262
|
- id: docsig
|
|
228
263
|
args:
|
|
@@ -124,16 +124,49 @@ Options can also be configured with the pyproject.toml file
|
|
|
124
124
|
check-overridden = false
|
|
125
125
|
check-protected = false
|
|
126
126
|
disable = [
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
127
|
+
"SIG101",
|
|
128
|
+
"SIG102",
|
|
129
|
+
"SIG402",
|
|
130
130
|
]
|
|
131
131
|
target = [
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
132
|
+
"SIG202",
|
|
133
|
+
"SIG203",
|
|
134
|
+
"SIG201",
|
|
135
135
|
]
|
|
136
136
|
|
|
137
|
+
Flake8
|
|
138
|
+
******
|
|
139
|
+
|
|
140
|
+
``docsig`` can also be used as a ``flake8`` plugin. Install ``flake8`` and
|
|
141
|
+
ensure your installation has registered `docsig`
|
|
142
|
+
|
|
143
|
+
.. code-block:: console
|
|
144
|
+
|
|
145
|
+
$ flake8 --version
|
|
146
|
+
7.1.0 (docsig: 0.57.0, mccabe: 0.7.0, pycodestyle: 2.12.0, pyflakes: 3.2.0) CPython 3.8.13 on Darwin
|
|
147
|
+
|
|
148
|
+
And now use `flake8` to lint your files
|
|
149
|
+
|
|
150
|
+
.. code-block:: console
|
|
151
|
+
|
|
152
|
+
$ flake8 example.py
|
|
153
|
+
example.py:1:1: SIG202 includes parameters that do not exist (params-do-not-exist) 'function'
|
|
154
|
+
|
|
155
|
+
With ``flake8`` the pyproject.toml config will still be the base config, though the
|
|
156
|
+
`ini files <https://flake8.pycqa.org/en/latest/user/configuration.html#configuration-locations>`_ ``flake8`` gets it config from will override the pyproject.toml config.
|
|
157
|
+
For ``flake8`` all args and config options are prefixed with ``sig`` to
|
|
158
|
+
avoid any potential conflicts with other plugins
|
|
159
|
+
|
|
160
|
+
.. code-block:: ini
|
|
161
|
+
|
|
162
|
+
[flake8]
|
|
163
|
+
sig-check-dunders = True
|
|
164
|
+
sig-check-overridden = True
|
|
165
|
+
sig-check-protected = True
|
|
166
|
+
|
|
167
|
+
..
|
|
168
|
+
end flake8
|
|
169
|
+
|
|
137
170
|
API
|
|
138
171
|
***
|
|
139
172
|
|
|
@@ -168,7 +201,7 @@ API
|
|
|
168
201
|
... """
|
|
169
202
|
>>> docsig(string=string, no_ansi=True)
|
|
170
203
|
2 in function
|
|
171
|
-
|
|
204
|
+
SIG202: includes parameters that do not exist (params-do-not-exist)
|
|
172
205
|
1
|
|
173
206
|
|
|
174
207
|
A full list of checks can be found `here <https://docsig.readthedocs.io/en/latest/usage/messages.html>`__
|
|
@@ -176,6 +209,9 @@ A full list of checks can be found `here <https://docsig.readthedocs.io/en/lates
|
|
|
176
209
|
Message Control
|
|
177
210
|
***************
|
|
178
211
|
|
|
212
|
+
If you have been using ``docsig`` prior to ``v0.56.0``, please see
|
|
213
|
+
`updated messages <https://docsig.readthedocs.io/en/latest/deprecated/messages.html>`_
|
|
214
|
+
|
|
179
215
|
`Documentation on message control <https://docsig.readthedocs.io/en/latest/usage/message-control.html>`_
|
|
180
216
|
|
|
181
217
|
Classes
|
|
@@ -194,7 +230,7 @@ It can be added to your .pre-commit-config.yaml as follows:
|
|
|
194
230
|
|
|
195
231
|
repos:
|
|
196
232
|
- repo: https://github.com/jshwi/docsig
|
|
197
|
-
rev: v0.
|
|
233
|
+
rev: v0.57.0
|
|
198
234
|
hooks:
|
|
199
235
|
- id: docsig
|
|
200
236
|
args:
|
|
@@ -14,7 +14,7 @@ def excepthook(no_ansi: bool = False) -> None:
|
|
|
14
14
|
|
|
15
15
|
:param no_ansi: Disable ANSI output.
|
|
16
16
|
"""
|
|
17
|
-
if _e.get("DOCSIG_DEBUG"
|
|
17
|
+
if _e.get("DOCSIG_DEBUG") != "1":
|
|
18
18
|
_sys.excepthook = lambda x, y, _: _pretty_print_error(
|
|
19
19
|
x, str(y), no_ansi
|
|
20
20
|
)
|
|
@@ -80,24 +80,24 @@ class Failure(_t.List[str]):
|
|
|
80
80
|
if not comment.isvalid:
|
|
81
81
|
if comment.ismodule:
|
|
82
82
|
# unknown-module-directive
|
|
83
|
-
self._add(_E[
|
|
83
|
+
self._add(_E[1], directive=comment.kind)
|
|
84
84
|
else:
|
|
85
85
|
# unknown-inline-directive
|
|
86
|
-
self._add(_E[
|
|
86
|
+
self._add(_E[2], directive=comment.kind)
|
|
87
87
|
else:
|
|
88
88
|
for rule in comment:
|
|
89
89
|
if not rule.isknown:
|
|
90
90
|
if comment.ismodule:
|
|
91
91
|
# unknown-module-directive-option
|
|
92
92
|
self._add(
|
|
93
|
-
_E[
|
|
93
|
+
_E[3],
|
|
94
94
|
directive=comment.kind,
|
|
95
95
|
option=rule.description,
|
|
96
96
|
)
|
|
97
97
|
else:
|
|
98
98
|
# unknown-inline-directive-option
|
|
99
99
|
self._add(
|
|
100
|
-
_E[
|
|
100
|
+
_E[4],
|
|
101
101
|
directive=comment.kind,
|
|
102
102
|
option=rule.description,
|
|
103
103
|
)
|
|
@@ -105,10 +105,10 @@ class Failure(_t.List[str]):
|
|
|
105
105
|
def _sig1xx_missing(self) -> None:
|
|
106
106
|
if not self._func.isinit:
|
|
107
107
|
# function-doc-missing
|
|
108
|
-
self._add(_E[
|
|
108
|
+
self._add(_E[101])
|
|
109
109
|
else:
|
|
110
110
|
# class-doc-missing
|
|
111
|
-
self._add(_E[
|
|
111
|
+
self._add(_E[102])
|
|
112
112
|
|
|
113
113
|
def _sig2xx_signature(self) -> None:
|
|
114
114
|
if self._func.docstring.args.duplicated:
|
|
@@ -120,7 +120,7 @@ class Failure(_t.List[str]):
|
|
|
120
120
|
self._func.docstring.args.pop(count)
|
|
121
121
|
|
|
122
122
|
# duplicate-params-found
|
|
123
|
-
self._add(_E[
|
|
123
|
+
self._add(_E[201])
|
|
124
124
|
# there are non-existing params in the docstring
|
|
125
125
|
elif len(self._func.docstring.args) > len(self._func.signature.args):
|
|
126
126
|
# pop the parameters that do not exist so that they are
|
|
@@ -133,7 +133,7 @@ class Failure(_t.List[str]):
|
|
|
133
133
|
if count > len(self._func.signature.args):
|
|
134
134
|
self._func.docstring.args.pop(count - 1)
|
|
135
135
|
# params-do-not-exist
|
|
136
|
-
self._add(_E[
|
|
136
|
+
self._add(_E[202])
|
|
137
137
|
# there are more args in sig than doc, so doc params missing
|
|
138
138
|
elif len(self._func.signature.args) > len(self._func.docstring.args):
|
|
139
139
|
# append the parameters that are missing so that they are
|
|
@@ -148,33 +148,33 @@ class Failure(_t.List[str]):
|
|
|
148
148
|
_Param(arg.kind, arg.name, _VALID_DESCRIPTION, 0)
|
|
149
149
|
)
|
|
150
150
|
# params-missing
|
|
151
|
-
self._add(_E[
|
|
151
|
+
self._add(_E[203])
|
|
152
152
|
|
|
153
153
|
def _sig3xx_description(self, doc: _Param) -> None:
|
|
154
154
|
if doc.description is None:
|
|
155
|
-
self._add(_E[
|
|
155
|
+
self._add(_E[301])
|
|
156
156
|
elif doc.description is not None and not doc.description.startswith(
|
|
157
157
|
" "
|
|
158
158
|
):
|
|
159
159
|
# syntax-error-in-description
|
|
160
|
-
self._add(_E[
|
|
160
|
+
self._add(_E[302])
|
|
161
161
|
# if the parameter does not have a name, but exists, then it
|
|
162
162
|
# must be incorrectly documented
|
|
163
163
|
elif doc.name == _UNNAMED:
|
|
164
164
|
# param-incorrectly-documented
|
|
165
|
-
self._add(_E[
|
|
165
|
+
self._add(_E[303])
|
|
166
166
|
|
|
167
167
|
def _sig4xx_parameters(self, doc: _Param, sig: _Param) -> None:
|
|
168
168
|
if doc.indent > 0:
|
|
169
169
|
# incorrect-indent
|
|
170
|
-
self._add(_E[
|
|
170
|
+
self._add(_E[401])
|
|
171
171
|
elif doc != sig:
|
|
172
172
|
if (
|
|
173
173
|
sig.name in self._func.docstring.args.names
|
|
174
174
|
or doc.name in self.func.signature.args.names
|
|
175
175
|
):
|
|
176
176
|
# params-out-of-order
|
|
177
|
-
self._add(_E[
|
|
177
|
+
self._add(_E[402])
|
|
178
178
|
elif (
|
|
179
179
|
doc.name != _UNNAMED
|
|
180
180
|
and sig.name is not None
|
|
@@ -182,10 +182,10 @@ class Failure(_t.List[str]):
|
|
|
182
182
|
):
|
|
183
183
|
if _almost_equal(sig.name, doc.name, _MIN_MATCH, _MAX_MATCH):
|
|
184
184
|
# spelling-error
|
|
185
|
-
self._add(_E[
|
|
185
|
+
self._add(_E[403])
|
|
186
186
|
else:
|
|
187
187
|
# param-not-equal-to-arg
|
|
188
|
-
self._add(_E[
|
|
188
|
+
self._add(_E[404])
|
|
189
189
|
|
|
190
190
|
def _sig5xx_returns(self) -> None:
|
|
191
191
|
if not self._func.isinit and not (
|
|
@@ -194,28 +194,28 @@ class Failure(_t.List[str]):
|
|
|
194
194
|
# no types, cannot know either way
|
|
195
195
|
if self._func.signature.rettype == _RetType.UNTYPED:
|
|
196
196
|
# confirm-return-needed
|
|
197
|
-
self._add(_E[
|
|
197
|
+
self._add(_E[501], hint=True)
|
|
198
198
|
# return type is none, so no return should be documented
|
|
199
199
|
elif self._func.docstring.returns:
|
|
200
200
|
if self._func.signature.rettype == _RetType.NONE:
|
|
201
201
|
# return-documented-for-none
|
|
202
|
-
self._add(_E[
|
|
202
|
+
self._add(_E[502])
|
|
203
203
|
# return type is some, so return should be documented
|
|
204
204
|
elif self._func.signature.returns:
|
|
205
205
|
# return-missing
|
|
206
206
|
self._add(
|
|
207
|
-
_E[
|
|
207
|
+
_E[503],
|
|
208
208
|
hint=_has_bad_return(str(self._func.docstring.string)),
|
|
209
209
|
)
|
|
210
210
|
elif self._func.docstring.returns:
|
|
211
211
|
# method is init, so no return should be documented
|
|
212
212
|
if self._func.isinit:
|
|
213
213
|
# class-return-documented
|
|
214
|
-
self._add(_E[
|
|
214
|
+
self._add(_E[504], hint=True)
|
|
215
215
|
# method is property and not set to document property
|
|
216
216
|
elif self._func.isproperty and not self._check_property_returns:
|
|
217
217
|
# return-documented-for-property
|
|
218
|
-
self._add(_E[
|
|
218
|
+
self._add(_E[505], hint=True)
|
|
219
219
|
|
|
220
220
|
@property
|
|
221
221
|
def func(self) -> _Function:
|
|
@@ -6,12 +6,16 @@ docsig.messages
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import typing as _t
|
|
9
|
+
from warnings import warn as _warn
|
|
9
10
|
|
|
10
11
|
#: Error code for unknown errors.
|
|
11
|
-
UNKNOWN = "
|
|
12
|
+
UNKNOWN = "SIG000"
|
|
12
13
|
|
|
13
14
|
#: Default template to format message strings.
|
|
14
|
-
TEMPLATE = "{
|
|
15
|
+
TEMPLATE = "{ref}: {description} ({symbolic})"
|
|
16
|
+
|
|
17
|
+
#: Flake8 template to format message strings.
|
|
18
|
+
FLAKE8 = "{ref} {description} ({symbolic})"
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
class Message(_t.NamedTuple):
|
|
@@ -39,7 +43,7 @@ class Message(_t.NamedTuple):
|
|
|
39
43
|
This might exist due to a typo or an attempt to retrieve an
|
|
40
44
|
error that does not exist.
|
|
41
45
|
"""
|
|
42
|
-
return self.
|
|
46
|
+
return self.ref != UNKNOWN
|
|
43
47
|
|
|
44
48
|
def fstring(self, template: str) -> str:
|
|
45
49
|
"""Return message values as a string.
|
|
@@ -48,7 +52,7 @@ class Message(_t.NamedTuple):
|
|
|
48
52
|
:return: Formatted string.
|
|
49
53
|
"""
|
|
50
54
|
return template.format(
|
|
51
|
-
|
|
55
|
+
ref=self.ref,
|
|
52
56
|
description=self.description,
|
|
53
57
|
symbolic=self.symbolic,
|
|
54
58
|
)
|
|
@@ -68,7 +72,18 @@ class MessageMap(_t.Dict[int, Message]):
|
|
|
68
72
|
:return: Message if valid ref else an unknown message type.
|
|
69
73
|
"""
|
|
70
74
|
for value in self.values():
|
|
71
|
-
if ref
|
|
75
|
+
if ref == value.code:
|
|
76
|
+
_warn(
|
|
77
|
+
"Exxx errors are deprecated and might not be supported in "
|
|
78
|
+
"a future version, see "
|
|
79
|
+
"https://docsig.readthedocs.io/en/latest/deprecated/"
|
|
80
|
+
"messages.html",
|
|
81
|
+
category=DeprecationWarning,
|
|
82
|
+
stacklevel=6,
|
|
83
|
+
)
|
|
84
|
+
return value
|
|
85
|
+
|
|
86
|
+
if ref in (value.ref, value.symbolic):
|
|
72
87
|
return value
|
|
73
88
|
|
|
74
89
|
return Message(UNKNOWN, UNKNOWN, ref)
|
|
@@ -84,144 +99,142 @@ class MessageMap(_t.Dict[int, Message]):
|
|
|
84
99
|
@property
|
|
85
100
|
def all(self) -> Messages:
|
|
86
101
|
"""Get all messages that aren't a config error."""
|
|
87
|
-
return Messages(
|
|
88
|
-
v for k, v in self.items() if str(k).startswith(str(1))
|
|
89
|
-
)
|
|
102
|
+
return Messages(v for k, v in self.items() if len(str(k)) > 1)
|
|
90
103
|
|
|
91
104
|
|
|
92
105
|
# SIGxxx: Error
|
|
93
106
|
E = MessageMap(
|
|
94
107
|
{
|
|
95
108
|
#: SIG0xx Config
|
|
96
|
-
|
|
109
|
+
1: Message(
|
|
97
110
|
"SIG001",
|
|
98
111
|
"E201",
|
|
99
112
|
"unknown module comment directive '{directive}'",
|
|
100
113
|
"unknown-module-directive",
|
|
101
114
|
),
|
|
102
|
-
|
|
115
|
+
2: Message(
|
|
103
116
|
"SIG002",
|
|
104
117
|
"E202",
|
|
105
118
|
"unknown inline comment directive '{directive}'",
|
|
106
119
|
"unknown-inline-directive",
|
|
107
120
|
),
|
|
108
|
-
|
|
121
|
+
3: Message(
|
|
109
122
|
"SIG003",
|
|
110
123
|
"E203",
|
|
111
124
|
"unknown module comment option for {directive} '{option}'",
|
|
112
125
|
"unknown-module-directive-option",
|
|
113
126
|
),
|
|
114
|
-
|
|
127
|
+
4: Message(
|
|
115
128
|
"SIG004",
|
|
116
129
|
"E204",
|
|
117
130
|
"unknown inline comment option for {directive} '{option}'",
|
|
118
131
|
"unknown-inline-directive-option",
|
|
119
132
|
),
|
|
120
133
|
#: SIG1xx Missing
|
|
121
|
-
|
|
134
|
+
101: Message(
|
|
122
135
|
"SIG101",
|
|
123
136
|
"E113",
|
|
124
137
|
"function is missing a docstring",
|
|
125
138
|
"function-doc-missing",
|
|
126
139
|
),
|
|
127
|
-
|
|
140
|
+
102: Message(
|
|
128
141
|
"SIG102",
|
|
129
142
|
"E114",
|
|
130
143
|
"class is missing a docstring",
|
|
131
144
|
"class-doc-missing",
|
|
132
145
|
),
|
|
133
146
|
#: SIG2xx Signature
|
|
134
|
-
|
|
147
|
+
201: Message(
|
|
135
148
|
"SIG201",
|
|
136
149
|
"E106",
|
|
137
150
|
"duplicate parameters found",
|
|
138
151
|
"duplicate-params-found",
|
|
139
152
|
),
|
|
140
|
-
|
|
153
|
+
202: Message(
|
|
141
154
|
"SIG202",
|
|
142
155
|
"E102",
|
|
143
156
|
"includes parameters that do not exist",
|
|
144
157
|
"params-do-not-exist",
|
|
145
158
|
),
|
|
146
|
-
|
|
159
|
+
203: Message(
|
|
147
160
|
"SIG203",
|
|
148
161
|
"E103",
|
|
149
162
|
"parameters missing",
|
|
150
163
|
"params-missing",
|
|
151
164
|
),
|
|
152
165
|
#: SIG3xx Parameters
|
|
153
|
-
|
|
166
|
+
301: Message(
|
|
154
167
|
"SIG301",
|
|
155
168
|
"E117",
|
|
156
169
|
"description missing from parameter",
|
|
157
170
|
"description-missing",
|
|
158
171
|
),
|
|
159
|
-
|
|
172
|
+
302: Message(
|
|
160
173
|
"SIG302",
|
|
161
174
|
"E115",
|
|
162
175
|
"syntax error in description",
|
|
163
176
|
"syntax-error-in-description",
|
|
164
177
|
),
|
|
165
|
-
|
|
178
|
+
303: Message(
|
|
166
179
|
"SIG303",
|
|
167
180
|
"E107",
|
|
168
181
|
"parameter appears to be incorrectly documented",
|
|
169
182
|
"param-incorrectly-documented",
|
|
170
183
|
),
|
|
171
184
|
#: SIG4xx Description
|
|
172
|
-
|
|
185
|
+
401: Message(
|
|
173
186
|
"SIG401",
|
|
174
187
|
"E116",
|
|
175
188
|
"param not indented correctly",
|
|
176
189
|
"incorrect-indent",
|
|
177
190
|
),
|
|
178
|
-
|
|
191
|
+
402: Message(
|
|
179
192
|
"SIG402",
|
|
180
193
|
"E101",
|
|
181
194
|
"parameters out of order",
|
|
182
195
|
"params-out-of-order",
|
|
183
196
|
),
|
|
184
|
-
|
|
197
|
+
403: Message(
|
|
185
198
|
"SIG403",
|
|
186
199
|
"E112",
|
|
187
200
|
"spelling error found in documented parameter",
|
|
188
201
|
"spelling-error",
|
|
189
202
|
),
|
|
190
|
-
|
|
203
|
+
404: Message(
|
|
191
204
|
"SIG404",
|
|
192
205
|
"E110",
|
|
193
206
|
"documented parameter not equal to its respective argument",
|
|
194
207
|
"param-not-equal-to-arg",
|
|
195
208
|
),
|
|
196
209
|
#: SIG5xx Returns
|
|
197
|
-
|
|
210
|
+
501: Message(
|
|
198
211
|
"SIG501",
|
|
199
212
|
"E109",
|
|
200
213
|
"cannot determine whether a return statement should exist",
|
|
201
214
|
"confirm-return-needed",
|
|
202
215
|
"annotate type to indicate whether return documentation needed",
|
|
203
216
|
),
|
|
204
|
-
|
|
217
|
+
502: Message(
|
|
205
218
|
"SIG502",
|
|
206
219
|
"E104",
|
|
207
220
|
"return statement documented for None",
|
|
208
221
|
"return-documented-for-none",
|
|
209
222
|
),
|
|
210
|
-
|
|
223
|
+
503: Message(
|
|
211
224
|
"SIG503",
|
|
212
225
|
"E105",
|
|
213
226
|
"return missing from docstring",
|
|
214
227
|
"return-missing",
|
|
215
228
|
"it is possible a syntax error could be causing this",
|
|
216
229
|
),
|
|
217
|
-
|
|
230
|
+
504: Message(
|
|
218
231
|
"SIG504",
|
|
219
232
|
"E111",
|
|
220
233
|
"return statement documented for class",
|
|
221
234
|
"class-return-documented",
|
|
222
235
|
"a class does not return a value during instantiation",
|
|
223
236
|
),
|
|
224
|
-
|
|
237
|
+
505: Message(
|
|
225
238
|
"SIG505",
|
|
226
239
|
"E108",
|
|
227
240
|
"return statement documented for property",
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Flake8 implementation of docsig."""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
import contextlib
|
|
5
|
+
import io
|
|
6
|
+
import re
|
|
7
|
+
import sys
|
|
8
|
+
import typing as t
|
|
9
|
+
from argparse import Namespace
|
|
10
|
+
|
|
11
|
+
import docsig
|
|
12
|
+
|
|
13
|
+
Flake8Error = t.Tuple[int, int, str, t.Type]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Docsig:
|
|
17
|
+
"""Flake8 implementation of docsig class.
|
|
18
|
+
|
|
19
|
+
:param tree: Ast module, which will not be used by flake8 will
|
|
20
|
+
provide.
|
|
21
|
+
:param filename: Filename to pass to docsig.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
off_by_default = False
|
|
25
|
+
name = docsig.__name__
|
|
26
|
+
version = docsig.__version__
|
|
27
|
+
options_dict: t.Dict[str, bool] = {}
|
|
28
|
+
|
|
29
|
+
def __init__(self, tree: ast.Module, filename: str) -> None:
|
|
30
|
+
_tree = tree # noqa
|
|
31
|
+
self.filename = filename
|
|
32
|
+
|
|
33
|
+
# won't import flake8 type
|
|
34
|
+
# conflicts with this module name
|
|
35
|
+
# might require that flake8 actually be installed, which is not a
|
|
36
|
+
# requirement for this package
|
|
37
|
+
@classmethod
|
|
38
|
+
def add_options(cls, parser) -> None:
|
|
39
|
+
"""Add flake8 commandline and config options.sig_
|
|
40
|
+
|
|
41
|
+
:param parser: Flake8 option manager.
|
|
42
|
+
"""
|
|
43
|
+
parser.add_option(
|
|
44
|
+
"--sig-check-class",
|
|
45
|
+
action="store_true",
|
|
46
|
+
parse_from_config=True,
|
|
47
|
+
help="check class docstrings",
|
|
48
|
+
)
|
|
49
|
+
parser.add_option(
|
|
50
|
+
"--sig-check-class-constructor",
|
|
51
|
+
action="store_true",
|
|
52
|
+
parse_from_config=True,
|
|
53
|
+
help="check __init__ methods. Note: mutually incompatible with -c",
|
|
54
|
+
)
|
|
55
|
+
parser.add_option(
|
|
56
|
+
"--sig-check-dunders",
|
|
57
|
+
action="store_true",
|
|
58
|
+
parse_from_config=True,
|
|
59
|
+
help="check dunder methods",
|
|
60
|
+
)
|
|
61
|
+
parser.add_option(
|
|
62
|
+
"--sig-check-protected-class-methods",
|
|
63
|
+
action="store_true",
|
|
64
|
+
parse_from_config=True,
|
|
65
|
+
help="check public methods belonging to protected classes",
|
|
66
|
+
)
|
|
67
|
+
parser.add_option(
|
|
68
|
+
"--sig-check-nested",
|
|
69
|
+
action="store_true",
|
|
70
|
+
parse_from_config=True,
|
|
71
|
+
help="check nested functions and classes",
|
|
72
|
+
)
|
|
73
|
+
parser.add_option(
|
|
74
|
+
"--sig-check-overridden",
|
|
75
|
+
action="store_true",
|
|
76
|
+
parse_from_config=True,
|
|
77
|
+
help="check overridden methods",
|
|
78
|
+
)
|
|
79
|
+
parser.add_option(
|
|
80
|
+
"--sig-check-protected",
|
|
81
|
+
action="store_true",
|
|
82
|
+
parse_from_config=True,
|
|
83
|
+
help="check protected functions and classes",
|
|
84
|
+
)
|
|
85
|
+
parser.add_option(
|
|
86
|
+
"--sig-check-property-returns",
|
|
87
|
+
action="store_true",
|
|
88
|
+
parse_from_config=True,
|
|
89
|
+
help="check property return values",
|
|
90
|
+
)
|
|
91
|
+
parser.add_option(
|
|
92
|
+
"--sig-ignore-no-params",
|
|
93
|
+
action="store_true",
|
|
94
|
+
parse_from_config=True,
|
|
95
|
+
help="ignore docstrings where parameters are not documented",
|
|
96
|
+
)
|
|
97
|
+
parser.add_option(
|
|
98
|
+
"--sig-ignore-args",
|
|
99
|
+
action="store_true",
|
|
100
|
+
parse_from_config=True,
|
|
101
|
+
help="ignore args prefixed with an asterisk",
|
|
102
|
+
)
|
|
103
|
+
parser.add_option(
|
|
104
|
+
"--sig-ignore-kwargs",
|
|
105
|
+
action="store_true",
|
|
106
|
+
parse_from_config=True,
|
|
107
|
+
help="ignore kwargs prefixed with two asterisks",
|
|
108
|
+
)
|
|
109
|
+
parser.add_option(
|
|
110
|
+
"--sig-ignore-typechecker",
|
|
111
|
+
action="store_true",
|
|
112
|
+
parse_from_config=True,
|
|
113
|
+
help="ignore checking return values",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def parse_options(cls, options: Namespace) -> None:
|
|
118
|
+
"""Parse flake8 options into am instance accessible dict.
|
|
119
|
+
|
|
120
|
+
:param options: Argparse namespace.
|
|
121
|
+
"""
|
|
122
|
+
cls.options_dict = {
|
|
123
|
+
"check_class": options.sig_check_class,
|
|
124
|
+
"check_class_constructor": options.sig_check_class_constructor,
|
|
125
|
+
"check_dunders": options.sig_check_dunders,
|
|
126
|
+
"check_protected_class_methods": (
|
|
127
|
+
options.sig_check_protected_class_methods
|
|
128
|
+
),
|
|
129
|
+
"check_nested": options.sig_check_nested,
|
|
130
|
+
"check_overridden": options.sig_check_overridden,
|
|
131
|
+
"check_protected": options.sig_check_protected,
|
|
132
|
+
"check_property_returns": options.sig_check_property_returns,
|
|
133
|
+
"ignore_no_params": options.sig_ignore_no_params,
|
|
134
|
+
"ignore_args": options.sig_ignore_args,
|
|
135
|
+
"ignore_kwargs": options.sig_ignore_kwargs,
|
|
136
|
+
"ignore_typechecker": options.sig_ignore_typechecker,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
def run(self) -> t.Generator[Flake8Error, None, None]:
|
|
140
|
+
"""Run docsig and possibly yield a flake8 error.
|
|
141
|
+
|
|
142
|
+
:return: Flake8 error, if there is one.
|
|
143
|
+
"""
|
|
144
|
+
buffer = io.StringIO()
|
|
145
|
+
with contextlib.redirect_stdout(buffer):
|
|
146
|
+
sys.argv = [
|
|
147
|
+
__package__,
|
|
148
|
+
self.filename,
|
|
149
|
+
*[
|
|
150
|
+
f"--{k.replace('_', '-')}"
|
|
151
|
+
for k, v in self.options_dict.items()
|
|
152
|
+
if v
|
|
153
|
+
],
|
|
154
|
+
]
|
|
155
|
+
docsig.main()
|
|
156
|
+
|
|
157
|
+
results = re.split(r"^(?!\s)", buffer.getvalue(), flags=re.MULTILINE)
|
|
158
|
+
for result in results:
|
|
159
|
+
if not result:
|
|
160
|
+
continue
|
|
161
|
+
|
|
162
|
+
header, remainder = result.splitlines()[:2]
|
|
163
|
+
lineno, func_name = header.split(":", 1)[1].split(" in ", 1)
|
|
164
|
+
line = f"{remainder.lstrip().replace(':', '')} '{func_name}'"
|
|
165
|
+
yield int(lineno), 0, line, self.__class__
|
|
@@ -7,12 +7,56 @@ requires = [
|
|
|
7
7
|
[tool.black]
|
|
8
8
|
line-length = 79
|
|
9
9
|
|
|
10
|
+
[tool.bumpversion]
|
|
11
|
+
allow_dirty = true
|
|
12
|
+
commit = true
|
|
13
|
+
commit_args = "-sS"
|
|
14
|
+
current_version = "0.57.0"
|
|
15
|
+
message = "bump: version {current_version} → {new_version}"
|
|
16
|
+
sign_tags = true
|
|
17
|
+
tag = true
|
|
18
|
+
|
|
19
|
+
[[tool.bumpversion.files]]
|
|
20
|
+
filename = "docs/conf.py"
|
|
21
|
+
|
|
22
|
+
[[tool.bumpversion.files]]
|
|
23
|
+
filename = "docsig/_version.py"
|
|
24
|
+
|
|
25
|
+
[[tool.bumpversion.files]]
|
|
26
|
+
filename = "pyproject.toml"
|
|
27
|
+
replace = 'version = "{new_version}"'
|
|
28
|
+
search = 'version = "{current_version}"'
|
|
29
|
+
|
|
30
|
+
[[tool.bumpversion.files]]
|
|
31
|
+
filename = "package.json"
|
|
32
|
+
replace = '"version": "{new_version}"'
|
|
33
|
+
search = '"version": "{current_version}"'
|
|
34
|
+
|
|
35
|
+
[[tool.bumpversion.files]]
|
|
36
|
+
filename = "README.rst"
|
|
37
|
+
replace = "rev: v{new_version}"
|
|
38
|
+
search = "rev: v{current_version}"
|
|
39
|
+
|
|
40
|
+
[[tool.bumpversion.files]]
|
|
41
|
+
filename = "README.rst"
|
|
42
|
+
replace = "docsig: {new_version}"
|
|
43
|
+
search = "docsig: {current_version}"
|
|
44
|
+
|
|
45
|
+
[[tool.bumpversion.files]]
|
|
46
|
+
filename = "SECURITY.md"
|
|
47
|
+
|
|
48
|
+
[[tool.bumpversion.files]]
|
|
49
|
+
filename = "Makefile"
|
|
50
|
+
replace = "VERSION := {new_version}"
|
|
51
|
+
search = "VERSION := {current_version}"
|
|
52
|
+
|
|
10
53
|
[tool.codespell]
|
|
11
54
|
ignore-words-list = "astroid"
|
|
12
55
|
|
|
13
56
|
[tool.coverage.report]
|
|
14
57
|
exclude_lines = [
|
|
15
|
-
"@_t.overload"
|
|
58
|
+
"@_t.overload",
|
|
59
|
+
"if __name__ == .__main__.:"
|
|
16
60
|
]
|
|
17
61
|
fail_under = 100
|
|
18
62
|
|
|
@@ -24,7 +68,14 @@ omit = [
|
|
|
24
68
|
]
|
|
25
69
|
|
|
26
70
|
[tool.deptry.per_rule_ignores]
|
|
27
|
-
DEP004 = [
|
|
71
|
+
DEP004 = [
|
|
72
|
+
"flake8",
|
|
73
|
+
"git",
|
|
74
|
+
"pytest",
|
|
75
|
+
"tomli",
|
|
76
|
+
"tomli_w",
|
|
77
|
+
"yaml"
|
|
78
|
+
]
|
|
28
79
|
|
|
29
80
|
[tool.docformatter]
|
|
30
81
|
in-place = true
|
|
@@ -76,7 +127,7 @@ maintainers = [
|
|
|
76
127
|
name = "docsig"
|
|
77
128
|
readme = "README.rst"
|
|
78
129
|
repository = "https://github.com/jshwi/docsig"
|
|
79
|
-
version = "0.
|
|
130
|
+
version = "0.57.0"
|
|
80
131
|
|
|
81
132
|
[tool.poetry.dependencies]
|
|
82
133
|
Sphinx = "^7.0.0"
|
|
@@ -84,18 +135,22 @@ arcon = ">=0.4.0"
|
|
|
84
135
|
astroid = "^3.0.1"
|
|
85
136
|
click = "^8.1.7"
|
|
86
137
|
pathspec = "^0.12.1"
|
|
87
|
-
python = "^3.8"
|
|
138
|
+
python = "^3.8.1"
|
|
88
139
|
|
|
89
140
|
[tool.poetry.group.dev.dependencies]
|
|
90
141
|
black = "^24.4.2"
|
|
91
|
-
|
|
142
|
+
bump-my-version = "^0.24.1"
|
|
92
143
|
deptry = "^0.16.1"
|
|
93
144
|
docformatter = "^1.7.5"
|
|
94
145
|
flynt = "^1.0.1"
|
|
146
|
+
gitpython = "^3.1.43"
|
|
95
147
|
isort = "^5.13.2"
|
|
96
148
|
mypy = "^1.10.0"
|
|
97
149
|
pre-commit = "^3.3.3"
|
|
98
150
|
pylint = "^3.1.0"
|
|
151
|
+
tomli = "^2.0.1"
|
|
152
|
+
tomli-w = "^1.0.0"
|
|
153
|
+
towncrier = "^23.11.0"
|
|
99
154
|
tox = "^4.15.0"
|
|
100
155
|
vulture = "^2.11"
|
|
101
156
|
|
|
@@ -108,6 +163,9 @@ sphinx-copybutton = "^0.5.2"
|
|
|
108
163
|
sphinx-markdown-builder = ">=0.5.5,<0.7.0"
|
|
109
164
|
templatest = "^0.10.1"
|
|
110
165
|
|
|
166
|
+
[tool.poetry.group.flake8.dependencies]
|
|
167
|
+
flake8 = "^7.1.0"
|
|
168
|
+
|
|
111
169
|
[tool.poetry.group.tests.dependencies]
|
|
112
170
|
pytest = "^8.2.0"
|
|
113
171
|
pytest-benchmark = "^4.0.0"
|
|
@@ -117,6 +175,9 @@ pytest-sugar = "^1.0.0"
|
|
|
117
175
|
pytest-xdist = "^3.6.1"
|
|
118
176
|
templatest = "^0.10.1"
|
|
119
177
|
|
|
178
|
+
[tool.poetry.plugins."flake8.extension"]
|
|
179
|
+
SIG = "docsig.plugin:Docsig"
|
|
180
|
+
|
|
120
181
|
[tool.poetry.scripts]
|
|
121
182
|
docsig = "docsig.__main__:main"
|
|
122
183
|
|
|
@@ -149,3 +210,32 @@ norecursedirs = [
|
|
|
149
210
|
".pytest_cache",
|
|
150
211
|
"docs"
|
|
151
212
|
]
|
|
213
|
+
|
|
214
|
+
[tool.towncrier]
|
|
215
|
+
directory = "changelog"
|
|
216
|
+
filename = "CHANGELOG.md"
|
|
217
|
+
issue_format = "[#{issue}](https://github.com/jshwi/docsig/issues/{issue})"
|
|
218
|
+
package = "docsig"
|
|
219
|
+
start_string = "<!-- release notes start -->\n"
|
|
220
|
+
template = "changelog/_template.md"
|
|
221
|
+
|
|
222
|
+
[tool.towncrier.fragment.add]
|
|
223
|
+
name = "Added"
|
|
224
|
+
|
|
225
|
+
[tool.towncrier.fragment.change]
|
|
226
|
+
name = "Changed"
|
|
227
|
+
|
|
228
|
+
[tool.towncrier.fragment.deprecate]
|
|
229
|
+
name = "Deprecated"
|
|
230
|
+
|
|
231
|
+
[tool.towncrier.fragment.fix]
|
|
232
|
+
name = "Fixed"
|
|
233
|
+
|
|
234
|
+
[tool.towncrier.fragment.hack]
|
|
235
|
+
name = "Hacked"
|
|
236
|
+
|
|
237
|
+
[tool.towncrier.fragment.remove]
|
|
238
|
+
name = "Removed"
|
|
239
|
+
|
|
240
|
+
[tool.towncrier.fragment.security]
|
|
241
|
+
name = "Security"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|