docsig 0.40.0__tar.gz → 0.42.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.40.0
3
+ Version: 0.42.0
4
4
  Summary: Check signature params for proper documentation
5
5
  Home-page: https://pypi.org/project/docsig/
6
6
  License: MIT
@@ -18,8 +18,8 @@ Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
19
  Requires-Dist: Pygments (>=2.13.0,<3.0.0)
20
20
  Requires-Dist: Sphinx (>=4.3.2,<7.0.0)
21
- Requires-Dist: arcon (>=0,<1)
22
- Requires-Dist: astroid (>=2.11.6,<3.0.0)
21
+ Requires-Dist: arcon (>=0.3.1,<0.4.0)
22
+ Requires-Dist: astroid (>=3.0.1,<4.0.0)
23
23
  Requires-Dist: object-colors (>=2.1.0,<3.0.0)
24
24
  Requires-Dist: typing-extensions (>=4.8.0,<5.0.0)
25
25
  Project-URL: Documentation, https://docsig.readthedocs.io/en/latest
@@ -105,31 +105,36 @@ Commandline
105
105
 
106
106
  .. code-block:: console
107
107
 
108
- usage: docsig [-h] [-v] [-c] [-D] [-o] [-p] [-P] [-i] [-a] [-k] [-n] [-S] [-s STR]
109
- [-d LIST] [-t LIST]
108
+ usage: docsig [-h] [-v] [-c | -C] [-D] [-m] [-o] [-p] [-P] [-i] [-a] [-k] [-n]
109
+ [-S] [-s STR] [-d LIST] [-t LIST]
110
110
  path [path ...]
111
111
 
112
112
  Check signature params for proper documentation
113
113
 
114
114
  positional arguments:
115
- path directories or files to check
115
+ path directories or files to check
116
116
 
117
117
  optional arguments:
118
- -h, --help show this help message and exit
119
- -v, --version show program's version number and exit
120
- -c, --check-class check class docstrings
121
- -D, --check-dunders check dunder methods
122
- -o, --check-overridden check overridden methods
123
- -p, --check-protected check protected functions and classes
124
- -P, --check-property-returns check property return values
125
- -i, --ignore-no-params ignore docstrings where parameters are not documented
126
- -a, --ignore-args ignore args prefixed with an asterisk
127
- -k, --ignore-kwargs ignore kwargs prefixed with two asterisks
128
- -n, --no-ansi disable ansi output
129
- -S, --summary print a summarised report
130
- -s STR, --string STR string to parse instead of files
131
- -d LIST, --disable LIST comma separated list of rules to disable
132
- -t LIST, --target LIST comma separated list of rules to target
118
+ -h, --help show this help message and exit
119
+ -v, --version show program's version number and exit
120
+ -c, --check-class check class docstrings
121
+ -C, --check-class-constructor check __init__ methods. Note: mutually
122
+ incompatible with -c
123
+ -D, --check-dunders check dunder methods
124
+ -m, --check-protected-class-methods check public methods belonging to protected
125
+ classes
126
+ -o, --check-overridden check overridden methods
127
+ -p, --check-protected check protected functions and classes
128
+ -P, --check-property-returns check property return values
129
+ -i, --ignore-no-params ignore docstrings where parameters are not
130
+ documented
131
+ -a, --ignore-args ignore args prefixed with an asterisk
132
+ -k, --ignore-kwargs ignore kwargs prefixed with two asterisks
133
+ -n, --no-ansi disable ansi output
134
+ -S, --summary print a summarised report
135
+ -s STR, --string STR string to parse instead of files
136
+ -d LIST, --disable LIST comma separated list of rules to disable
137
+ -t LIST, --target LIST comma separated list of rules to target
133
138
 
134
139
  Options can also be configured with the pyproject.toml file
135
140
 
@@ -195,7 +200,7 @@ API
195
200
  :param param3: ✖
196
201
  """
197
202
  <BLANKLINE>
198
- E102: includes parameters that do not exist
203
+ E102: includes parameters that do not exist (params-do-not-exist)
199
204
  <BLANKLINE>
200
205
  1
201
206
 
@@ -244,7 +249,7 @@ To disable individual function checks add an inline comment similar to the examp
244
249
  :param param3: ✖
245
250
  """
246
251
  <BLANKLINE>
247
- E102: includes parameters that do not exist
252
+ E102: includes parameters that do not exist (params-do-not-exist)
248
253
  <BLANKLINE>
249
254
  18
250
255
  --
@@ -255,7 +260,7 @@ To disable individual function checks add an inline comment similar to the examp
255
260
  :param None: ✖
256
261
  """
257
262
  <BLANKLINE>
258
- E103: parameters missing
263
+ E103: parameters missing (params-missing)
259
264
  <BLANKLINE>
260
265
  1
261
266
 
@@ -331,7 +336,7 @@ To disable multiple function checks add a module level disable and enable commen
331
336
  :param None: ✖
332
337
  """
333
338
  <BLANKLINE>
334
- E103: parameters missing
339
+ E103: parameters missing (params-missing)
335
340
  <BLANKLINE>
336
341
  1
337
342
 
@@ -378,7 +383,7 @@ The same can be done for disabling individual rules
378
383
  :return: ✖
379
384
  """
380
385
  <BLANKLINE>
381
- E105: return missing from docstring
386
+ E105: return missing from docstring (return-missing)
382
387
  <BLANKLINE>
383
388
  20
384
389
  --
@@ -390,9 +395,9 @@ The same can be done for disabling individual rules
390
395
  :param None: ✖
391
396
  """
392
397
  <BLANKLINE>
393
- E102: includes parameters that do not exist
394
- E106: duplicate parameters found
395
- E107: parameter appears to be incorrectly documented
398
+ E102: includes parameters that do not exist (params-do-not-exist)
399
+ E106: duplicate parameters found (duplicate-params-found)
400
+ E107: parameter appears to be incorrectly documented (param-incorrectly-documented)
396
401
  <BLANKLINE>
397
402
  1
398
403
 
@@ -441,16 +446,44 @@ Module level directives will be evaluated separately to inline directives and pr
441
446
  :param param3: ✖
442
447
  """
443
448
  <BLANKLINE>
444
- E102: includes parameters that do not exist
445
- E106: duplicate parameters found
449
+ E102: includes parameters that do not exist (params-do-not-exist)
450
+ E106: duplicate parameters found (duplicate-params-found)
446
451
  <BLANKLINE>
447
452
  1
448
453
 
449
454
  Classes
450
455
  *******
451
- Checking a class docstring is not enabled by default, as this check is opinionated, and won't suite everyone
456
+ Checking a class docstring is not enabled by default, as there are two mutually exclusive choices to choose from.
452
457
 
453
- This check will check documentation of ``__init__`` under the class docstring, and not under ``__init__`` itself
458
+ This check will either check the documentation of ``__init__``, or check documentation of ``__init__`` under the class docstring, and not under ``__init__`` itself
459
+
460
+ .. code-block:: python
461
+
462
+ >>> string = """
463
+ ... class Klass:
464
+ ... def __init__(self, param1, param2) -> None:
465
+ ... '''
466
+ ...
467
+ ... :param param1: About param1.
468
+ ... :param param2: About param2.
469
+ ... :param param3: About param3.
470
+ ... '''
471
+ ... """
472
+ >>> docsig(string=string, check_class_constructor=True)
473
+ 3 in Klass
474
+ ----------
475
+ class Klass:
476
+ """
477
+ :param param1: ✓
478
+ :param param2: ✓
479
+ :param param3: ✖
480
+ """
481
+ <BLANKLINE>
482
+ def __init__(✓param1, ✓param2, ✖None) -> ✓None:
483
+ <BLANKLINE>
484
+ E102: includes parameters that do not exist (params-do-not-exist)
485
+ <BLANKLINE>
486
+ 1
454
487
 
455
488
  .. code-block:: python
456
489
 
@@ -477,12 +510,19 @@ This check will check documentation of ``__init__`` under the class docstring, a
477
510
  <BLANKLINE>
478
511
  def __init__(✓param1, ✓param2, ✖None) -> ✓None:
479
512
  <BLANKLINE>
480
- E102: includes parameters that do not exist
513
+ E102: includes parameters that do not exist (params-do-not-exist)
481
514
  <BLANKLINE>
482
515
  1
483
516
 
484
517
  Checking class docstrings can be permanently enabled in the pyproject.toml file
485
518
 
519
+ .. code-block:: toml
520
+
521
+ [tool.docsig]
522
+ check-class-constructor = true
523
+
524
+ Or
525
+
486
526
  .. code-block:: toml
487
527
 
488
528
  [tool.docsig]
@@ -499,7 +539,7 @@ It can be added to your .pre-commit-config.yaml as follows:
499
539
 
500
540
  repos:
501
541
  - repo: https://github.com/jshwi/docsig
502
- rev: v0.40.0
542
+ rev: v0.42.0
503
543
  hooks:
504
544
  - id: docsig
505
545
  args:
@@ -77,31 +77,36 @@ Commandline
77
77
 
78
78
  .. code-block:: console
79
79
 
80
- usage: docsig [-h] [-v] [-c] [-D] [-o] [-p] [-P] [-i] [-a] [-k] [-n] [-S] [-s STR]
81
- [-d LIST] [-t LIST]
80
+ usage: docsig [-h] [-v] [-c | -C] [-D] [-m] [-o] [-p] [-P] [-i] [-a] [-k] [-n]
81
+ [-S] [-s STR] [-d LIST] [-t LIST]
82
82
  path [path ...]
83
83
 
84
84
  Check signature params for proper documentation
85
85
 
86
86
  positional arguments:
87
- path directories or files to check
87
+ path directories or files to check
88
88
 
89
89
  optional arguments:
90
- -h, --help show this help message and exit
91
- -v, --version show program's version number and exit
92
- -c, --check-class check class docstrings
93
- -D, --check-dunders check dunder methods
94
- -o, --check-overridden check overridden methods
95
- -p, --check-protected check protected functions and classes
96
- -P, --check-property-returns check property return values
97
- -i, --ignore-no-params ignore docstrings where parameters are not documented
98
- -a, --ignore-args ignore args prefixed with an asterisk
99
- -k, --ignore-kwargs ignore kwargs prefixed with two asterisks
100
- -n, --no-ansi disable ansi output
101
- -S, --summary print a summarised report
102
- -s STR, --string STR string to parse instead of files
103
- -d LIST, --disable LIST comma separated list of rules to disable
104
- -t LIST, --target LIST comma separated list of rules to target
90
+ -h, --help show this help message and exit
91
+ -v, --version show program's version number and exit
92
+ -c, --check-class check class docstrings
93
+ -C, --check-class-constructor check __init__ methods. Note: mutually
94
+ incompatible with -c
95
+ -D, --check-dunders check dunder methods
96
+ -m, --check-protected-class-methods check public methods belonging to protected
97
+ classes
98
+ -o, --check-overridden check overridden methods
99
+ -p, --check-protected check protected functions and classes
100
+ -P, --check-property-returns check property return values
101
+ -i, --ignore-no-params ignore docstrings where parameters are not
102
+ documented
103
+ -a, --ignore-args ignore args prefixed with an asterisk
104
+ -k, --ignore-kwargs ignore kwargs prefixed with two asterisks
105
+ -n, --no-ansi disable ansi output
106
+ -S, --summary print a summarised report
107
+ -s STR, --string STR string to parse instead of files
108
+ -d LIST, --disable LIST comma separated list of rules to disable
109
+ -t LIST, --target LIST comma separated list of rules to target
105
110
 
106
111
  Options can also be configured with the pyproject.toml file
107
112
 
@@ -167,7 +172,7 @@ API
167
172
  :param param3: ✖
168
173
  """
169
174
  <BLANKLINE>
170
- E102: includes parameters that do not exist
175
+ E102: includes parameters that do not exist (params-do-not-exist)
171
176
  <BLANKLINE>
172
177
  1
173
178
 
@@ -216,7 +221,7 @@ To disable individual function checks add an inline comment similar to the examp
216
221
  :param param3: ✖
217
222
  """
218
223
  <BLANKLINE>
219
- E102: includes parameters that do not exist
224
+ E102: includes parameters that do not exist (params-do-not-exist)
220
225
  <BLANKLINE>
221
226
  18
222
227
  --
@@ -227,7 +232,7 @@ To disable individual function checks add an inline comment similar to the examp
227
232
  :param None: ✖
228
233
  """
229
234
  <BLANKLINE>
230
- E103: parameters missing
235
+ E103: parameters missing (params-missing)
231
236
  <BLANKLINE>
232
237
  1
233
238
 
@@ -303,7 +308,7 @@ To disable multiple function checks add a module level disable and enable commen
303
308
  :param None: ✖
304
309
  """
305
310
  <BLANKLINE>
306
- E103: parameters missing
311
+ E103: parameters missing (params-missing)
307
312
  <BLANKLINE>
308
313
  1
309
314
 
@@ -350,7 +355,7 @@ The same can be done for disabling individual rules
350
355
  :return: ✖
351
356
  """
352
357
  <BLANKLINE>
353
- E105: return missing from docstring
358
+ E105: return missing from docstring (return-missing)
354
359
  <BLANKLINE>
355
360
  20
356
361
  --
@@ -362,9 +367,9 @@ The same can be done for disabling individual rules
362
367
  :param None: ✖
363
368
  """
364
369
  <BLANKLINE>
365
- E102: includes parameters that do not exist
366
- E106: duplicate parameters found
367
- E107: parameter appears to be incorrectly documented
370
+ E102: includes parameters that do not exist (params-do-not-exist)
371
+ E106: duplicate parameters found (duplicate-params-found)
372
+ E107: parameter appears to be incorrectly documented (param-incorrectly-documented)
368
373
  <BLANKLINE>
369
374
  1
370
375
 
@@ -413,16 +418,44 @@ Module level directives will be evaluated separately to inline directives and pr
413
418
  :param param3: ✖
414
419
  """
415
420
  <BLANKLINE>
416
- E102: includes parameters that do not exist
417
- E106: duplicate parameters found
421
+ E102: includes parameters that do not exist (params-do-not-exist)
422
+ E106: duplicate parameters found (duplicate-params-found)
418
423
  <BLANKLINE>
419
424
  1
420
425
 
421
426
  Classes
422
427
  *******
423
- Checking a class docstring is not enabled by default, as this check is opinionated, and won't suite everyone
428
+ Checking a class docstring is not enabled by default, as there are two mutually exclusive choices to choose from.
424
429
 
425
- This check will check documentation of ``__init__`` under the class docstring, and not under ``__init__`` itself
430
+ This check will either check the documentation of ``__init__``, or check documentation of ``__init__`` under the class docstring, and not under ``__init__`` itself
431
+
432
+ .. code-block:: python
433
+
434
+ >>> string = """
435
+ ... class Klass:
436
+ ... def __init__(self, param1, param2) -> None:
437
+ ... '''
438
+ ...
439
+ ... :param param1: About param1.
440
+ ... :param param2: About param2.
441
+ ... :param param3: About param3.
442
+ ... '''
443
+ ... """
444
+ >>> docsig(string=string, check_class_constructor=True)
445
+ 3 in Klass
446
+ ----------
447
+ class Klass:
448
+ """
449
+ :param param1: ✓
450
+ :param param2: ✓
451
+ :param param3: ✖
452
+ """
453
+ <BLANKLINE>
454
+ def __init__(✓param1, ✓param2, ✖None) -> ✓None:
455
+ <BLANKLINE>
456
+ E102: includes parameters that do not exist (params-do-not-exist)
457
+ <BLANKLINE>
458
+ 1
426
459
 
427
460
  .. code-block:: python
428
461
 
@@ -449,12 +482,19 @@ This check will check documentation of ``__init__`` under the class docstring, a
449
482
  <BLANKLINE>
450
483
  def __init__(✓param1, ✓param2, ✖None) -> ✓None:
451
484
  <BLANKLINE>
452
- E102: includes parameters that do not exist
485
+ E102: includes parameters that do not exist (params-do-not-exist)
453
486
  <BLANKLINE>
454
487
  1
455
488
 
456
489
  Checking class docstrings can be permanently enabled in the pyproject.toml file
457
490
 
491
+ .. code-block:: toml
492
+
493
+ [tool.docsig]
494
+ check-class-constructor = true
495
+
496
+ Or
497
+
458
498
  .. code-block:: toml
459
499
 
460
500
  [tool.docsig]
@@ -471,7 +511,7 @@ It can be added to your .pre-commit-config.yaml as follows:
471
511
 
472
512
  repos:
473
513
  - repo: https://github.com/jshwi/docsig
474
- rev: v0.40.0
514
+ rev: v0.42.0
475
515
  hooks:
476
516
  - id: docsig
477
517
  args:
@@ -53,6 +53,12 @@ class Parser(_ArgumentParser):
53
53
  action="store_true",
54
54
  help="check dunder methods",
55
55
  )
56
+ self.add_argument(
57
+ "-m",
58
+ "--check-protected-class-methods",
59
+ action="store_true",
60
+ help="check public methods belonging to protected classes",
61
+ )
56
62
  self.add_argument(
57
63
  "-o",
58
64
  "--check-overridden",
@@ -90,7 +96,10 @@ class Parser(_ArgumentParser):
90
96
  help="ignore kwargs prefixed with two asterisks",
91
97
  )
92
98
  self.add_argument(
93
- "-n", "--no-ansi", action="store_true", help="disable ansi output"
99
+ "-n",
100
+ "--no-ansi",
101
+ action="store_true",
102
+ help="disable ansi output",
94
103
  )
95
104
  self.add_argument(
96
105
  "-S",
@@ -13,9 +13,11 @@ from ._display import Failure as _Failure
13
13
  from ._display import Failures as _Failures
14
14
  from ._display import FuncStr as _FuncStr
15
15
  from ._display import color as _color
16
+ from ._message import Message as _Message
16
17
  from ._module import Modules as _Modules
17
18
  from ._module import Parent as _Parent
18
19
  from ._report import generate_report as _generate_report
20
+ from .messages import E as _E
19
21
 
20
22
 
21
23
  def pretty_print_error() -> None:
@@ -36,14 +38,18 @@ def _run_check( # pylint: disable=too-many-arguments
36
38
  check_property_returns: bool,
37
39
  ignore_no_params: bool,
38
40
  no_ansi: bool,
39
- targets: list[str],
41
+ targets: list[_Message],
40
42
  ) -> _Failures:
41
43
  failures = _Failures()
42
44
  for func in parent:
43
45
  if not (func.isoverridden and not check_overridden) and (
44
46
  not (func.isprotected and not check_protected)
45
47
  and not (
46
- func.isinit and not (check_class or check_class_constructor)
48
+ func.isinit
49
+ and not (
50
+ (check_class or check_class_constructor)
51
+ and not (parent.isprotected and not check_protected)
52
+ )
47
53
  )
48
54
  and not (func.isdunder and not check_dunders)
49
55
  and not (func.docstring.bare and ignore_no_params)
@@ -59,12 +65,13 @@ def _run_check( # pylint: disable=too-many-arguments
59
65
  return failures
60
66
 
61
67
 
62
- def docsig( # pylint: disable=too-many-locals
68
+ def docsig( # pylint: disable=too-many-locals,too-many-arguments
63
69
  *path: _Path,
64
70
  string: str | None = None,
65
71
  check_class: bool = False,
66
72
  check_class_constructor: bool = False,
67
73
  check_dunders: bool = False,
74
+ check_protected_class_methods: bool = False,
68
75
  check_overridden: bool = False,
69
76
  check_protected: bool = False,
70
77
  check_property_returns: bool = False,
@@ -91,6 +98,8 @@ def docsig( # pylint: disable=too-many-locals
91
98
  :param check_class_constructor: Check ``__init__`` methods. Note that this
92
99
  is mutually incompatible with check_class.
93
100
  :param check_dunders: Check dunder methods
101
+ :param check_protected_class_methods: Check public methods belonging
102
+ to protected classes.
94
103
  :param check_overridden: Check overridden methods
95
104
  :param check_protected: Check protected functions and classes.
96
105
  :param check_property_returns: Run return checks on properties.
@@ -104,9 +113,23 @@ def docsig( # pylint: disable=too-many-locals
104
113
  :param disable: List of errors to disable.
105
114
  :return: Exit status for whether test failed or not.
106
115
  """
116
+ disabled_args = list(_E.fromcodes(disable or []))
117
+ target_args = list(_E.fromcodes(targets or []))
118
+ for message in disabled_args:
119
+ if not message.isknown:
120
+ raise ValueError(
121
+ f"unknown option to disable '{message.description}'",
122
+ )
123
+
124
+ for message in target_args:
125
+ if not message.isknown:
126
+ raise ValueError(
127
+ f"unknown option to target '{message.description}'",
128
+ )
129
+
107
130
  modules = _Modules(
108
131
  *path,
109
- disable=disable or [],
132
+ disable=disabled_args,
110
133
  string=string,
111
134
  ignore_args=ignore_args,
112
135
  ignore_kwargs=ignore_kwargs,
@@ -115,7 +138,11 @@ def docsig( # pylint: disable=too-many-locals
115
138
  display = _Display(no_ansi)
116
139
  for module in modules:
117
140
  for top_level in module:
118
- if not top_level.isprotected or check_protected:
141
+ if (
142
+ not top_level.isprotected
143
+ or check_protected
144
+ or check_protected_class_methods
145
+ ):
119
146
  failures = _run_check(
120
147
  top_level,
121
148
  check_class,
@@ -126,7 +153,7 @@ def docsig( # pylint: disable=too-many-locals
126
153
  check_property_returns,
127
154
  ignore_no_params,
128
155
  no_ansi,
129
- targets or [],
156
+ target_args,
130
157
  )
131
158
  if failures:
132
159
  display[top_level.path].append(failures)
@@ -11,14 +11,11 @@ from io import StringIO as _StringIO
11
11
 
12
12
  from typing_extensions import Self as _Self
13
13
 
14
- from . import messages as _messages
14
+ from ._message import Message as _Message
15
+ from .messages import E as _E
15
16
 
16
- ERRORS = tuple(
17
- i for i in dir(_messages) if not i.startswith("__") and i.startswith("E1")
18
- )
19
17
 
20
-
21
- class _Rules(_t.List[str]):
18
+ class _Rules(_t.List[_Message]):
22
19
  def __init__(self, kind: str) -> None:
23
20
  super().__init__()
24
21
  self._unknown = []
@@ -26,19 +23,21 @@ class _Rules(_t.List[str]):
26
23
  delimiter = _re.search(r"\W+", kind)
27
24
  if delimiter and delimiter[0] == "=":
28
25
  self._kind, option = kind.split("=")
26
+ message = _E.fromref(option)
29
27
  if "," in option:
30
28
  values = option.split(",")
31
29
  for value in values:
32
- if value in ERRORS:
33
- self.append(value)
30
+ message = _E.fromref(value)
31
+ if message.isknown:
32
+ self.append(message)
34
33
  else:
35
- self._unknown.append(value)
36
- elif option not in ERRORS:
37
- self._unknown.append(option)
34
+ self._unknown.append(message)
35
+ elif message.isknown:
36
+ self.append(message)
38
37
  else:
39
- self.append(option)
38
+ self._unknown.append(message)
40
39
  else:
41
- self.extend(ERRORS)
40
+ self.extend(_E.all(1))
42
41
 
43
42
  @property
44
43
  def kind(self) -> str:
@@ -46,7 +45,7 @@ class _Rules(_t.List[str]):
46
45
  return self._kind
47
46
 
48
47
  @property
49
- def unknown(self) -> list[str]:
48
+ def unknown(self) -> list[_Message]:
50
49
  """List of unknown directive options if any."""
51
50
  return self._unknown
52
51
 
@@ -110,7 +109,9 @@ class Directive:
110
109
  return None
111
110
 
112
111
 
113
- class Directives(_t.Dict[int, _t.Tuple[_t.List[Directive], _t.List[str]]]):
112
+ class Directives(
113
+ _t.Dict[int, _t.Tuple[_t.List[Directive], _t.List[_Message]]]
114
+ ):
114
115
  """Data for directives:
115
116
 
116
117
  Dict like object with the line number of directive as the key and
@@ -120,7 +121,7 @@ class Directives(_t.Dict[int, _t.Tuple[_t.List[Directive], _t.List[str]]]):
120
121
  :param disable: List of checks to disable.
121
122
  """
122
123
 
123
- def __init__(self, text: str, disable: list[str]) -> None:
124
+ def __init__(self, text: str, disable: list[_Message]) -> None:
124
125
  super().__init__()
125
126
  fin = _StringIO(text)
126
127
  module_disables = list(disable)
@@ -13,6 +13,7 @@ import astroid as _ast
13
13
  import sphinx.ext.napoleon as _s
14
14
 
15
15
  from ._directives import Directive as _Directive
16
+ from ._message import Message as _Message
16
17
  from ._utils import isprotected as _isprotected
17
18
 
18
19
  PARAM = "param"
@@ -286,7 +287,7 @@ class Function: # pylint: disable=too-many-arguments
286
287
  self,
287
288
  node: _ast.FunctionDef,
288
289
  directives: _t.List[_Directive],
289
- disabled: list[str],
290
+ disabled: list[_Message],
290
291
  ignore_args: bool = False,
291
292
  ignore_kwargs: bool = False,
292
293
  check_class_constructor: bool = False,
@@ -402,7 +403,7 @@ class Function: # pylint: disable=too-many-arguments
402
403
  return self._docstring
403
404
 
404
405
  @property
405
- def disabled(self) -> list[str]:
406
+ def disabled(self) -> list[_Message]:
406
407
  """List of disabled checks specific to this function."""
407
408
  return self._disabled
408
409
 
@@ -24,6 +24,9 @@ def main() -> int:
24
24
  check_class=parser.args.check_class,
25
25
  check_class_constructor=parser.args.check_class_constructor,
26
26
  check_dunders=parser.args.check_dunders,
27
+ check_protected_class_methods=(
28
+ parser.args.check_protected_class_methods
29
+ ),
27
30
  check_overridden=parser.args.check_overridden,
28
31
  check_protected=parser.args.check_protected,
29
32
  check_property_returns=parser.args.check_property_returns,
@@ -0,0 +1,69 @@
1
+ """
2
+ docsig._message
3
+ ===============
4
+ """
5
+ from __future__ import annotations as _
6
+
7
+ import typing as _t
8
+
9
+ UNKNOWN = "E000"
10
+
11
+
12
+ class Message(_t.NamedTuple):
13
+ """Message type for errors."""
14
+
15
+ code: str
16
+ description: str
17
+ symbolic: str = ""
18
+ hint: _t.Optional[str] = None
19
+
20
+ @property
21
+ def isknown(self) -> bool:
22
+ """Whether this is a known error."""
23
+ return self.code != UNKNOWN
24
+
25
+ def fstring(self, template: str) -> str:
26
+ """Return values as a format string.
27
+
28
+ :param template: String to interpolate values.
29
+ :return: Formatted string.
30
+ """
31
+ return template.format(
32
+ code=self.code,
33
+ description=self.description,
34
+ symbolic=self.symbolic,
35
+ )
36
+
37
+
38
+ class Messages(_t.Dict[int, Message]):
39
+ """Object for storing and retrieving message objects."""
40
+
41
+ def fromref(self, ref: str) -> Message:
42
+ """Get a message by its code or symbolic reference.
43
+
44
+ :param ref: Code or symbolic reference.
45
+ :return: Message if valid ref else an unknown message type.
46
+ """
47
+ for value in self.values():
48
+ if ref in (value.code, value.symbolic):
49
+ return value
50
+
51
+ return Message(UNKNOWN, ref)
52
+
53
+ def fromcodes(self, refs: list[str]) -> tuple[Message, ...]:
54
+ """Get tuple of message types from codes or symbolic references.
55
+
56
+ :param refs: Tuple of codes or symbolic references.
57
+ :return: Tuple of message types.
58
+ """
59
+ return tuple(self.fromref(i) for i in refs)
60
+
61
+ def all(self, category: int) -> tuple[Message, ...]:
62
+ """Get all messages belonging to a category.
63
+
64
+ :param category: Index of message category.
65
+ :return: Tuple of all message objects belonging to category.
66
+ """
67
+ return tuple(
68
+ v for k, v in self.items() if str(k).startswith(str(category))
69
+ )
@@ -11,6 +11,7 @@ import astroid as _ast
11
11
 
12
12
  from ._directives import Directives as _Directives
13
13
  from ._function import Function as _Function
14
+ from ._message import Message as _Message
14
15
  from ._utils import isprotected as _isprotected
15
16
 
16
17
 
@@ -87,7 +88,7 @@ class _Module(_t.List[Parent]):
87
88
  def __init__( # pylint: disable=too-many-arguments
88
89
  self,
89
90
  string: str,
90
- disable: list[str],
91
+ disable: list[_Message],
91
92
  path: _Path | None = None,
92
93
  ignore_args: bool = False,
93
94
  ignore_kwargs: bool = False,
@@ -129,10 +130,10 @@ class Modules(_t.List[_Module]):
129
130
  be on the class level docstring.
130
131
  """
131
132
 
132
- def __init__(
133
+ def __init__( # pylint: disable=too-many-arguments
133
134
  self,
134
135
  *paths: _Path,
135
- disable: list[str],
136
+ disable: list[_Message],
136
137
  string: str | None = None,
137
138
  ignore_args: bool = False,
138
139
  ignore_kwargs: bool = False,
@@ -6,12 +6,13 @@ from __future__ import annotations as _
6
6
 
7
7
  import typing as _t
8
8
 
9
- from . import messages as _messages
10
- from ._directives import ERRORS as _ERRORS
11
9
  from ._function import RETURN as _RETURN
12
10
  from ._function import Function as _Function
13
11
  from ._function import Param as _Param
12
+ from ._message import Message as _Message
14
13
  from ._utils import almost_equal as _almost_equal
14
+ from .messages import TEMPLATE as _TEMPLATE
15
+ from .messages import E as _E
15
16
 
16
17
  _MIN_MATCH = 0.8
17
18
  _MAX_MATCH = 1.0
@@ -20,43 +21,36 @@ _MAX_MATCH = 1.0
20
21
  class _MessageSequence(_t.List[str]):
21
22
  def __init__(
22
23
  self,
23
- targets: list[str] | None = None,
24
- disable: list[str] | None = None,
24
+ targets: list[_Message],
25
+ disable: list[_Message],
25
26
  ) -> None:
26
27
  super().__init__()
27
- self._disable = disable or []
28
- self._disabled = False
28
+ self._disable = list(disable)
29
29
  if targets:
30
- errors = list(_ERRORS)
30
+ errors = list(_E.all(1))
31
31
  for target in targets:
32
32
  errors.remove(target)
33
33
 
34
34
  self._disable.extend(errors)
35
35
 
36
- self._errors: list[str] = []
36
+ self._errors: list[_Message] = []
37
37
 
38
- def add(self, value: str, **kwargs) -> None:
38
+ def add(self, value: _Message, hint: bool = False, **kwargs) -> None:
39
39
  """Add an error to the container.
40
40
 
41
41
  :param value: Value to add.
42
+ :param hint: Whether to print a hint or not.
42
43
  :param kwargs: Variable(s) if format string.
43
44
  """
44
- # if the last code to be disabled was an error then all
45
- # following hints are disabled until a new error is evaluated
46
- if value.startswith("E"):
47
- self._disabled = False
48
- self._errors.append(value)
49
-
50
- if value in self._disable:
51
- self._disabled = True
52
-
53
- message = getattr(_messages, value)
45
+ self._errors.append(value)
46
+ message = value.fstring(_TEMPLATE)
54
47
  if kwargs:
55
48
  message = message.format(**kwargs)
56
49
 
57
- if not self._disabled and not (
58
- value.startswith("E") and message in self
59
- ):
50
+ if hint:
51
+ message += f"\nhint: {value.hint}"
52
+
53
+ if value not in self._disable and message not in self:
60
54
  super().append(message)
61
55
 
62
56
 
@@ -72,8 +66,8 @@ class Report(_MessageSequence):
72
66
  def __init__(
73
67
  self,
74
68
  func: _Function,
75
- targets: list[str],
76
- disable: list[str],
69
+ targets: list[_Message],
70
+ disable: list[_Message],
77
71
  check_property_returns: bool,
78
72
  ) -> None:
79
73
  super().__init__(targets, disable)
@@ -90,32 +84,32 @@ class Report(_MessageSequence):
90
84
  if any(sig.name == i.name for i in self._func.docstring.args) or any(
91
85
  doc.name == i.name for i in self._func.signature.args
92
86
  ):
93
- self.add("E101")
87
+ self.add(_E[101])
94
88
 
95
89
  def exists(self) -> None:
96
90
  """Test that non-existing parameter is not documented."""
97
91
  if len(self._func.docstring.args) > len(self._func.signature.args):
98
- self.add("E102")
92
+ self.add(_E[102])
99
93
 
100
94
  def missing_func_docstring(self) -> None:
101
95
  """Test that docstring is not missing from func."""
102
96
  if not self._func.isinit and self._func.docstring.string is None:
103
- self.add("E113")
97
+ self.add(_E[113])
104
98
 
105
99
  def missing_class_docstring(self) -> None:
106
100
  """Test that docstring is not missing from class."""
107
101
  if self._func.isinit and self._func.docstring.string is None:
108
- self.add("E114")
102
+ self.add(_E[114])
109
103
 
110
104
  def missing(self) -> None:
111
105
  """Test that parameter is not missing from documentation."""
112
106
  if len(self._func.signature.args) > len(self._func.docstring.args):
113
- self.add("E103")
107
+ self.add(_E[103])
114
108
 
115
109
  def duplicates(self) -> None:
116
110
  """Test that there are no duplicate parameters in docstring."""
117
111
  if self._func.docstring.args.duplicated:
118
- self.add("E106")
112
+ self.add(_E[106])
119
113
 
120
114
  def extra_return(self) -> None:
121
115
  """Check that return is not documented when there is none."""
@@ -124,30 +118,31 @@ class Report(_MessageSequence):
124
118
  and self._func.signature.rettype == "None"
125
119
  and not self._no_returns
126
120
  ):
127
- self.add("E104")
121
+ self.add(_E[104])
128
122
 
129
123
  def property_return(self) -> None:
130
124
  """Check that return is not documented for property."""
131
125
  if self._func.docstring.returns and self._no_prop_return:
132
- self.add("E108")
133
- self.add("H101")
126
+ self.add(_E[108], hint=True)
134
127
 
135
128
  def return_not_typed(self) -> None:
136
129
  """Check that return is not documented when no type provided."""
137
130
  if self._func.signature.rettype is None and not self._no_returns:
138
- self.add("E109")
131
+ self.add(_E[109])
139
132
 
140
133
  def missing_return(self) -> None:
141
134
  """Check that return is documented when func returns value."""
135
+ hint = False
142
136
  if (
143
137
  self._func.signature.returns
144
138
  and not self._func.docstring.returns
145
139
  and not self._no_returns
146
140
  ):
147
- self.add("E105")
148
141
  docstring = self._func.docstring.string
149
142
  if docstring is not None and _RETURN in docstring:
150
- self.add("H102")
143
+ hint = True
144
+
145
+ self.add(_E[105], hint=hint)
151
146
 
152
147
  def incorrect(self, sig: _Param, doc: _Param) -> None:
153
148
  """Test that proper syntax is used when documenting parameters.
@@ -156,7 +151,7 @@ class Report(_MessageSequence):
156
151
  :param doc: Docstring argument.
157
152
  """
158
153
  if sig.name is None and doc.name is None:
159
- self.add("E107")
154
+ self.add(_E[107])
160
155
 
161
156
  def not_equal(self, sig: _Param, doc: _Param) -> None:
162
157
  """Final catch-all.
@@ -168,13 +163,12 @@ class Report(_MessageSequence):
168
163
  :param doc: Docstring argument.
169
164
  """
170
165
  if sig.name is not None and doc.name is not None and not self._errors:
171
- self.add("E110")
166
+ self.add(_E[110])
172
167
 
173
168
  def class_return(self) -> None:
174
169
  """Check that return is not documented for __init__."""
175
170
  if self._func.docstring.returns and self._func.isinit:
176
- self.add("E111")
177
- self.add("H103")
171
+ self.add(_E[111], hint=True)
178
172
 
179
173
  def misspelled(self, sig: _Param, doc: _Param) -> None:
180
174
  """Test whether there is a spelling error in documentation.
@@ -192,7 +186,7 @@ class Report(_MessageSequence):
192
186
  and not self._errors
193
187
  and _almost_equal(sig.name, doc.name, _MIN_MATCH, _MAX_MATCH)
194
188
  ):
195
- self.add("E112")
189
+ self.add(_E[112])
196
190
 
197
191
  def description_syntax(self, doc: _Param) -> None:
198
192
  """Test whether docstring description has correct spacing.
@@ -200,7 +194,7 @@ class Report(_MessageSequence):
200
194
  :param doc: Docstring argument.
201
195
  """
202
196
  if doc.description is not None and not doc.description.startswith(" "):
203
- self.add("E115")
197
+ self.add(_E[115])
204
198
 
205
199
  def indent_syntax(self, doc: _Param) -> None:
206
200
  """Test whether docstring description is indented correctly.
@@ -208,22 +202,24 @@ class Report(_MessageSequence):
208
202
  :param doc: Docstring argument.
209
203
  """
210
204
  if doc.indent > 0:
211
- self.add("E116")
205
+ self.add(_E[116])
212
206
 
213
207
  def invalid_directive(self) -> None:
214
208
  """Report on any invalid directives belonging to this func."""
215
209
  for directive in self._func.directives:
216
210
  if not directive.isvalid:
217
- err = f"E20{1 if directive.ismodule else 2}"
211
+ err = _E[int(f"20{1 if directive.ismodule else 2}")]
218
212
  self.add(err, directive=directive.kind)
219
213
 
220
214
  def invalid_directive_options(self) -> None:
221
215
  """Report on any invalid directive options belonging to this."""
222
216
  for directive in self._func.directives:
223
217
  if directive.rules.unknown:
224
- err = f"E20{3 if directive.ismodule else 4}"
218
+ err = _E[int(f"20{3 if directive.ismodule else 4}")]
225
219
  for rule in directive.rules.unknown:
226
- self.add(err, directive=directive.kind, option=rule)
220
+ self.add(
221
+ err, directive=directive.kind, option=rule.description
222
+ )
227
223
 
228
224
  def get_report(self, prefix: str = "") -> str:
229
225
  """Get report compiled as a string.
@@ -231,13 +227,14 @@ class Report(_MessageSequence):
231
227
  :param prefix: Prefix report.
232
228
  :return: Current report.
233
229
  """
234
- return f"\n{prefix}".join(self) + "\n"
230
+ report = f"\n{prefix}".join(self)
231
+ return f"{report}\n"
235
232
 
236
233
 
237
234
  def generate_report(
238
235
  func: _Function,
239
- targets: list[str],
240
- disable: list[str],
236
+ targets: list[_Message],
237
+ disable: list[_Message],
241
238
  check_property_returns: bool,
242
239
  ) -> Report:
243
240
  """Generate report if function or method has failed.
@@ -7,4 +7,4 @@ Contains the version of this package.
7
7
  Allows for access to the version internally without cyclic imports
8
8
  caused by accessing it through __init__.
9
9
  """
10
- __version__ = "0.40.0"
10
+ __version__ = "0.42.0"
@@ -0,0 +1,140 @@
1
+ """
2
+ docsig.messages
3
+ ===============
4
+ | E101: parameters out of order
5
+ | E102: includes parameters that do not exist
6
+ | E103: parameters missing
7
+ | E104: return statement documented for None
8
+ | E105: return missing from docstring
9
+ | E106: duplicate parameters found
10
+ | E107: parameter appears to be incorrectly documented
11
+ | E108: return statement documented for property
12
+ | E109: cannot determine whether a return statement should exist or not
13
+ | E110: documented parameter not equal to its respective argument
14
+ | E111: return statement documented for class
15
+ | E112: spelling error found in documented parameter
16
+ | E113: function is missing a docstring
17
+ | E114: class is missing a docstring
18
+ | E115: syntax error in description
19
+ | E116: param not indented correctly
20
+ | E201: unknown module comment directive '{directive}'
21
+ | E202: unknown inline comment directive '{directive}'
22
+ | E203: unknown module comment option for {directive} '{option}'
23
+ | E204: unknown inline comment option for {directive} '{option}'
24
+ """
25
+ from ._message import Message as _Message
26
+ from ._message import Messages as _Messages
27
+
28
+ TEMPLATE = "{code}: {description} ({symbolic})"
29
+
30
+
31
+ # Exxx: Error
32
+ E = _Messages(
33
+ {
34
+ # E1xx: Docstring
35
+ 101: _Message(
36
+ "E101",
37
+ "parameters out of order",
38
+ "params-out-of-order",
39
+ ),
40
+ 102: _Message(
41
+ "E102",
42
+ "includes parameters that do not exist",
43
+ "params-do-not-exist",
44
+ ),
45
+ 103: _Message(
46
+ "E103",
47
+ "parameters missing",
48
+ "params-missing",
49
+ ),
50
+ 104: _Message(
51
+ "E104",
52
+ "return statement documented for None",
53
+ "return-documented-for-none",
54
+ ),
55
+ 105: _Message(
56
+ "E105",
57
+ "return missing from docstring",
58
+ "return-missing",
59
+ "it is possible a syntax error could be causing this",
60
+ ),
61
+ 106: _Message(
62
+ "E106",
63
+ "duplicate parameters found",
64
+ "duplicate-params-found",
65
+ ),
66
+ 107: _Message(
67
+ "E107",
68
+ "parameter appears to be incorrectly documented",
69
+ "param-incorrectly-documented",
70
+ ),
71
+ 108: _Message(
72
+ "E108",
73
+ "return statement documented for property",
74
+ "return-documented-for-property",
75
+ "documentation is sufficient as a getter is the value returned",
76
+ ),
77
+ 109: _Message(
78
+ "E109",
79
+ "cannot determine whether a return statement should exist or not",
80
+ "confirm-return-needed",
81
+ ),
82
+ 110: _Message(
83
+ "E110",
84
+ "documented parameter not equal to its respective argument",
85
+ "param-not-equal-to-arg",
86
+ ),
87
+ 111: _Message(
88
+ "E111",
89
+ "return statement documented for class",
90
+ "class-return-documented",
91
+ "a class does not return a value during instantiation",
92
+ ),
93
+ 112: _Message(
94
+ "E112",
95
+ "spelling error found in documented parameter",
96
+ "spelling-error",
97
+ ),
98
+ 113: _Message(
99
+ "E113",
100
+ "function is missing a docstring",
101
+ "function-doc-missing",
102
+ ),
103
+ 114: _Message(
104
+ "E114",
105
+ "class is missing a docstring",
106
+ "class-doc-missing",
107
+ ),
108
+ 115: _Message(
109
+ "E115",
110
+ "syntax error in description",
111
+ "syntax-error-in-description",
112
+ ),
113
+ 116: _Message(
114
+ "E116",
115
+ "param not indented correctly",
116
+ "incorrect-indent",
117
+ ),
118
+ # E2xx: Config
119
+ 201: _Message(
120
+ "E201",
121
+ "unknown module comment directive '{directive}'",
122
+ "unknown-module-directive",
123
+ ),
124
+ 202: _Message(
125
+ "E202",
126
+ "unknown inline comment directive '{directive}'",
127
+ "unknown-inline-directive",
128
+ ),
129
+ 203: _Message(
130
+ "E203",
131
+ "unknown module comment option for {directive} '{option}'",
132
+ "unknown-module-directive-option",
133
+ ),
134
+ 204: _Message(
135
+ "E204",
136
+ "unknown inline comment option for {directive} '{option}'",
137
+ "unknown-module-directive-option",
138
+ ),
139
+ }
140
+ )
@@ -15,7 +15,6 @@ exclude = '''
15
15
  )/
16
16
  '''
17
17
  line-length = 79
18
- skip-magic-trailing-comma = true
19
18
 
20
19
  [tool.constcheck]
21
20
  ignore_strings = [
@@ -38,6 +37,7 @@ omit = [
38
37
 
39
38
  [tool.docsig]
40
39
  check-class = true
40
+ check-protected-class-methods = true
41
41
  summary = true
42
42
 
43
43
  [tool.isort]
@@ -70,13 +70,13 @@ maintainers = [
70
70
  name = "docsig"
71
71
  readme = "README.rst"
72
72
  repository = "https://github.com/jshwi/docsig"
73
- version = "0.40.0"
73
+ version = "0.42.0"
74
74
 
75
75
  [tool.poetry.dependencies]
76
76
  Pygments = "^2.13.0"
77
77
  Sphinx = ">=4.3.2,<7.0.0"
78
- arcon = "^0"
79
- astroid = "^2.11.6"
78
+ arcon = "^0.3.1"
79
+ astroid = "^3.0.1"
80
80
  object-colors = "^2.1.0"
81
81
  python = "^3.8"
82
82
  typing-extensions = "^4.8.0"
@@ -87,7 +87,6 @@ deptry = "^0.12.0"
87
87
  ipython = "^8.12.0"
88
88
  pre-commit = "^3.3.3"
89
89
  pyaud = "^7.2.0"
90
- pylint = "2.15.10"
91
90
  pytest = "^7.4.0"
92
91
  pytest-randomly = "^3.13.0"
93
92
  pytest-sugar = "^0.9.6"
@@ -118,10 +117,10 @@ audit = [
118
117
  "unused"
119
118
  ]
120
119
  exclude = '''
121
- (?x)^(
122
- | docs\/conf\.py
123
- | whitelist\.py
124
- )$
120
+ (?x)^(
121
+ | docs\/conf\.py
122
+ | whitelist\.py
123
+ )$
125
124
  '''
126
125
 
127
126
  [tool.pytest.ini_options]
@@ -1,54 +0,0 @@
1
- """
2
- docsig.messages
3
- ===============
4
- | E101: parameters out of order
5
- | E102: includes parameters that do not exist
6
- | E103: parameters missing
7
- | E104: return statement documented for None
8
- | E105: return missing from docstring
9
- | E106: duplicate parameters found
10
- | E107: parameter appears to be incorrectly documented
11
- | E108: return statement documented for property
12
- | E109: cannot determine whether a return statement should exist or not
13
- | E110: documented parameter not equal to its respective argument
14
- | E111: return statement documented for class
15
- | E112: spelling error found in documented parameter
16
- | E113: function is missing a docstring
17
- | E114: class is missing a docstring
18
- | E115: syntax error in description
19
- | E116: param not indented correctly
20
- | E201: unknown module comment directive '{directive}'
21
- | E202: unknown inline comment directive '{directive}'
22
- | E203: unknown module comment option for {directive} '{option}'
23
- | E204: unknown inline comment option for {directive} '{option}'
24
- """
25
- # Exxx: Error
26
- # E1xx: Docstring
27
- E101 = "E101: parameters out of order"
28
- E102 = "E102: includes parameters that do not exist"
29
- E103 = "E103: parameters missing"
30
- E104 = "E104: return statement documented for None"
31
- E105 = "E105: return missing from docstring"
32
- E106 = "E106: duplicate parameters found"
33
- E107 = "E107: parameter appears to be incorrectly documented"
34
- E108 = "E108: return statement documented for property"
35
- E109 = "E109: cannot determine whether a return statement should exist or not"
36
- E110 = "E110: documented parameter not equal to its respective argument"
37
- E111 = "E111: return statement documented for class"
38
- E112 = "E112: spelling error found in documented parameter"
39
- E113 = "E113: function is missing a docstring"
40
- E114 = "E114: class is missing a docstring"
41
- E115 = "E115: syntax error in description"
42
- E116 = "E116: param not indented correctly"
43
-
44
- # E2xx: Config
45
- E201 = "E201: unknown module comment directive '{directive}'"
46
- E202 = "E202: unknown inline comment directive '{directive}'"
47
- E203 = "E203: unknown module comment option for {directive} '{option}'"
48
- E204 = "E204: unknown inline comment option for {directive} '{option}'"
49
-
50
- # Hxxx: Hint
51
- # H1xx: Docstring
52
- H101 = "hint: documentation is sufficient as a getter is the value returned"
53
- H102 = "hint: it is possible a syntax error could be causing this"
54
- H103 = "hint: a class does not return a value during instantiation"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes