docsig 0.90.1__tar.gz → 0.90.3__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 (27) hide show
  1. {docsig-0.90.1 → docsig-0.90.3}/PKG-INFO +4 -4
  2. {docsig-0.90.1 → docsig-0.90.3}/README.rst +3 -3
  3. {docsig-0.90.1 → docsig-0.90.3}/docsig/_module.py +2 -2
  4. {docsig-0.90.1 → docsig-0.90.3}/docsig/_report.py +4 -4
  5. {docsig-0.90.1 → docsig-0.90.3}/docsig/_stub.py +62 -18
  6. {docsig-0.90.1 → docsig-0.90.3}/docsig/_version.py +1 -1
  7. {docsig-0.90.1 → docsig-0.90.3}/pyproject.toml +4 -4
  8. {docsig-0.90.1 → docsig-0.90.3}/LICENSE +0 -0
  9. {docsig-0.90.1 → docsig-0.90.3}/LICENSES/SPHINX_LICENSE +0 -0
  10. {docsig-0.90.1 → docsig-0.90.3}/docsig/__init__.py +0 -0
  11. {docsig-0.90.1 → docsig-0.90.3}/docsig/__main__.py +0 -0
  12. {docsig-0.90.1 → docsig-0.90.3}/docsig/_check.py +0 -0
  13. {docsig-0.90.1 → docsig-0.90.3}/docsig/_config.py +0 -0
  14. {docsig-0.90.1 → docsig-0.90.3}/docsig/_core.py +0 -0
  15. {docsig-0.90.1 → docsig-0.90.3}/docsig/_decorators.py +0 -0
  16. {docsig-0.90.1 → docsig-0.90.3}/docsig/_directives.py +0 -0
  17. {docsig-0.90.1 → docsig-0.90.3}/docsig/_files.py +0 -0
  18. {docsig-0.90.1 → docsig-0.90.3}/docsig/_hooks.py +0 -0
  19. {docsig-0.90.1 → docsig-0.90.3}/docsig/_main.py +0 -0
  20. {docsig-0.90.1 → docsig-0.90.3}/docsig/_parsers.py +0 -0
  21. {docsig-0.90.1 → docsig-0.90.3}/docsig/_utils.py +0 -0
  22. {docsig-0.90.1 → docsig-0.90.3}/docsig/_vendor/sphinx/ext/napoleon.py +0 -0
  23. {docsig-0.90.1 → docsig-0.90.3}/docsig/messages.py +0 -0
  24. {docsig-0.90.1 → docsig-0.90.3}/docsig/plugin/__init__.py +0 -0
  25. {docsig-0.90.1 → docsig-0.90.3}/docsig/plugin/_flake8.py +0 -0
  26. {docsig-0.90.1 → docsig-0.90.3}/docsig/plugin/_validate_pyproject.py +0 -0
  27. {docsig-0.90.1 → docsig-0.90.3}/docsig/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docsig
3
- Version: 0.90.1
3
+ Version: 0.90.3
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.1, mccabe: 0.7.0, pycodestyle: 2.14.0, pyflakes: 3.4.0) CPython 3.10.19 on Darwin
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
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.1
295
+ rev: v0.90.3
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.1
314
+ - docsig==0.90.3
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.1, mccabe: 0.7.0, pycodestyle: 2.14.0, pyflakes: 3.4.0) CPython 3.10.19 on Darwin
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
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.1
267
+ rev: v0.90.3
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.1
286
+ - docsig==0.90.3
287
287
  args:
288
288
  - "--sig-check-class"
289
289
  - "--sig-check-dunders"
@@ -282,8 +282,8 @@ class Function(Parent): # pylint: disable=too-many-instance-attributes
282
282
 
283
283
  @property
284
284
  def isproperty(self) -> bool:
285
- """Whether this function is a property."""
286
- valid_properties = "property", "cached_property"
285
+ """Whether this function is a property or property method."""
286
+ valid_properties = "property", "cached_property", "setter", "deleter"
287
287
  return self.ismethod and any(
288
288
  self._decorated_with(i) for i in valid_properties
289
289
  )
@@ -36,14 +36,14 @@ _MIN_MATCH = 0.8
36
36
  _MAX_MATCH = 1.0
37
37
 
38
38
 
39
- def check_function(func: _Function, config: _Config) -> "Failure":
39
+ def check_function(func: _Function, config: _Config) -> "FunctionChecker":
40
40
  """Run configured checks for one function and return the result.
41
41
 
42
42
  :param func: Function under check.
43
43
  :param config: Configuration object.
44
44
  :return: Collected diagnostics for the function.
45
45
  """
46
- return Failure(func, config)
46
+ return FunctionChecker(func, config)
47
47
 
48
48
 
49
49
  class RetCode:
@@ -68,7 +68,7 @@ class RetCode:
68
68
  return max(self._data)
69
69
 
70
70
 
71
- class Failures(list["Failure"]):
71
+ class Failures(list["FunctionChecker"]):
72
72
  """Sequence of Failure instances (one per function checked)."""
73
73
 
74
74
 
@@ -85,7 +85,7 @@ class Diagnostic: # pylint: disable=too-few-public-methods
85
85
  new: bool = False
86
86
 
87
87
 
88
- class Failure(list[Diagnostic]):
88
+ class FunctionChecker(list[Diagnostic]):
89
89
  """Collect docstring and signature failures for one function.
90
90
 
91
91
  Runs configured checks and appends Failed entries for each
@@ -7,8 +7,8 @@ Stub types for parsed docstrings and signatures.
7
7
 
8
8
  from __future__ import annotations as _
9
9
 
10
+ import inspect as _inspect
10
11
  import re as _re
11
- import textwrap as _textwrap
12
12
  import typing as _t
13
13
  from collections import Counter as _Counter
14
14
  from enum import Enum as _Enum
@@ -42,6 +42,18 @@ class RetType(_Enum):
42
42
  if isinstance(returns, _ast.nodes.Const) and returns.value is None:
43
43
  return cls.NONE
44
44
 
45
+ # NoReturn / Never mean the function never returns a value, so
46
+ # treat them the same as -> None for documentation purposes
47
+ _no_return = {"NoReturn", "Never"}
48
+ if isinstance(returns, _ast.nodes.Name) and returns.name in _no_return:
49
+ return cls.NONE
50
+
51
+ if (
52
+ isinstance(returns, _ast.nodes.Attribute)
53
+ and returns.attrname in _no_return
54
+ ):
55
+ return cls.NONE
56
+
45
57
  if isinstance(
46
58
  returns,
47
59
  (
@@ -325,21 +337,44 @@ class Docstring(_Stub):
325
337
 
326
338
  return False
327
339
 
340
+ @staticmethod
341
+ def _docstring_style(string: str) -> str:
342
+ # prefer existing rst fields over napoleon section headers
343
+ if _re.search(r"^:\w+", string, _re.MULTILINE):
344
+ return "rst"
345
+
346
+ if _re.search(
347
+ r"^(Parameters|Other Parameters|Returns|Yields|Raises|"
348
+ r"See Also|Notes|Examples|Attributes|Methods)\n"
349
+ r"\s*-{3,}\s*$",
350
+ string,
351
+ _re.MULTILINE,
352
+ ):
353
+ return "numpy"
354
+
355
+ if _re.search(
356
+ r"^(Args|Arguments|Parameters|Returns|Yields|Raises|"
357
+ r"Attributes|Example|Examples):\s*$",
358
+ string,
359
+ _re.MULTILINE,
360
+ ):
361
+ return "google"
362
+
363
+ return "rst"
364
+
328
365
  @staticmethod
329
366
  def _normalize_docstring(string: str) -> str:
330
- # convert Google and numpy style docstrings to parse docstrings
331
- # as restructured text
332
- return str(
333
- _s.NumpyDocstring( # type: ignore
334
- str(
335
- _s.GoogleDocstring( # type: ignore
336
- _textwrap.dedent(
337
- "\n".join(string.splitlines()[1:]),
338
- ).replace("*", ""),
339
- ),
340
- ),
341
- ),
342
- )
367
+ # convert Google or numpy style to rst when detected
368
+ # leave rst (including field lists) unchanged
369
+ string = _inspect.cleandoc(string)
370
+ style = Docstring._docstring_style(string)
371
+ if style == "google":
372
+ return str(_s.GoogleDocstring(string)) # type: ignore
373
+
374
+ if style == "numpy":
375
+ return str(_s.NumpyDocstring(string)) # type: ignore
376
+
377
+ return string
343
378
 
344
379
  def __init__(
345
380
  self,
@@ -359,9 +394,9 @@ class Docstring(_Stub):
359
394
  indent_anomaly = cls._indent_anomaly(node.value)
360
395
  string = cls._normalize_docstring(node.value)
361
396
  match = _re.search(
362
- r":(?:returns?|yields?):\s*(.*)",
397
+ r"^[ \t]*:(?:returns?|yields?):\s*(.*)",
363
398
  string,
364
- _re.IGNORECASE,
399
+ _re.IGNORECASE | _re.MULTILINE,
365
400
  )
366
401
  returns = _Return(
367
402
  bool(match),
@@ -371,16 +406,25 @@ class Docstring(_Stub):
371
406
  # the suggestion is broken
372
407
  # noinspection RegExpSingleCharAlternation
373
408
  for match in _re.findall(
374
- r":([\w\s]+(?:\s\|\s[\w\s]+|\w+))([^\w\s])((?:.|\n)*?)(?=\n:|$)",
409
+ r"^[ \t]*:((?:\\?\*){0,2}[\w]+"
410
+ r"(?:\s+(?:\\?\*){0,2}[\w]+|"
411
+ r"\s\|\s(?:\\?\*){0,2}[\w]+)*)"
412
+ r"([^\w\s\\*])"
413
+ r"((?:.|\n)*?)(?=\n[ \t]*:|\Z)",
375
414
  string,
415
+ _re.MULTILINE,
376
416
  ):
377
417
  if match:
378
418
  kinds = match[0].split()
379
419
  if kinds:
420
+ name = None
421
+ if len(kinds) > 1:
422
+ # drop * / ** / napoleon-escaped stars on the name
423
+ name = kinds[-1].lstrip("\\*")
380
424
  docstring.args.append(
381
425
  Param(
382
426
  DocType.from_str(kinds[0]),
383
- UNNAMED if len(kinds) == 1 else kinds[-1],
427
+ UNNAMED if name is None else name,
384
428
  match[2] or None,
385
429
  int(indent_anomaly),
386
430
  match[1],
@@ -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.1"
11
+ __version__ = "0.90.3"
@@ -29,7 +29,7 @@ maintainers = [
29
29
  name = "docsig"
30
30
  readme = "README.rst"
31
31
  requires-python = ">=3.10"
32
- version = "0.90.1"
32
+ version = "0.90.3"
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.1"
50
+ current_version = "0.90.3"
51
51
  message = "bump: version {current_version} → {new_version}"
52
52
  sign_tags = true
53
53
  tag = true
@@ -146,9 +146,9 @@ 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.43"
149
+ gitpython = "^3.1.51"
150
150
  isort = ">=5.13.2,<9.0.0"
151
- mypy = ">=2.2.0,<3.0"
151
+ mypy = ">=2.3.0,<3.0"
152
152
  pre-commit = ">=3.3.3,<5.0.0"
153
153
  pylint = "^4.0.6"
154
154
  tomli = "^2.0.1"
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
File without changes
File without changes