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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: docsig
3
- Version: 0.51.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
- .. image:: https://img.shields.io/badge/License-MIT-yellow.svg
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.51.0
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
- .. image:: https://img.shields.io/badge/License-MIT-yellow.svg
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.51.0
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 .messages import TEMPLATE as _TEMPLATE
23
- from .messages import E as _E
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: list[_Message],
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.disabled, check_property_returns
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: list[_Message] | None = None,
142
- disable: list[_Message] | None = None,
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
- disable=disable or [],
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 = list(_E.fromcodes(kwargs.get("disable", []))) or None
29
- targets = list(_E.fromcodes(kwargs.get("targets", []))) or None
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, _: pretty_print_error(
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 Directive as _Directive
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
- overloads: list[str] = []
102
- returns = None
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.FunctionDef):
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
- overloads.append(func.name)
146
- returns = func.signature.rettype
154
+ self._overloads[func.name] = func
147
155
  else:
148
- if func.name in overloads:
149
- subnode.returns = returns
150
- # noinspection PyProtectedMember
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 disabled: List of disabled checks specific to this function.
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: _t.List[_Directive],
214
+ comments: list[_Comment],
215
215
  directives: _Directives,
216
- disabled: list[_Message],
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._directives = comments
232
- self._disabled = disabled
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 disabled(self) -> list[_Message]:
350
+ def messages(self) -> _Messages:
348
351
  """List of disabled checks specific to this function."""
349
- return self._disabled
352
+ return self._messages
350
353
 
351
354
  @property
352
- def directives(self) -> _t.List[_Directive]:
353
- """Directive, if any, belonging to this function."""
354
- return self._directives
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 disable: List of checks to disable.
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
- disable: list[_Message],
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, disable),
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
- pretty_print_error(type(err), msg, no_ansi=self._no_ansi)
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
- disable: list[_Message],
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._disable = disable
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.check_class_constructor = check_class_constructor
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
- disable,
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._disable,
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.check_class_constructor,
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: list[_Message],
35
- disable: list[_Message],
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: list[_Message] = []
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 directive in self._func.directives:
176
- if not directive.isvalid:
177
- err = _E[int(f"20{1 if directive.ismodule else 2}")]
178
- self._add(err, directive=directive.kind)
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 directive in self._func.directives:
182
- if directive.rules.unknown:
183
- err = _E[int(f"20{3 if directive.ismodule else 4}")]
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
- err, directive=directive.kind, option=rule.description
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))
@@ -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.51.0"
11
+ __version__ = "0.52.0"
@@ -23,116 +23,196 @@ docsig.messages
23
23
  | E204: unknown inline comment option for {directive} '{option}'
24
24
  """
25
25
 
26
- from ._message import Message as _Message
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 = _Messages(
113
+ E = MessageMap(
34
114
  {
35
115
  # E1xx: Docstring
36
- 101: _Message(
116
+ 101: Message(
37
117
  "E101",
38
118
  "parameters out of order",
39
119
  "params-out-of-order",
40
120
  ),
41
- 102: _Message(
121
+ 102: Message(
42
122
  "E102",
43
123
  "includes parameters that do not exist",
44
124
  "params-do-not-exist",
45
125
  ),
46
- 103: _Message(
126
+ 103: Message(
47
127
  "E103",
48
128
  "parameters missing",
49
129
  "params-missing",
50
130
  ),
51
- 104: _Message(
131
+ 104: Message(
52
132
  "E104",
53
133
  "return statement documented for None",
54
134
  "return-documented-for-none",
55
135
  ),
56
- 105: _Message(
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: _Message(
142
+ 106: Message(
63
143
  "E106",
64
144
  "duplicate parameters found",
65
145
  "duplicate-params-found",
66
146
  ),
67
- 107: _Message(
147
+ 107: Message(
68
148
  "E107",
69
149
  "parameter appears to be incorrectly documented",
70
150
  "param-incorrectly-documented",
71
151
  ),
72
- 108: _Message(
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: _Message(
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: _Message(
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: _Message(
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: _Message(
174
+ 112: Message(
95
175
  "E112",
96
176
  "spelling error found in documented parameter",
97
177
  "spelling-error",
98
178
  ),
99
- 113: _Message(
179
+ 113: Message(
100
180
  "E113",
101
181
  "function is missing a docstring",
102
182
  "function-doc-missing",
103
183
  ),
104
- 114: _Message(
184
+ 114: Message(
105
185
  "E114",
106
186
  "class is missing a docstring",
107
187
  "class-doc-missing",
108
188
  ),
109
- 115: _Message(
189
+ 115: Message(
110
190
  "E115",
111
191
  "syntax error in description",
112
192
  "syntax-error-in-description",
113
193
  ),
114
- 116: _Message(
194
+ 116: Message(
115
195
  "E116",
116
196
  "param not indented correctly",
117
197
  "incorrect-indent",
118
198
  ),
119
199
  # E2xx: Config
120
- 201: _Message(
200
+ 201: Message(
121
201
  "E201",
122
202
  "unknown module comment directive '{directive}'",
123
203
  "unknown-module-directive",
124
204
  ),
125
- 202: _Message(
205
+ 202: Message(
126
206
  "E202",
127
207
  "unknown inline comment directive '{directive}'",
128
208
  "unknown-inline-directive",
129
209
  ),
130
- 203: _Message(
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: _Message(
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.51.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)
@@ -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