docsig 0.90.3__tar.gz → 0.91.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.
Files changed (28) hide show
  1. {docsig-0.90.3 → docsig-0.91.0}/PKG-INFO +4 -4
  2. {docsig-0.90.3 → docsig-0.91.0}/README.rst +3 -3
  3. {docsig-0.90.3 → docsig-0.91.0}/docsig/_check.py +2 -0
  4. {docsig-0.90.3 → docsig-0.91.0}/docsig/_config.py +8 -7
  5. docsig-0.91.0/docsig/_diagnostic.py +21 -0
  6. {docsig-0.90.3 → docsig-0.91.0}/docsig/_main.py +0 -1
  7. {docsig-0.90.3 → docsig-0.91.0}/docsig/_parsers.py +3 -3
  8. {docsig-0.90.3 → docsig-0.91.0}/docsig/_report.py +99 -45
  9. {docsig-0.90.3 → docsig-0.91.0}/docsig/_version.py +1 -1
  10. {docsig-0.90.3 → docsig-0.91.0}/pyproject.toml +3 -3
  11. {docsig-0.90.3 → docsig-0.91.0}/LICENSE +0 -0
  12. {docsig-0.90.3 → docsig-0.91.0}/LICENSES/SPHINX_LICENSE +0 -0
  13. {docsig-0.90.3 → docsig-0.91.0}/docsig/__init__.py +0 -0
  14. {docsig-0.90.3 → docsig-0.91.0}/docsig/__main__.py +0 -0
  15. {docsig-0.90.3 → docsig-0.91.0}/docsig/_core.py +0 -0
  16. {docsig-0.90.3 → docsig-0.91.0}/docsig/_decorators.py +0 -0
  17. {docsig-0.90.3 → docsig-0.91.0}/docsig/_directives.py +0 -0
  18. {docsig-0.90.3 → docsig-0.91.0}/docsig/_files.py +0 -0
  19. {docsig-0.90.3 → docsig-0.91.0}/docsig/_hooks.py +0 -0
  20. {docsig-0.90.3 → docsig-0.91.0}/docsig/_module.py +0 -0
  21. {docsig-0.90.3 → docsig-0.91.0}/docsig/_stub.py +0 -0
  22. {docsig-0.90.3 → docsig-0.91.0}/docsig/_utils.py +0 -0
  23. {docsig-0.90.3 → docsig-0.91.0}/docsig/_vendor/sphinx/ext/napoleon.py +0 -0
  24. {docsig-0.90.3 → docsig-0.91.0}/docsig/messages.py +0 -0
  25. {docsig-0.90.3 → docsig-0.91.0}/docsig/plugin/__init__.py +0 -0
  26. {docsig-0.90.3 → docsig-0.91.0}/docsig/plugin/_flake8.py +0 -0
  27. {docsig-0.90.3 → docsig-0.91.0}/docsig/plugin/_validate_pyproject.py +0 -0
  28. {docsig-0.90.3 → docsig-0.91.0}/docsig/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docsig
3
- Version: 0.90.3
3
+ Version: 0.91.0
4
4
  Summary: Check signature params for proper documentation
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -206,7 +206,7 @@ ensure your installation has registered `docsig`
206
206
  .. code-block:: console
207
207
 
208
208
  $ flake8 --version
209
- 7.3.0 (docsig: 0.90.3, mccabe: 0.7.0, pycodestyle: 2.14.0, pyflakes: 3.4.0) CPython 3.10.19 on Darwin
209
+ 7.3.0 (docsig: 0.91.0, mccabe: 0.7.0, pycodestyle: 2.14.0, pyflakes: 3.4.0) CPython 3.10.19 on Darwin
210
210
 
211
211
  And now use `flake8` to lint your files
212
212
 
@@ -292,7 +292,7 @@ Standalone
292
292
 
293
293
  repos:
294
294
  - repo: https://github.com/jshwi/docsig
295
- rev: v0.90.3
295
+ rev: v0.91.0
296
296
  hooks:
297
297
  - id: docsig
298
298
  args:
@@ -311,7 +311,7 @@ or integrated with ``flake8``
311
311
  hooks:
312
312
  - id: flake8
313
313
  additional_dependencies:
314
- - docsig==0.90.3
314
+ - docsig==0.91.0
315
315
  args:
316
316
  - "--sig-check-class"
317
317
  - "--sig-check-dunders"
@@ -178,7 +178,7 @@ ensure your installation has registered `docsig`
178
178
  .. code-block:: console
179
179
 
180
180
  $ flake8 --version
181
- 7.3.0 (docsig: 0.90.3, mccabe: 0.7.0, pycodestyle: 2.14.0, pyflakes: 3.4.0) CPython 3.10.19 on Darwin
181
+ 7.3.0 (docsig: 0.91.0, mccabe: 0.7.0, pycodestyle: 2.14.0, pyflakes: 3.4.0) CPython 3.10.19 on Darwin
182
182
 
183
183
  And now use `flake8` to lint your files
184
184
 
@@ -264,7 +264,7 @@ Standalone
264
264
 
265
265
  repos:
266
266
  - repo: https://github.com/jshwi/docsig
267
- rev: v0.90.3
267
+ rev: v0.91.0
268
268
  hooks:
269
269
  - id: docsig
270
270
  args:
@@ -283,7 +283,7 @@ or integrated with ``flake8``
283
283
  hooks:
284
284
  - id: flake8
285
285
  additional_dependencies:
286
- - docsig==0.90.3
286
+ - docsig==0.91.0
287
287
  args:
288
288
  - "--sig-check-class"
289
289
  - "--sig-check-dunders"
@@ -1,6 +1,8 @@
1
1
  """
2
2
  docsig._check
3
3
  =============
4
+
5
+ Traverse modules and run docstring/signature checks per function.
4
6
  """
5
7
 
6
8
  from ._config import Config as _Config
@@ -156,17 +156,10 @@ def build_parser() -> _ArgumentParser:
156
156
  action="store_true",
157
157
  help="check nested functions and classes",
158
158
  )
159
- parser.add_argument(
160
- "-o",
161
- action="store_true",
162
- help=_argparse.SUPPRESS,
163
- dest="check_overridden",
164
- )
165
159
  parser.add_argument(
166
160
  "--check-overridden",
167
161
  action="store_true",
168
162
  help="check overridden methods",
169
- dest="check_overridden",
170
163
  )
171
164
  parser.add_argument(
172
165
  "--check-property-returns",
@@ -332,6 +325,14 @@ class Config:
332
325
 
333
326
  Groups check, ignore settings, and run options so the core runner
334
327
  takes a single config object instead of many parameters.
328
+
329
+ :param check: Configuration for which docstrings and members to
330
+ check.
331
+ :param ignore: Configuration for which docstring elements to ignore.
332
+ :param filters: Configuration for which paths to filter.
333
+ :param target: List of errors to target.
334
+ :param disable: List of errors to disable.
335
+ :param no_ansi: Disable ANSI output.
335
336
  """
336
337
 
337
338
  check: Check = _field(default_factory=Check)
@@ -0,0 +1,21 @@
1
+ """
2
+ docsig._diagnostic
3
+ ==================
4
+
5
+ Diagnostic records and per-function check results for docsig runs.
6
+ """
7
+
8
+ from dataclasses import dataclass as _dataclass
9
+
10
+
11
+ @_dataclass(frozen=True, order=True)
12
+ class Diagnostic: # pylint: disable=too-few-public-methods
13
+ """Single reported issue for one function."""
14
+
15
+ name: str
16
+ ref: str
17
+ description: str
18
+ symbolic: str
19
+ lineno: int
20
+ hint: str | None = None
21
+ new: bool = False
@@ -19,7 +19,6 @@ def _warn_on_deprecated_short_flags() -> None:
19
19
  "-I": "--include-ignored",
20
20
  "-c": "--check-class",
21
21
  "-D": "--check-dunders",
22
- "-o": "--check-overridden",
23
22
  }
24
23
  raw_args = _sys.argv[1:]
25
24
  expanded_flags = []
@@ -25,9 +25,9 @@ def parse_from_string(
25
25
  ) -> _Parent:
26
26
  """Build a Parent from a string of Python code.
27
27
 
28
- Parses AST and comment directives (AST does not include comments,
29
- so directives are parsed separately). On syntax error, returns a
30
- Parent with an error set.
28
+ Parses AST and comment directives (AST does not include comments, so
29
+ directives are parsed separately). On syntax error, returns a Parent
30
+ with an error set.
31
31
 
32
32
  :param code: Python source to parse.
33
33
  :param config: Configuration object.
@@ -2,10 +2,7 @@
2
2
  docsig._report
3
3
  ==============
4
4
 
5
- Collect and format docstring-check failures for reporting. This module
6
- defines Failure (per-function validation results), Failed (one reported
7
- issue), Failures (sequence of failures), and report() to print them and
8
- return the highest exit code.
5
+ Format and print docstring-check diagnostics for CLI and tooling.
9
6
  """
10
7
 
11
8
  import contextlib as _contextlib
@@ -13,12 +10,12 @@ import json as _json
13
10
  import os as _os
14
11
  import sys as _sys
15
12
  import typing as _t
16
- from dataclasses import dataclass as _dataclass
17
13
  from warnings import warn as _warn
18
14
 
19
15
  import astroid as _ast
20
16
 
21
17
  from ._config import Config as _Config
18
+ from ._diagnostic import Diagnostic as _Diagnostic
22
19
  from ._module import Function as _Function
23
20
  from ._stub import UNNAMED as _UNNAMED
24
21
  from ._stub import VALID_DESCRIPTION as _VALID_DESCRIPTION
@@ -36,14 +33,14 @@ _MIN_MATCH = 0.8
36
33
  _MAX_MATCH = 1.0
37
34
 
38
35
 
39
- def check_function(func: _Function, config: _Config) -> "FunctionChecker":
36
+ def check_function(func: _Function, config: _Config) -> "_FunctionResult":
40
37
  """Run configured checks for one function and return the result.
41
38
 
42
39
  :param func: Function under check.
43
40
  :param config: Configuration object.
44
41
  :return: Collected diagnostics for the function.
45
42
  """
46
- return FunctionChecker(func, config)
43
+ return FunctionChecker(func, config).run()
47
44
 
48
45
 
49
46
  class RetCode:
@@ -68,24 +65,11 @@ class RetCode:
68
65
  return max(self._data)
69
66
 
70
67
 
71
- class Failures(list["FunctionChecker"]):
72
- """Sequence of Failure instances (one per function checked)."""
68
+ class Failures(list["_FunctionResult"]):
69
+ """Sequence of result instances (one per function checked)."""
73
70
 
74
71
 
75
- @_dataclass(frozen=True, order=True)
76
- class Diagnostic: # pylint: disable=too-few-public-methods
77
- """Single reported issue."""
78
-
79
- name: str
80
- ref: str
81
- description: str
82
- symbolic: str
83
- lineno: int
84
- hint: str | None = None
85
- new: bool = False
86
-
87
-
88
- class FunctionChecker(list[Diagnostic]):
72
+ class FunctionChecker: # pylint: disable=too-few-public-methods
89
73
  """Collect docstring and signature failures for one function.
90
74
 
91
75
  Runs configured checks and appends Failed entries for each
@@ -96,9 +80,9 @@ class FunctionChecker(list[Diagnostic]):
96
80
  """
97
81
 
98
82
  def __init__(self, func: _Function, config: _Config) -> None:
99
- super().__init__()
100
- self._retcode = RetCode()
101
83
  self._func = func
84
+ self._config = config
85
+ self._diagnostics: list[_Diagnostic] = []
102
86
  if config.target:
103
87
  self._func.messages.extend(
104
88
  i for i in _E.all if i not in config.target
@@ -113,8 +97,15 @@ class FunctionChecker(list[Diagnostic]):
113
97
  ):
114
98
  self._name = f"{self._func.parent.name}.{self._name}"
115
99
 
100
+ self._collector = _Collector(func, self._name, self._func.lineno)
101
+
102
+ def run(self) -> "_FunctionResult":
103
+ """Run the function checks and return the result.
104
+
105
+ :return: Function result.
106
+ """
116
107
  if self._func.error is not None:
117
- self._retcode.add(2)
108
+ self._collector.retcode.add(2)
118
109
  self._sig9xx_error()
119
110
  else:
120
111
  self._sig0xx_config()
@@ -128,9 +119,9 @@ class FunctionChecker(list[Diagnostic]):
128
119
  sig = self._func.signature.args.get(index)
129
120
  self._sig4xx_parameters(doc, sig)
130
121
 
131
- self._sig5xx_returns(config.check.property_returns)
122
+ self._sig5xx_returns(self._config.check.property_returns)
132
123
 
133
- self.sort()
124
+ return _FunctionResult(self._name, self._func.lineno, self._collector)
134
125
 
135
126
  def _add(
136
127
  self,
@@ -138,18 +129,7 @@ class FunctionChecker(list[Diagnostic]):
138
129
  include_hint: bool = False,
139
130
  **kwargs: _t.Any,
140
131
  ) -> None:
141
- self._retcode.add(int(not value.new))
142
- failed = Diagnostic(
143
- self._name,
144
- value.ref,
145
- value.description.format(**kwargs),
146
- value.symbolic,
147
- self.lineno,
148
- value.hint if include_hint else None,
149
- value.new,
150
- )
151
- if value not in self._func.messages and failed not in self:
152
- super().append(failed)
132
+ self._collector.add(value, include_hint=include_hint, **kwargs)
153
133
 
154
134
  @staticmethod
155
135
  def _normalize_params(from_: _Params, to: _Params) -> None:
@@ -371,7 +351,7 @@ class FunctionChecker(list[Diagnostic]):
371
351
  # invalid-syntax
372
352
  if self._func.error is _ast.AstroidSyntaxError:
373
353
  self._add(_E[901])
374
- self._retcode.add(123)
354
+ self._collector.retcode.add(123)
375
355
  # unicode-decode-error
376
356
  if self._func.error is UnicodeDecodeError:
377
357
  self._add(_E[902])
@@ -382,6 +362,73 @@ class FunctionChecker(list[Diagnostic]):
382
362
  if self._func.error is _ast.DuplicateBasesError:
383
363
  self._add(_E[904])
384
364
 
365
+
366
+ class _Collector:
367
+ def __init__(
368
+ self,
369
+ func: _Function,
370
+ qualified_name: str,
371
+ lineno: int,
372
+ ) -> None:
373
+ self._func = func
374
+ self._qualified_name = qualified_name
375
+ self._lineno = lineno
376
+ self._diagnostics: list[_Diagnostic] = []
377
+ self._retcode = RetCode()
378
+
379
+ def add(
380
+ self,
381
+ value: _Message,
382
+ include_hint: bool = False,
383
+ **kwargs: _t.Any,
384
+ ) -> None:
385
+ """Add a diagnostic message.
386
+
387
+ :param value: Message to add.
388
+ :param include_hint: Whether to include the hint.
389
+ :param kwargs: Additional arguments to format the description.
390
+ """
391
+ self._retcode.add(int(not value.new))
392
+ diagnostic = _Diagnostic(
393
+ self._qualified_name,
394
+ value.ref,
395
+ value.description.format(**kwargs),
396
+ value.symbolic,
397
+ self._lineno,
398
+ value.hint if include_hint else None,
399
+ value.new,
400
+ )
401
+ if (
402
+ value not in self._func.messages
403
+ and diagnostic not in self._diagnostics
404
+ ):
405
+ self._diagnostics.append(diagnostic)
406
+
407
+ @property
408
+ def diagnostics(self) -> list[_Diagnostic]:
409
+ """Diagnostics sorted for stable output."""
410
+ return sorted(self._diagnostics)
411
+
412
+ @property
413
+ def retcode(self) -> RetCode:
414
+ """Exit code (non-zero if any check failed)."""
415
+ return self._retcode
416
+
417
+ def __bool__(self) -> bool:
418
+ return bool(self._diagnostics)
419
+
420
+
421
+ class _FunctionResult:
422
+ def __init__(
423
+ self,
424
+ name: str,
425
+ lineno: int,
426
+ collector: _Collector,
427
+ ) -> None:
428
+ self._name = name
429
+ self._lineno = lineno
430
+ self._collector = collector
431
+
385
432
  @property
386
433
  def name(self) -> str:
387
434
  """Qualified name (Class.method) when nested, else bare name."""
@@ -390,12 +437,18 @@ class FunctionChecker(list[Diagnostic]):
390
437
  @property
391
438
  def lineno(self) -> int:
392
439
  """Line number of the function in the source."""
393
- return self._func.lineno
440
+ return self._lineno
394
441
 
395
442
  @property
396
443
  def retcode(self) -> int:
397
444
  """Exit code (non-zero if any check failed)."""
398
- return self._retcode.result
445
+ return self._collector.retcode.result
446
+
447
+ def __iter__(self) -> _t.Iterator[_Diagnostic]:
448
+ return iter(self._collector.diagnostics)
449
+
450
+ def __bool__(self) -> bool:
451
+ return bool(self._collector)
399
452
 
400
453
 
401
454
  # TODO: make report json by default and wrap with a reporter for cli
@@ -404,12 +457,13 @@ def report(
404
457
  config: _Config,
405
458
  file: str | None = None,
406
459
  ) -> int:
407
- """Print failures to stdout and return the highest exit code.
460
+ """Print failures and return the highest exit code.
408
461
 
409
462
  Iterates over failures, prints each with path, line header, and
410
463
  messages, then returns the maximum retcode (0 or non-zero).
411
464
 
412
- :param failures: Failures to print (one Failure per function).
465
+ :param failures: Failures to print (one FunctionResult per
466
+ function).
413
467
  :param config: Config for ANSI and formatting.
414
468
  :param file: Module path when failures came from a file (optional).
415
469
  :return: Exit code (non-zero if any check failed).
@@ -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.90.3"
11
+ __version__ = "0.91.0"
@@ -29,7 +29,7 @@ maintainers = [
29
29
  name = "docsig"
30
30
  readme = "README.rst"
31
31
  requires-python = ">=3.10"
32
- version = "0.90.3"
32
+ version = "0.91.0"
33
33
 
34
34
  [project.entry-points."flake8.extension"]
35
35
  SIG = "docsig.plugin:Flake8"
@@ -47,7 +47,7 @@ line-length = 79
47
47
  allow_dirty = true
48
48
  commit = true
49
49
  commit_args = "-sS"
50
- current_version = "0.90.3"
50
+ current_version = "0.91.0"
51
51
  message = "bump: version {current_version} → {new_version}"
52
52
  sign_tags = true
53
53
  tag = true
@@ -146,7 +146,7 @@ black = ">=24.4.2,<27.0.0"
146
146
  bump-my-version = ">=1.4.1,<1.5.0"
147
147
  deptry = ">=0.16.1,<0.26.0"
148
148
  flynt = "^1.0.1"
149
- gitpython = "^3.1.51"
149
+ gitpython = "^3.1.52"
150
150
  isort = ">=5.13.2,<9.0.0"
151
151
  mypy = ">=2.3.0,<3.0"
152
152
  pre-commit = ">=3.3.3,<5.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
File without changes