docstring-format-checker 0.9.0__tar.gz → 0.11.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.
- {docstring_format_checker-0.9.0 → docstring_format_checker-0.11.0}/PKG-INFO +1 -1
- {docstring_format_checker-0.9.0 → docstring_format_checker-0.11.0}/pyproject.toml +14 -58
- {docstring_format_checker-0.9.0 → docstring_format_checker-0.11.0}/src/docstring_format_checker/__init__.py +1 -1
- {docstring_format_checker-0.9.0 → docstring_format_checker-0.11.0}/src/docstring_format_checker/cli.py +15 -0
- {docstring_format_checker-0.9.0 → docstring_format_checker-0.11.0}/src/docstring_format_checker/config.py +38 -10
- {docstring_format_checker-0.9.0 → docstring_format_checker-0.11.0}/src/docstring_format_checker/core.py +38 -10
- {docstring_format_checker-0.9.0 → docstring_format_checker-0.11.0}/src/docstring_format_checker/utils/exceptions.py +31 -1
- {docstring_format_checker-0.9.0 → docstring_format_checker-0.11.0}/README.md +0 -0
- {docstring_format_checker-0.9.0 → docstring_format_checker-0.11.0}/src/docstring_format_checker/utils/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docstring-format-checker
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: A CLI tool to check and validate Python docstring formatting and completeness
|
|
5
5
|
Author: Chris Mahoney
|
|
6
6
|
Author-email: Chris Mahoney <docstring-format-checker@data-science-extensions.com>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "docstring-format-checker"
|
|
3
|
-
version = "v0.
|
|
3
|
+
version = "v0.11.0"
|
|
4
4
|
description = "A CLI tool to check and validate Python docstring formatting and completeness"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -154,63 +154,19 @@ files = [
|
|
|
154
154
|
]
|
|
155
155
|
|
|
156
156
|
[tool.dfc]
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
name = "summary"
|
|
162
|
-
type = "free_text"
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
required =
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
order =
|
|
169
|
-
|
|
170
|
-
type = "free_text"
|
|
171
|
-
admonition = "info"
|
|
172
|
-
prefix = "???+"
|
|
173
|
-
required = false
|
|
174
|
-
|
|
175
|
-
[[tool.dfc.sections]]
|
|
176
|
-
order = 3
|
|
177
|
-
name = "params"
|
|
178
|
-
type = "list_name_and_type"
|
|
179
|
-
required = true
|
|
180
|
-
|
|
181
|
-
[[tool.dfc.sections]]
|
|
182
|
-
order = 4
|
|
183
|
-
name = "returns"
|
|
184
|
-
type = "list_name_and_type"
|
|
185
|
-
required = false
|
|
186
|
-
|
|
187
|
-
[[tool.dfc.sections]]
|
|
188
|
-
order = 5
|
|
189
|
-
name = "yields"
|
|
190
|
-
type = "list_type"
|
|
191
|
-
required = false
|
|
192
|
-
|
|
193
|
-
[[tool.dfc.sections]]
|
|
194
|
-
order = 6
|
|
195
|
-
name = "raises"
|
|
196
|
-
type = "list_type"
|
|
197
|
-
required = false
|
|
198
|
-
|
|
199
|
-
[[tool.dfc.sections]]
|
|
200
|
-
order = 7
|
|
201
|
-
name = "examples"
|
|
202
|
-
type = "free_text"
|
|
203
|
-
admonition = "example"
|
|
204
|
-
prefix = "???+"
|
|
205
|
-
required = false
|
|
206
|
-
|
|
207
|
-
[[tool.dfc.sections]]
|
|
208
|
-
order = 8
|
|
209
|
-
name = "notes"
|
|
210
|
-
type = "free_text"
|
|
211
|
-
admonition = "note"
|
|
212
|
-
prefix = "???"
|
|
213
|
-
required = false
|
|
157
|
+
allow_undefined_sections = false
|
|
158
|
+
require_docstrings = true
|
|
159
|
+
check_private = true
|
|
160
|
+
sections = [
|
|
161
|
+
{ order = 1, name = "summary", type = "free_text", required = true, admonition = "note", prefix = "!!!" },
|
|
162
|
+
{ order = 2, name = "details", type = "free_text", required = false, admonition = "abstract", prefix = "???+" },
|
|
163
|
+
{ order = 3, name = "params", type = "list_name_and_type", required = false },
|
|
164
|
+
{ order = 4, name = "raises", type = "list_type", required = false },
|
|
165
|
+
{ order = 5, name = "returns", type = "list_name_and_type", required = false },
|
|
166
|
+
{ order = 6, name = "yields", type = "list_type", required = false },
|
|
167
|
+
{ order = 7, name = "examples", type = "free_text", required = false, admonition = "example", prefix = "???+" },
|
|
168
|
+
{ order = 8, name = "notes", type = "free_text", required = false, admonition = "note", prefix = "???" },
|
|
169
|
+
]
|
|
214
170
|
|
|
215
171
|
[build-system]
|
|
216
172
|
requires = ["uv_build>=0.7.19,<0.8.0"]
|
|
@@ -4,7 +4,7 @@ Docstring Format Checker.
|
|
|
4
4
|
A CLI tool to check and validate Python docstring formatting and completeness.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
__version__ = "v0.
|
|
7
|
+
__version__ = "v0.11.0"
|
|
8
8
|
__author__ = "Chris Mahoney"
|
|
9
9
|
__email__ = "docstring-format-checker@data-science-extensions.com"
|
|
10
10
|
|
|
@@ -72,6 +72,7 @@ from docstring_format_checker.core import DocstringChecker, DocstringError
|
|
|
72
72
|
__all__: list[str] = [
|
|
73
73
|
"main",
|
|
74
74
|
"entry_point",
|
|
75
|
+
"check_docstrings",
|
|
75
76
|
]
|
|
76
77
|
|
|
77
78
|
|
|
@@ -90,6 +91,20 @@ NEW_LINE = "\n"
|
|
|
90
91
|
|
|
91
92
|
### Colours ----
|
|
92
93
|
def _colour(text: str, colour: str) -> str:
|
|
94
|
+
"""
|
|
95
|
+
!!! note "Summary"
|
|
96
|
+
Apply Rich colour markup to text.
|
|
97
|
+
|
|
98
|
+
Params:
|
|
99
|
+
text (str):
|
|
100
|
+
The text to colour.
|
|
101
|
+
colour (str):
|
|
102
|
+
The colour to apply, e.g., 'red', 'green', 'blue'.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
(str):
|
|
106
|
+
The text wrapped in Rich colour markup.
|
|
107
|
+
"""
|
|
93
108
|
return f"[{colour}]{text}[/{colour}]"
|
|
94
109
|
|
|
95
110
|
|
|
@@ -107,7 +107,8 @@ VALID_TYPES: tuple[str, ...] = (
|
|
|
107
107
|
@dataclass
|
|
108
108
|
class GlobalConfig:
|
|
109
109
|
"""
|
|
110
|
-
|
|
110
|
+
!!! note "Summary"
|
|
111
|
+
Global configuration for docstring checking behavior.
|
|
111
112
|
"""
|
|
112
113
|
|
|
113
114
|
allow_undefined_sections: bool = False
|
|
@@ -123,7 +124,8 @@ class GlobalConfig:
|
|
|
123
124
|
@dataclass
|
|
124
125
|
class SectionConfig:
|
|
125
126
|
"""
|
|
126
|
-
|
|
127
|
+
!!! note "Summary"
|
|
128
|
+
Configuration for a docstring section.
|
|
127
129
|
"""
|
|
128
130
|
|
|
129
131
|
order: int
|
|
@@ -135,17 +137,26 @@ class SectionConfig:
|
|
|
135
137
|
message: str = "" # Optional message for validation errors
|
|
136
138
|
|
|
137
139
|
def __post_init__(self) -> None:
|
|
138
|
-
"""
|
|
140
|
+
"""
|
|
141
|
+
!!! note "Summary"
|
|
142
|
+
Validate configuration after initialization.
|
|
143
|
+
"""
|
|
139
144
|
self._validate_types()
|
|
140
145
|
self._validate_admonition_prefix_combination()
|
|
141
146
|
|
|
142
147
|
def _validate_types(self) -> None:
|
|
143
|
-
"""
|
|
148
|
+
"""
|
|
149
|
+
!!! note "Summary"
|
|
150
|
+
Validate the 'type' field.
|
|
151
|
+
"""
|
|
144
152
|
if self.type not in VALID_TYPES:
|
|
145
153
|
raise InvalidTypeValuesError(f"Invalid section type: {self.type}. Valid types: {VALID_TYPES}")
|
|
146
154
|
|
|
147
155
|
def _validate_admonition_prefix_combination(self) -> None:
|
|
148
|
-
"""
|
|
156
|
+
"""
|
|
157
|
+
!!! note "Summary"
|
|
158
|
+
Validate admonition and prefix combination rules.
|
|
159
|
+
"""
|
|
149
160
|
|
|
150
161
|
if isinstance(self.admonition, bool):
|
|
151
162
|
# Rule: admonition cannot be True (only False or string)
|
|
@@ -173,6 +184,22 @@ class SectionConfig:
|
|
|
173
184
|
|
|
174
185
|
|
|
175
186
|
def _validate_config_order(config_sections: list[SectionConfig]) -> None:
|
|
187
|
+
"""
|
|
188
|
+
!!! note "Summary"
|
|
189
|
+
Validate that section order values are unique.
|
|
190
|
+
|
|
191
|
+
Params:
|
|
192
|
+
config_sections (list[SectionConfig]):
|
|
193
|
+
List of section configurations to validate.
|
|
194
|
+
|
|
195
|
+
Raises:
|
|
196
|
+
(InvalidConfigError_DuplicateOrderValues):
|
|
197
|
+
If duplicate order values are found.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
(None):
|
|
201
|
+
Nothing is returned.
|
|
202
|
+
"""
|
|
176
203
|
|
|
177
204
|
# Validate no duplicate order values
|
|
178
205
|
order_values: list[int] = [section.order for section in config_sections]
|
|
@@ -202,7 +229,8 @@ def _validate_config_order(config_sections: list[SectionConfig]) -> None:
|
|
|
202
229
|
@dataclass
|
|
203
230
|
class Config:
|
|
204
231
|
"""
|
|
205
|
-
|
|
232
|
+
!!! note "Summary"
|
|
233
|
+
Complete configuration containing global settings and section definitions.
|
|
206
234
|
"""
|
|
207
235
|
|
|
208
236
|
global_config: GlobalConfig
|
|
@@ -293,15 +321,15 @@ def load_config(config_path: Optional[Union[str, Path]] = None) -> Config:
|
|
|
293
321
|
If `None`, looks for `pyproject.toml` in current directory.
|
|
294
322
|
Default: `None`.
|
|
295
323
|
|
|
296
|
-
Returns:
|
|
297
|
-
(Config):
|
|
298
|
-
Configuration object containing global settings and section definitions.
|
|
299
|
-
|
|
300
324
|
Raises:
|
|
301
325
|
(FileNotFoundError):
|
|
302
326
|
If the specified config file doesn't exist.
|
|
303
327
|
(InvalidConfigError):
|
|
304
328
|
If the configuration is invalid.
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
(Config):
|
|
332
|
+
Configuration object containing global settings and section definitions.
|
|
305
333
|
"""
|
|
306
334
|
|
|
307
335
|
if config_path is None:
|
|
@@ -80,7 +80,8 @@ __all__: list[str] = [
|
|
|
80
80
|
|
|
81
81
|
class FunctionAndClassDetails(NamedTuple):
|
|
82
82
|
"""
|
|
83
|
-
|
|
83
|
+
!!! note "Summary"
|
|
84
|
+
Details about a function or class found in the AST.
|
|
84
85
|
"""
|
|
85
86
|
|
|
86
87
|
item_type: Literal["function", "class", "method"]
|
|
@@ -92,7 +93,8 @@ class FunctionAndClassDetails(NamedTuple):
|
|
|
92
93
|
|
|
93
94
|
class DocstringChecker:
|
|
94
95
|
"""
|
|
95
|
-
|
|
96
|
+
!!! note "Summary"
|
|
97
|
+
Main class for checking docstring format and completeness.
|
|
96
98
|
"""
|
|
97
99
|
|
|
98
100
|
def __init__(self, config: Config) -> None:
|
|
@@ -118,10 +120,6 @@ class DocstringChecker:
|
|
|
118
120
|
file_path (Union[str, Path]):
|
|
119
121
|
Path to the Python file to check.
|
|
120
122
|
|
|
121
|
-
Returns:
|
|
122
|
-
(list[DocstringError]):
|
|
123
|
-
List of DocstringError objects for any validation failures.
|
|
124
|
-
|
|
125
123
|
Raises:
|
|
126
124
|
(FileNotFoundError):
|
|
127
125
|
If the file doesn't exist.
|
|
@@ -131,6 +129,10 @@ class DocstringChecker:
|
|
|
131
129
|
If the file can't be decoded.
|
|
132
130
|
(SyntaxError):
|
|
133
131
|
If the file contains invalid Python syntax.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
(list[DocstringError]):
|
|
135
|
+
List of DocstringError objects for any validation failures.
|
|
134
136
|
"""
|
|
135
137
|
|
|
136
138
|
file_path = Path(file_path)
|
|
@@ -274,12 +276,24 @@ class DocstringChecker:
|
|
|
274
276
|
items: list[FunctionAndClassDetails] = []
|
|
275
277
|
|
|
276
278
|
class ItemVisitor(ast.NodeVisitor):
|
|
279
|
+
"""
|
|
280
|
+
!!! note "Summary"
|
|
281
|
+
AST visitor to extract function and class definitions
|
|
282
|
+
"""
|
|
277
283
|
|
|
278
284
|
def __init__(self, checker: DocstringChecker) -> None:
|
|
285
|
+
"""
|
|
286
|
+
!!! note "Summary"
|
|
287
|
+
Initialize the AST visitor.
|
|
288
|
+
"""
|
|
279
289
|
self.class_stack: list[str] = []
|
|
280
290
|
self.checker: DocstringChecker = checker
|
|
281
291
|
|
|
282
292
|
def visit_ClassDef(self, node: ast.ClassDef) -> None:
|
|
293
|
+
"""
|
|
294
|
+
!!! note "Summary"
|
|
295
|
+
Visit class definition node.
|
|
296
|
+
"""
|
|
283
297
|
# Skip private classes unless check_private is enabled
|
|
284
298
|
should_check: bool = self.checker.config.global_config.check_private or not node.name.startswith("_")
|
|
285
299
|
if should_check:
|
|
@@ -299,13 +313,24 @@ class DocstringChecker:
|
|
|
299
313
|
self.class_stack.pop()
|
|
300
314
|
|
|
301
315
|
def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
|
|
316
|
+
"""
|
|
317
|
+
!!! note "Summary"
|
|
318
|
+
Visit function definition node.
|
|
319
|
+
"""
|
|
302
320
|
self._visit_function(node)
|
|
303
321
|
|
|
304
322
|
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None:
|
|
323
|
+
"""
|
|
324
|
+
!!! note "Summary"
|
|
325
|
+
Visit async function definition node.
|
|
326
|
+
"""
|
|
305
327
|
self._visit_function(node)
|
|
306
328
|
|
|
307
329
|
def _visit_function(self, node: Union[ast.FunctionDef, ast.AsyncFunctionDef]) -> None:
|
|
308
|
-
"""
|
|
330
|
+
"""
|
|
331
|
+
!!! note "Summary"
|
|
332
|
+
Visit function definition node (sync or async).
|
|
333
|
+
"""
|
|
309
334
|
|
|
310
335
|
# Skip private functions unless check_private is enabled
|
|
311
336
|
should_check: bool = self.checker.config.global_config.check_private or not node.name.startswith("_")
|
|
@@ -835,7 +860,8 @@ class DocstringChecker:
|
|
|
835
860
|
|
|
836
861
|
def _check_colon_usage(self, docstring: str) -> list[str]:
|
|
837
862
|
"""
|
|
838
|
-
|
|
863
|
+
!!! note "Summary"
|
|
864
|
+
Check that colons are used correctly for admonition vs non-admonition sections.
|
|
839
865
|
"""
|
|
840
866
|
|
|
841
867
|
errors: list[str] = []
|
|
@@ -882,7 +908,8 @@ class DocstringChecker:
|
|
|
882
908
|
|
|
883
909
|
def _check_title_case_sections(self, docstring: str) -> list[str]:
|
|
884
910
|
"""
|
|
885
|
-
|
|
911
|
+
!!! note "Summary"
|
|
912
|
+
Check that non-admonition sections are single word, title case, and match config name.
|
|
886
913
|
"""
|
|
887
914
|
|
|
888
915
|
errors: list[str] = []
|
|
@@ -914,7 +941,8 @@ class DocstringChecker:
|
|
|
914
941
|
|
|
915
942
|
def _check_parentheses_validation(self, docstring: str) -> list[str]:
|
|
916
943
|
"""
|
|
917
|
-
|
|
944
|
+
!!! note "Summary"
|
|
945
|
+
Check that list_type and list_name_and_type sections have proper parentheses.
|
|
918
946
|
"""
|
|
919
947
|
|
|
920
948
|
errors: list[str] = []
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
class DocstringError(Exception):
|
|
2
2
|
"""
|
|
3
|
-
|
|
3
|
+
!!! note "Summary"
|
|
4
|
+
Exception raised when a docstring validation error occurs.
|
|
4
5
|
"""
|
|
5
6
|
|
|
6
7
|
def __init__(
|
|
@@ -11,6 +12,10 @@ class DocstringError(Exception):
|
|
|
11
12
|
item_name: str,
|
|
12
13
|
item_type: str,
|
|
13
14
|
) -> None:
|
|
15
|
+
"""
|
|
16
|
+
!!! note "Summary"
|
|
17
|
+
Initialize a DocstringError.
|
|
18
|
+
"""
|
|
14
19
|
self.message = message
|
|
15
20
|
self.file_path = file_path
|
|
16
21
|
self.line_number = line_number
|
|
@@ -20,20 +25,45 @@ class DocstringError(Exception):
|
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
class InvalidConfigError(Exception):
|
|
28
|
+
"""
|
|
29
|
+
!!! note "Summary"
|
|
30
|
+
Exception raised for invalid configuration errors.
|
|
31
|
+
"""
|
|
32
|
+
|
|
23
33
|
pass
|
|
24
34
|
|
|
25
35
|
|
|
26
36
|
class InvalidConfigError_DuplicateOrderValues(Exception):
|
|
37
|
+
"""
|
|
38
|
+
!!! note "Summary"
|
|
39
|
+
Exception raised for duplicate order values in configuration.
|
|
40
|
+
"""
|
|
41
|
+
|
|
27
42
|
pass
|
|
28
43
|
|
|
29
44
|
|
|
30
45
|
class InvalidTypeValuesError(Exception):
|
|
46
|
+
"""
|
|
47
|
+
!!! note "Summary"
|
|
48
|
+
Exception raised for invalid type values in configuration.
|
|
49
|
+
"""
|
|
50
|
+
|
|
31
51
|
pass
|
|
32
52
|
|
|
33
53
|
|
|
34
54
|
class InvalidFileError(OSError):
|
|
55
|
+
"""
|
|
56
|
+
!!! note "Summary"
|
|
57
|
+
Exception raised for invalid file errors.
|
|
58
|
+
"""
|
|
59
|
+
|
|
35
60
|
pass
|
|
36
61
|
|
|
37
62
|
|
|
38
63
|
class DirectoryNotFoundError(OSError):
|
|
64
|
+
"""
|
|
65
|
+
!!! note "Summary"
|
|
66
|
+
Exception raised for directory not found errors.
|
|
67
|
+
"""
|
|
68
|
+
|
|
39
69
|
pass
|
|
File without changes
|
|
File without changes
|