docsig 0.58.0__tar.gz → 0.59.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: docsig
3
- Version: 0.58.0
3
+ Version: 0.59.1
4
4
  Summary: Check signature params for proper documentation
5
5
  Home-page: https://pypi.org/project/docsig/
6
6
  License: MIT
@@ -169,7 +169,7 @@ ensure your installation has registered `docsig`
169
169
  .. code-block:: console
170
170
 
171
171
  $ flake8 --version
172
- 7.1.0 (docsig: 0.58.0, mccabe: 0.7.0, pycodestyle: 2.12.0, pyflakes: 3.2.0) CPython 3.8.13 on Darwin
172
+ 7.1.0 (docsig: 0.59.1, mccabe: 0.7.0, pycodestyle: 2.12.0, pyflakes: 3.2.0) CPython 3.8.13 on Darwin
173
173
 
174
174
  And now use `flake8` to lint your files
175
175
 
@@ -258,7 +258,7 @@ Standalone
258
258
 
259
259
  repos:
260
260
  - repo: https://github.com/jshwi/docsig
261
- rev: v0.58.0
261
+ rev: v0.59.1
262
262
  hooks:
263
263
  - id: docsig
264
264
  args:
@@ -277,7 +277,7 @@ or integrated with ``flake8``
277
277
  hooks:
278
278
  - id: flake8
279
279
  additional_dependencies:
280
- - docsig==0.58.0
280
+ - docsig==0.59.1
281
281
  args:
282
282
  - "--sig-check-class"
283
283
  - "--sig-check-dunders"
@@ -143,7 +143,7 @@ ensure your installation has registered `docsig`
143
143
  .. code-block:: console
144
144
 
145
145
  $ flake8 --version
146
- 7.1.0 (docsig: 0.58.0, mccabe: 0.7.0, pycodestyle: 2.12.0, pyflakes: 3.2.0) CPython 3.8.13 on Darwin
146
+ 7.1.0 (docsig: 0.59.1, mccabe: 0.7.0, pycodestyle: 2.12.0, pyflakes: 3.2.0) CPython 3.8.13 on Darwin
147
147
 
148
148
  And now use `flake8` to lint your files
149
149
 
@@ -232,7 +232,7 @@ Standalone
232
232
 
233
233
  repos:
234
234
  - repo: https://github.com/jshwi/docsig
235
- rev: v0.58.0
235
+ rev: v0.59.1
236
236
  hooks:
237
237
  - id: docsig
238
238
  args:
@@ -251,7 +251,7 @@ or integrated with ``flake8``
251
251
  hooks:
252
252
  - id: flake8
253
253
  additional_dependencies:
254
- - docsig==0.58.0
254
+ - docsig==0.59.1
255
255
  args:
256
256
  - "--sig-check-class"
257
257
  - "--sig-check-dunders"
@@ -8,13 +8,19 @@ from __future__ import annotations as _
8
8
  import sys as _sys
9
9
  from pathlib import Path as _Path
10
10
 
11
+ import astroid as _ast
12
+
11
13
  from . import _decorators
14
+ from ._directives import Directives as _Directives
15
+ from ._files import FILE_INFO as _FILE_INFO
16
+ from ._files import Paths as _Paths
12
17
  from ._module import Function as _Function
13
- from ._module import Modules as _Modules
14
18
  from ._module import Parent as _Parent
15
19
  from ._report import Failure as _Failure
16
20
  from ._report import Failures as _Failures
21
+ from ._utils import pretty_print_error as _pretty_print_error
17
22
  from ._utils import print_checks as _print_checks
23
+ from ._utils import vprint as _vprint
18
24
  from .messages import TEMPLATE as _TEMPLATE
19
25
  from .messages import Messages as _Messages
20
26
 
@@ -112,6 +118,56 @@ def _run_check( # pylint: disable=too-many-arguments,too-many-locals
112
118
  )
113
119
 
114
120
 
121
+ def _parse_ast( # pylint: disable=too-many-arguments
122
+ messages: _Messages,
123
+ ignore_args: bool,
124
+ ignore_kwargs: bool,
125
+ check_class_constructor,
126
+ verbose: bool,
127
+ no_ansi: bool,
128
+ root: _Path | None = None,
129
+ string: str | None = None,
130
+ ) -> tuple[_Parent | None, int]:
131
+ parent = None
132
+ retcode = 0
133
+ try:
134
+ if root is not None:
135
+ string = root.read_text(encoding="utf-8")
136
+
137
+ # empty string won't happen but keeps the
138
+ # typechecker happy
139
+ string = string or ""
140
+ parent = _Parent(
141
+ _ast.parse(string),
142
+ _Directives(string, messages),
143
+ root,
144
+ ignore_args,
145
+ ignore_kwargs,
146
+ check_class_constructor,
147
+ )
148
+ _vprint(
149
+ _FILE_INFO.format(
150
+ path=root or "stdin", msg="Parsing Python code successful"
151
+ ),
152
+ verbose,
153
+ )
154
+ except (_ast.AstroidSyntaxError, UnicodeDecodeError) as err:
155
+ msg = str(err).replace("\n", " ")
156
+ if root is not None and root.name.endswith(".py"):
157
+ # pass by silently for files that do not end with .py, may
158
+ # result in a 123 syntax error exit status in the future
159
+ print(root, file=_sys.stderr)
160
+ _pretty_print_error(type(err), msg, no_ansi=no_ansi)
161
+ retcode = 1
162
+
163
+ _vprint(
164
+ _FILE_INFO.format(path=root or "stdin", msg=msg),
165
+ verbose,
166
+ )
167
+
168
+ return parent, retcode
169
+
170
+
115
171
  def _get_failures( # pylint: disable=too-many-locals,too-many-arguments
116
172
  module: _Parent,
117
173
  check_class: bool,
@@ -158,7 +214,8 @@ def _report(
158
214
  failures: _Failures, path: str | None = None, no_ansi: bool = False
159
215
  ) -> None:
160
216
  for failure in failures:
161
- header = f"{path}{failure.lineno} in {failure.name}"
217
+ module = f"{path}:" if path is not None else ""
218
+ header = f"{module}{failure.lineno} in {failure.name}"
162
219
  if not no_ansi and _sys.stdout.isatty():
163
220
  header = f"\033[35m{header}\033[0m"
164
221
 
@@ -176,6 +233,79 @@ def _report(
176
233
  print(f" hint: {item.hint}")
177
234
 
178
235
 
236
+ def runner( # pylint: disable=too-many-locals,too-many-arguments
237
+ file: str | _Path,
238
+ disable: _Messages | None = None,
239
+ check_class: bool = False,
240
+ check_class_constructor: bool = False,
241
+ check_dunders: bool = False,
242
+ check_nested: bool = False,
243
+ check_overridden: bool = False,
244
+ check_protected: bool = False,
245
+ check_property_returns: bool = False,
246
+ ignore_no_params: bool = False,
247
+ ignore_args: bool = False,
248
+ ignore_kwargs: bool = False,
249
+ ignore_typechecker: bool = False,
250
+ check_protected_class_methods: bool = False,
251
+ no_ansi: bool = False,
252
+ verbose: bool = False,
253
+ target: _Messages | None = None,
254
+ ) -> tuple[_Failures, int]:
255
+ """Per path runner.
256
+
257
+ :param file: Path to check.
258
+ :param disable: Messages to disable.
259
+ :param check_class: Check class docstrings.
260
+ :param check_class_constructor: Check ``__init__`` methods. Note that this
261
+ is mutually incompatible with check_class.
262
+ :param check_dunders: Check dunder methods
263
+ :param check_nested: Check nested functions and classes.
264
+ :param check_overridden: Check overridden methods
265
+ :param check_protected: Check protected functions and classes.
266
+ :param check_property_returns: Run return checks on properties.
267
+ :param ignore_no_params: Ignore docstrings where parameters are not
268
+ documented
269
+ :param ignore_args: Ignore args prefixed with an asterisk.
270
+ :param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
271
+ :param ignore_typechecker: Ignore checking return values.
272
+ :param check_protected_class_methods: Check public methods belonging
273
+ to protected classes.
274
+ :param no_ansi: Disable ANSI output.
275
+ :param verbose: increase output verbosity.
276
+ :param target: List of errors to target.
277
+ :return: Exit status for whether test failed or not.
278
+ """
279
+ failures = _Failures()
280
+ module, retcode = _parse_ast(
281
+ disable or _Messages(),
282
+ ignore_args,
283
+ ignore_kwargs,
284
+ check_class_constructor,
285
+ verbose,
286
+ no_ansi,
287
+ root=_Path(file),
288
+ )
289
+ if module:
290
+ failures = _get_failures(
291
+ module,
292
+ check_class,
293
+ check_class_constructor,
294
+ check_dunders,
295
+ check_nested,
296
+ check_overridden,
297
+ check_protected,
298
+ check_property_returns,
299
+ ignore_no_params,
300
+ ignore_typechecker,
301
+ check_protected_class_methods,
302
+ no_ansi,
303
+ target or _Messages(),
304
+ )
305
+
306
+ return failures, retcode
307
+
308
+
179
309
  @_decorators.parse_msgs
180
310
  @_decorators.handle_deprecations
181
311
  @_decorators.validate_args
@@ -239,7 +369,6 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
239
369
  checks.
240
370
  :return: Exit status for whether test failed or not.
241
371
  """
242
- retcode = 0
243
372
  if list_checks:
244
373
  return int(bool(_print_checks())) # type: ignore
245
374
 
@@ -247,19 +376,51 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
247
376
  if exclude is not None:
248
377
  excludes.append(exclude)
249
378
 
250
- modules = _Modules(
251
- *tuple(_Path(i) for i in path),
252
- messages=disable or _Messages(),
379
+ if string is None:
380
+ retcode = 0
381
+ paths = _Paths(
382
+ *tuple(_Path(i) for i in path),
383
+ excludes=excludes,
384
+ include_ignored=include_ignored,
385
+ verbose=verbose,
386
+ )
387
+ for file in paths:
388
+ failures, parse_retcode = runner(
389
+ file,
390
+ disable,
391
+ check_class,
392
+ check_class_constructor,
393
+ check_dunders,
394
+ check_nested,
395
+ check_overridden,
396
+ check_protected,
397
+ check_property_returns,
398
+ ignore_no_params,
399
+ ignore_args,
400
+ ignore_kwargs,
401
+ ignore_typechecker,
402
+ check_protected_class_methods,
403
+ no_ansi,
404
+ verbose,
405
+ target,
406
+ )
407
+ retcode = retcode or parse_retcode
408
+ if failures:
409
+ _report(failures, str(file), no_ansi)
410
+ retcode = 1
411
+
412
+ return retcode
413
+
414
+ module, retcode = _parse_ast(
415
+ disable or _Messages(),
416
+ ignore_args,
417
+ ignore_kwargs,
418
+ check_class_constructor,
419
+ verbose,
420
+ no_ansi,
253
421
  string=string,
254
- excludes=excludes,
255
- include_ignored=include_ignored,
256
- ignore_args=ignore_args,
257
- ignore_kwargs=ignore_kwargs,
258
- check_class_constructor=check_class_constructor,
259
- no_ansi=no_ansi,
260
- verbose=verbose,
261
422
  )
262
- for module in modules:
423
+ if module is not None:
263
424
  failures = _get_failures(
264
425
  module,
265
426
  check_class,
@@ -276,7 +437,7 @@ def docsig( # pylint: disable=too-many-locals,too-many-arguments
276
437
  target or _Messages(),
277
438
  )
278
439
  if failures:
279
- _report(failures, module.path, no_ansi=no_ansi)
280
- retcode = 1
440
+ _report(failures, no_ansi=no_ansi)
441
+ return 1
281
442
 
282
- return max(retcode, modules.retcode)
443
+ return 0
@@ -0,0 +1,118 @@
1
+ """
2
+ docsig._files
3
+ =============
4
+ """
5
+
6
+ from __future__ import annotations as _
7
+
8
+ import os as _os
9
+ import re as _re
10
+ import typing as _t
11
+ from pathlib import Path as _Path
12
+
13
+ from pathspec import PathSpec as _PathSpec
14
+ from pathspec.patterns import GitWildMatchPattern as _GitWildMatchPattern
15
+
16
+ from ._utils import vprint as _vprint
17
+
18
+ FILE_INFO = "{path}: {msg}"
19
+
20
+
21
+ class _Gitignore(_PathSpec):
22
+ def _get_repo_relative_to(self, path: _Path) -> _Path | None:
23
+ if (path / ".git" / "HEAD").is_file():
24
+ return path
25
+
26
+ if str(path) == _os.path.abspath(_os.sep):
27
+ return None
28
+
29
+ return self._get_repo_relative_to(path.parent)
30
+
31
+ def __init__(self) -> None:
32
+ patterns = []
33
+ repo = self._get_repo_relative_to(_Path.cwd())
34
+ # only consider gitignore patterns valid if inside a git repo
35
+ # there might be stray gitignore files lying about
36
+ if repo is not None:
37
+ # add patterns from all gitignore files
38
+ # adjust patterns to account for their relative paths
39
+ for file in repo.rglob(".gitignore"):
40
+ for pattern in file.read_text(encoding="utf-8").splitlines():
41
+ if pattern.startswith("#"):
42
+ continue
43
+
44
+ # if pattern starts with "/" then os.path.join will
45
+ # consider it in the filesystem root, and it will
46
+ # only ever return /pattern
47
+ if pattern.startswith("/"):
48
+ pattern = pattern[1:]
49
+
50
+ # use os.path.dirname, so it joins without a leading
51
+ # "./", like it does with pathlib parent
52
+ # use os.path.join so trailing slash is preserved
53
+ # replace sep with "/" as, even on windows,
54
+ # gitignore patterns only ever use "/"
55
+ patterns.append(
56
+ _os.path.join(
57
+ _os.path.dirname(file.relative_to(repo)),
58
+ pattern.strip(),
59
+ ).replace(_os.sep, "/")
60
+ )
61
+
62
+ super().__init__(map(_GitWildMatchPattern, patterns))
63
+
64
+
65
+ class Paths(_t.List[_Path]): # pylint: disable=too-many-instance-attributes
66
+ """Collect a list of valid paths.
67
+
68
+ :param paths: Path(s) to parse ``Module``(s) from.
69
+ :param excludes: List pf regular expression of files and dirs to
70
+ exclude from checks.
71
+ :param include_ignored: Check files even if they match a gitignore
72
+ pattern.
73
+ :param verbose: increase output verbosity.
74
+ """
75
+
76
+ def __init__( # pylint: disable=too-many-arguments
77
+ self,
78
+ *paths: _Path,
79
+ excludes: list[str],
80
+ include_ignored: bool = False,
81
+ verbose: bool = False,
82
+ ) -> None:
83
+ super().__init__()
84
+ self._excludes = excludes
85
+ self._include_ignored = include_ignored
86
+ self._verbose = verbose
87
+ self._gitignore = _Gitignore()
88
+ for path in paths:
89
+ self._populate(path)
90
+
91
+ self.sort()
92
+
93
+ def _populate(self, root: _Path) -> None:
94
+ if not root.exists():
95
+ raise FileNotFoundError(root)
96
+
97
+ if str(root) != "." and any(
98
+ _re.match(i, root.name) for i in self._excludes
99
+ ):
100
+ _vprint(
101
+ FILE_INFO.format(path=root, msg="in exclude list, skipping"),
102
+ self._verbose,
103
+ )
104
+ return
105
+
106
+ if not self._include_ignored and self._gitignore.match_file(root):
107
+ _vprint(
108
+ FILE_INFO.format(path=root, msg="in gitignore, skipping"),
109
+ self._verbose,
110
+ )
111
+ return
112
+
113
+ if root.is_file():
114
+ self.append(root)
115
+
116
+ if root.is_dir():
117
+ for path in root.iterdir():
118
+ self._populate(path)
@@ -5,71 +5,19 @@ docsig._module
5
5
 
6
6
  from __future__ import annotations as _
7
7
 
8
- import os as _os
9
8
  import re as _re
10
- import sys as _sys
11
9
  import typing as _t
12
10
  from pathlib import Path as _Path
13
11
 
14
12
  import astroid as _ast
15
- from pathspec import PathSpec as _PathSpec
16
- from pathspec.patterns import GitWildMatchPattern as _GitWildMatchPattern
17
13
 
18
14
  from ._directives import Comment as _Comment
19
15
  from ._directives import Directives as _Directives
20
16
  from ._stub import Docstring as _Docstring
21
17
  from ._stub import RetType as _RetType
22
18
  from ._stub import Signature as _Signature
23
- from ._utils import pretty_print_error as _pretty_print_error
24
- from ._utils import vprint as _vprint
25
19
  from .messages import Messages as _Messages
26
20
 
27
- _FILE_INFO = "{path}: {msg}"
28
-
29
-
30
- class _Gitignore(_PathSpec):
31
- def _get_repo_relative_to(self, path: _Path) -> _Path | None:
32
- if (path / ".git" / "HEAD").is_file():
33
- return path
34
-
35
- if str(path) == _os.path.abspath(_os.sep):
36
- return None
37
-
38
- return self._get_repo_relative_to(path.parent)
39
-
40
- def __init__(self) -> None:
41
- patterns = []
42
- repo = self._get_repo_relative_to(_Path.cwd())
43
- # only consider gitignore patterns valid if inside a git repo
44
- # there might be stray gitignore files lying about
45
- if repo is not None:
46
- # add patterns from all gitignore files
47
- # adjust patterns to account for their relative paths
48
- for file in repo.rglob(".gitignore"):
49
- for pattern in file.read_text(encoding="utf-8").splitlines():
50
- if pattern.startswith("#"):
51
- continue
52
-
53
- # if pattern starts with "/" then os.path.join will
54
- # consider it in the filesystem root, and it will
55
- # only ever return /pattern
56
- if pattern.startswith("/"):
57
- pattern = pattern[1:]
58
-
59
- # use os.path.dirname, so it joins without a leading
60
- # "./", like it does with pathlib parent
61
- # use os.path.join so trailing slash is preserved
62
- # replace sep with "/" as, even on windows,
63
- # gitignore patterns only ever use "/"
64
- patterns.append(
65
- _os.path.join(
66
- _os.path.dirname(file.relative_to(repo)),
67
- pattern.strip(),
68
- ).replace(_os.sep, "/")
69
- )
70
-
71
- super().__init__(map(_GitWildMatchPattern, patterns))
72
-
73
21
 
74
22
  class Parent(_t.List["Parent"]):
75
23
  """Represents an object that contains functions or methods.
@@ -98,7 +46,6 @@ class Parent(_t.List["Parent"]):
98
46
  ) -> None:
99
47
  super().__init__()
100
48
  self._name = node.name
101
- self._path = f"{path}:" if path is not None else ""
102
49
  self._overloads: dict[str, Function] = {}
103
50
  self._imports = imports or {}
104
51
  self._parse_ast(
@@ -185,11 +132,6 @@ class Parent(_t.List["Parent"]):
185
132
  check_class_constructor,
186
133
  )
187
134
 
188
- @property
189
- def path(self) -> str:
190
- """Representation of path to parent."""
191
- return self._path
192
-
193
135
  @property
194
136
  def isprotected(self) -> bool:
195
137
  """Boolean value for whether class is protected."""
@@ -366,150 +308,3 @@ class Function(Parent):
366
308
  :param rettype: Return type of overloaded signature.
367
309
  """
368
310
  self._signature.overload(rettype)
369
-
370
-
371
- class Modules(_t.List[Parent]): # pylint: disable=too-many-instance-attributes
372
- """Sequence of ``Module`` objects parsed from Python modules or str.
373
-
374
- Recursively collect Python files from within all dirs that exist
375
- under paths provided.
376
-
377
- If string is provided, ignore paths.
378
-
379
- :param paths: Path(s) to parse ``Module``(s) from.
380
- :param messages: List of checks to disable.
381
- :param excludes: List pf regular expression of files and dirs to
382
- exclude from checks.
383
- :param string: String to parse if provided.
384
- :param include_ignored: Check files even if they match a gitignore
385
- pattern.
386
- :param ignore_args: Ignore args prefixed with an asterisk.
387
- :param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
388
- :param check_class_constructor: Check the class constructor's
389
- docstring. Otherwise, expect the constructor's documentation to
390
- be on the class level docstring.
391
- :param no_ansi: Disable ANSI output.
392
- :param verbose: increase output verbosity.
393
- """
394
-
395
- # handle errors here before appending a module
396
- def _add_module( # pylint: disable=too-many-arguments
397
- self,
398
- messages: _Messages,
399
- string: str | None = None,
400
- root: _Path | None = None,
401
- ignore_args: bool = False,
402
- ignore_kwargs: bool = False,
403
- check_class_constructor: bool = False,
404
- ) -> None:
405
- try:
406
- if root is not None:
407
- string = root.read_text(encoding="utf-8")
408
-
409
- # empty string won't happen but keeps the
410
- # typechecker happy
411
- string = string or ""
412
- self.append(
413
- Parent(
414
- _ast.parse(string),
415
- _Directives(string, messages),
416
- root,
417
- ignore_args,
418
- ignore_kwargs,
419
- check_class_constructor,
420
- )
421
- )
422
- _vprint(
423
- _FILE_INFO.format(
424
- path=root or "stdin", msg="Parsing Python code successful"
425
- ),
426
- self._verbose,
427
- )
428
- except (_ast.AstroidSyntaxError, UnicodeDecodeError) as err:
429
- msg = str(err).replace("\n", " ")
430
- if root is not None and root.name.endswith(".py"):
431
- # pass by silently for files that do not end with .py,
432
- # may result in a 123 syntax error exit status in the
433
- # future
434
- print(root, file=_sys.stderr)
435
- _pretty_print_error(type(err), msg, no_ansi=self._no_ansi)
436
- self._retcode = 1
437
-
438
- _vprint(
439
- _FILE_INFO.format(path=root or "stdin", msg=msg),
440
- self._verbose,
441
- )
442
-
443
- def __init__( # pylint: disable=too-many-arguments
444
- self,
445
- *paths: _Path,
446
- messages: _Messages,
447
- excludes: list[str],
448
- string: str | None = None,
449
- include_ignored: bool = False,
450
- ignore_args: bool = False,
451
- ignore_kwargs: bool = False,
452
- check_class_constructor: bool = False,
453
- no_ansi: bool = False,
454
- verbose: bool = False,
455
- ) -> None:
456
- super().__init__()
457
- self._messages = messages
458
- self._excludes = excludes
459
- self._include_ignored = include_ignored
460
- self._ignore_args = ignore_args
461
- self._ignore_kwargs = ignore_kwargs
462
- self._check_class_constructor = check_class_constructor
463
- self._no_ansi = no_ansi
464
- self._verbose = verbose
465
- self._retcode = 0
466
- self._gitignore = _Gitignore()
467
- if string is not None:
468
- self._add_module(
469
- messages,
470
- string=string,
471
- ignore_args=ignore_args,
472
- ignore_kwargs=ignore_kwargs,
473
- check_class_constructor=check_class_constructor,
474
- )
475
- else:
476
- for path in paths:
477
- self._populate(path)
478
-
479
- def _populate(self, root: _Path) -> None:
480
- if not root.exists():
481
- raise FileNotFoundError(root)
482
-
483
- if str(root) != "." and any(
484
- _re.match(i, root.name) for i in self._excludes
485
- ):
486
- _vprint(
487
- _FILE_INFO.format(path=root, msg="in exclude list, skipping"),
488
- self._verbose,
489
- )
490
- return
491
-
492
- if not self._include_ignored and self._gitignore.match_file(root):
493
- _vprint(
494
- _FILE_INFO.format(path=root, msg="in gitignore, skipping"),
495
- self._verbose,
496
- )
497
- return
498
-
499
- if root.is_file():
500
- self._add_module(
501
- self._messages,
502
- root=root,
503
- ignore_args=self._ignore_args,
504
- ignore_kwargs=self._ignore_kwargs,
505
- check_class_constructor=self._check_class_constructor,
506
- )
507
-
508
- if root.is_dir():
509
- for path in root.iterdir():
510
- self._populate(path)
511
-
512
- @property
513
- def retcode(self) -> int:
514
- """Return code to propagate to main."""
515
- return self._retcode
@@ -8,4 +8,4 @@ Allows for access to the version internally without cyclic imports
8
8
  caused by accessing it through __init__.
9
9
  """
10
10
 
11
- __version__ = "0.58.0"
11
+ __version__ = "0.59.1"
@@ -1,14 +1,14 @@
1
1
  """Flake8 implementation of docsig."""
2
2
 
3
3
  import ast
4
- import contextlib
5
- import io
6
- import re
7
4
  import sys
8
5
  import typing as t
9
6
  from argparse import Namespace
10
7
 
11
- import docsig
8
+ from ._config import Parser
9
+ from ._core import runner
10
+ from ._version import __version__
11
+ from .messages import FLAKE8
12
12
 
13
13
  Flake8Error = t.Tuple[int, int, str, t.Type]
14
14
 
@@ -22,8 +22,8 @@ class Docsig:
22
22
  """
23
23
 
24
24
  off_by_default = False
25
- name = docsig.__name__
26
- version = docsig.__version__
25
+ name = __package__
26
+ version = __version__
27
27
  options_dict: t.Dict[str, bool] = {}
28
28
 
29
29
  def __init__(self, tree: ast.Module, filename: str) -> None:
@@ -141,25 +141,42 @@ class Docsig:
141
141
 
142
142
  :return: Flake8 error, if there is one.
143
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)
144
+ sys.argv = [
145
+ __package__,
146
+ self.filename,
147
+ *[
148
+ f"--{k.replace('_', '-')}"
149
+ for k, v in self.options_dict.items()
150
+ if v
151
+ ],
152
+ ]
153
+ p = Parser()
154
+ results = runner(
155
+ self.filename,
156
+ check_class=p.args.check_class,
157
+ check_class_constructor=p.args.check_class_constructor,
158
+ check_dunders=p.args.check_dunders,
159
+ check_protected_class_methods=(
160
+ p.args.check_protected_class_methods
161
+ ),
162
+ check_nested=p.args.check_nested,
163
+ check_overridden=p.args.check_overridden,
164
+ check_protected=p.args.check_protected,
165
+ check_property_returns=p.args.check_property_returns,
166
+ ignore_no_params=p.args.ignore_no_params,
167
+ ignore_args=p.args.ignore_args,
168
+ ignore_kwargs=p.args.ignore_kwargs,
169
+ ignore_typechecker=p.args.ignore_typechecker,
170
+ no_ansi=p.args.no_ansi,
171
+ )[0]
158
172
  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__
173
+ for info in result:
174
+ line = "{msg} '{name}'".format(
175
+ msg=FLAKE8.format(
176
+ ref=info.ref,
177
+ description=info.description,
178
+ symbolic=info.symbolic,
179
+ ),
180
+ name=info.name,
181
+ )
182
+ yield info.lineno, 0, line, self.__class__
@@ -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.58.0"
14
+ current_version = "0.59.1"
15
15
  message = "bump: version {current_version} → {new_version}"
16
16
  sign_tags = true
17
17
  tag = true
@@ -132,7 +132,7 @@ maintainers = [
132
132
  name = "docsig"
133
133
  readme = "README.rst"
134
134
  repository = "https://github.com/jshwi/docsig"
135
- version = "0.58.0"
135
+ version = "0.59.1"
136
136
 
137
137
  [tool.poetry.dependencies]
138
138
  Sphinx = "^7.0.0"
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
File without changes