docstring-format-checker 0.1.0__py3-none-any.whl
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/__init__.py +22 -0
- docstring_format_checker/cli.py +716 -0
- docstring_format_checker/config.py +334 -0
- docstring_format_checker/core.py +671 -0
- docstring_format_checker/utils/__init__.py +0 -0
- docstring_format_checker/utils/exceptions.py +39 -0
- docstring_format_checker-0.1.0.dist-info/METADATA +467 -0
- docstring_format_checker-0.1.0.dist-info/RECORD +10 -0
- docstring_format_checker-0.1.0.dist-info/WHEEL +4 -0
- docstring_format_checker-0.1.0.dist-info/entry_points.txt +4 -0
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
# ============================================================================ #
|
|
2
|
+
# #
|
|
3
|
+
# Title: Title #
|
|
4
|
+
# Purpose: Purpose #
|
|
5
|
+
# Notes: Notes #
|
|
6
|
+
# Author: chrimaho #
|
|
7
|
+
# Created: Created #
|
|
8
|
+
# References: References #
|
|
9
|
+
# Sources: Sources #
|
|
10
|
+
# Edited: Edited #
|
|
11
|
+
# #
|
|
12
|
+
# ============================================================================ #
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ---------------------------------------------------------------------------- #
|
|
16
|
+
# #
|
|
17
|
+
# Overview ####
|
|
18
|
+
# #
|
|
19
|
+
# ---------------------------------------------------------------------------- #
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------- #
|
|
23
|
+
# Description ####
|
|
24
|
+
# ---------------------------------------------------------------------------- #
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
!!! note "Summary"
|
|
29
|
+
Command-line interface for the docstring format checker.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------- #
|
|
34
|
+
# #
|
|
35
|
+
# Setup ####
|
|
36
|
+
# #
|
|
37
|
+
# ---------------------------------------------------------------------------- #
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## --------------------------------------------------------------------------- #
|
|
41
|
+
## Imports ####
|
|
42
|
+
## --------------------------------------------------------------------------- #
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# ## Python StdLib Imports ----
|
|
46
|
+
from pathlib import Path
|
|
47
|
+
from textwrap import dedent
|
|
48
|
+
from typing import Optional, Union
|
|
49
|
+
|
|
50
|
+
# ## Python Third Party Imports ----
|
|
51
|
+
from rich.console import Console
|
|
52
|
+
from rich.panel import Panel
|
|
53
|
+
from rich.table import Table
|
|
54
|
+
from toolbox_python.bools import strtobool
|
|
55
|
+
from typer import (
|
|
56
|
+
Argument,
|
|
57
|
+
BadParameter,
|
|
58
|
+
CallbackParam,
|
|
59
|
+
Context,
|
|
60
|
+
Exit,
|
|
61
|
+
Option,
|
|
62
|
+
Typer,
|
|
63
|
+
echo,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# ## Local First Party Imports ----
|
|
67
|
+
from docstring_format_checker import __version__
|
|
68
|
+
from docstring_format_checker.config import SectionConfig, find_config_file, load_config
|
|
69
|
+
from docstring_format_checker.core import DocstringChecker, DocstringError
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## --------------------------------------------------------------------------- #
|
|
73
|
+
## Exports ####
|
|
74
|
+
## --------------------------------------------------------------------------- #
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
__all__: list[str] = [
|
|
78
|
+
"main",
|
|
79
|
+
"config_example",
|
|
80
|
+
"check",
|
|
81
|
+
"entry_point",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
## --------------------------------------------------------------------------- #
|
|
86
|
+
## Constants ####
|
|
87
|
+
## --------------------------------------------------------------------------- #
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
NEW_LINE = "\n"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ---------------------------------------------------------------------------- #
|
|
94
|
+
# #
|
|
95
|
+
# Main Application ####
|
|
96
|
+
# #
|
|
97
|
+
# ---------------------------------------------------------------------------- #
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
app = Typer(
|
|
101
|
+
name="docstring-format-checker",
|
|
102
|
+
help="A CLI tool to check and validate Python docstring formatting and completeness.",
|
|
103
|
+
add_completion=False,
|
|
104
|
+
rich_markup_mode="rich",
|
|
105
|
+
add_help_option=False, # Disable automatic help so we can add our own with -h
|
|
106
|
+
)
|
|
107
|
+
console = Console()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# ---------------------------------------------------------------------------- #
|
|
111
|
+
# #
|
|
112
|
+
# Callbacks ####
|
|
113
|
+
# #
|
|
114
|
+
# ---------------------------------------------------------------------------- #
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _version_callback(ctx: Context, param: CallbackParam, value: bool) -> None:
|
|
118
|
+
"""
|
|
119
|
+
!!! note "Summary"
|
|
120
|
+
Print version and exit.
|
|
121
|
+
|
|
122
|
+
Params:
|
|
123
|
+
ctx (Context):
|
|
124
|
+
The context object.
|
|
125
|
+
param (CallbackParam):
|
|
126
|
+
The parameter object.
|
|
127
|
+
value (bool):
|
|
128
|
+
The boolean value indicating if the flag was set.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
(None):
|
|
132
|
+
Nothing is returned.
|
|
133
|
+
"""
|
|
134
|
+
if value:
|
|
135
|
+
echo(f"docstring-format-checker version {__version__}")
|
|
136
|
+
raise Exit()
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _help_callback(ctx: Context, param: CallbackParam, value: bool) -> None:
|
|
140
|
+
"""
|
|
141
|
+
!!! note "Summary"
|
|
142
|
+
Show help and exit.
|
|
143
|
+
|
|
144
|
+
Params:
|
|
145
|
+
ctx (Context):
|
|
146
|
+
The context object.
|
|
147
|
+
param (CallbackParam):
|
|
148
|
+
The parameter object.
|
|
149
|
+
value (bool):
|
|
150
|
+
The boolean value indicating if the flag was set.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
(None):
|
|
154
|
+
Nothing is returned.
|
|
155
|
+
"""
|
|
156
|
+
if not value or ctx.resilient_parsing:
|
|
157
|
+
return
|
|
158
|
+
echo(ctx.get_help())
|
|
159
|
+
raise Exit()
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _parse_boolean_flag(ctx: Context, param: CallbackParam, value: Optional[str]) -> Optional[bool]:
|
|
163
|
+
"""
|
|
164
|
+
!!! note "Summary"
|
|
165
|
+
Parse boolean flag that accepts various true/false values.
|
|
166
|
+
|
|
167
|
+
Params:
|
|
168
|
+
ctx (Context):
|
|
169
|
+
The context object.
|
|
170
|
+
param (CallbackParam):
|
|
171
|
+
The parameter object.
|
|
172
|
+
value (Optional[str]):
|
|
173
|
+
The string value of the flag.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
(Optional[bool]):
|
|
177
|
+
The parsed boolean value or `None` if not provided.
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
# Handle the case where the flag is provided without a value (e.g., just --recursive or -r)
|
|
181
|
+
# In this case, Typer doesn't call the callback, so we need to handle it differently
|
|
182
|
+
if value is None:
|
|
183
|
+
# This means the flag wasn't provided at all, use default
|
|
184
|
+
return True
|
|
185
|
+
|
|
186
|
+
# If value is an empty string, it means the flag was provided without a value
|
|
187
|
+
if value == "":
|
|
188
|
+
return True
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
return strtobool(value)
|
|
192
|
+
except ValueError as e:
|
|
193
|
+
raise BadParameter(
|
|
194
|
+
message=(
|
|
195
|
+
f"Invalid boolean value: '{value}'.{NEW_LINE}"
|
|
196
|
+
"Use one of: true/false, t/f, yes/no, y/n, 1/0, or on/off."
|
|
197
|
+
)
|
|
198
|
+
) from e
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _parse_recursive_flag(value: str) -> bool:
|
|
202
|
+
"""
|
|
203
|
+
!!! note "Summary"
|
|
204
|
+
Parse recursive flag using `strtobool()` utility.
|
|
205
|
+
|
|
206
|
+
Params:
|
|
207
|
+
value (str):
|
|
208
|
+
The string value of the flag.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
(bool):
|
|
212
|
+
The parsed boolean value.
|
|
213
|
+
"""
|
|
214
|
+
return strtobool(value)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _show_examples_callback(ctx: Context, param: CallbackParam, value: bool) -> None:
|
|
218
|
+
"""
|
|
219
|
+
!!! note "Summary"
|
|
220
|
+
Show examples and exit.
|
|
221
|
+
|
|
222
|
+
Params:
|
|
223
|
+
ctx (Context):
|
|
224
|
+
The context object.
|
|
225
|
+
param (CallbackParam):
|
|
226
|
+
The parameter object.
|
|
227
|
+
value (bool):
|
|
228
|
+
The boolean value indicating if the flag was set.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
(None):
|
|
232
|
+
Nothing is returned.
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
if not value or ctx.resilient_parsing:
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
examples_content: str = dedent(
|
|
239
|
+
"""
|
|
240
|
+
[green]dfc check myfile.py[/green] Check a single Python file
|
|
241
|
+
[green]dfc check src/[/green] Check all Python files in src/ directory
|
|
242
|
+
[green]dfc check . --exclude "*/tests/*"[/green] Check current directory, excluding tests
|
|
243
|
+
[green]dfc check . -c custom.toml[/green] Use custom configuration file
|
|
244
|
+
[green]dfc check . --verbose[/green] Show detailed validation output
|
|
245
|
+
[green]dfc config-example[/green] Show example configuration
|
|
246
|
+
"""
|
|
247
|
+
).strip()
|
|
248
|
+
|
|
249
|
+
panel = Panel(
|
|
250
|
+
examples_content,
|
|
251
|
+
title="Examples",
|
|
252
|
+
title_align="left",
|
|
253
|
+
border_style="dim",
|
|
254
|
+
padding=(0, 1),
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
console.print(panel)
|
|
258
|
+
raise Exit()
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _show_check_examples_callback(ctx: Context, param: CallbackParam, value: bool) -> None:
|
|
262
|
+
"""
|
|
263
|
+
!!! note "Summary"
|
|
264
|
+
Show check command examples and exit.
|
|
265
|
+
|
|
266
|
+
Params:
|
|
267
|
+
ctx (Context):
|
|
268
|
+
The context object.
|
|
269
|
+
param (CallbackParam):
|
|
270
|
+
The parameter object.
|
|
271
|
+
value (bool):
|
|
272
|
+
The boolean value indicating if the flag was set.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
(None):
|
|
276
|
+
Nothing is returned.
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
if not value or ctx.resilient_parsing:
|
|
280
|
+
return
|
|
281
|
+
|
|
282
|
+
examples_content: str = dedent(
|
|
283
|
+
"""
|
|
284
|
+
[green]dfc check myfile.py[/green] Check a single Python file
|
|
285
|
+
[green]dfc check src/[/green] Check all Python files in src/ directory
|
|
286
|
+
[green]dfc check . --exclude "*/tests/*"[/green] Check current directory, excluding tests
|
|
287
|
+
[green]dfc check . --config custom.toml[/green] Use custom configuration file
|
|
288
|
+
[green]dfc check . --verbose --recursive[/green] Show detailed output for all subdirectories
|
|
289
|
+
[green]dfc check . --quiet[/green] Only show errors, suppress success messages
|
|
290
|
+
"""
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
panel = Panel(
|
|
294
|
+
examples_content,
|
|
295
|
+
title="Check Command Examples",
|
|
296
|
+
title_align="left",
|
|
297
|
+
border_style="dim",
|
|
298
|
+
padding=(0, 1),
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
console.print(panel)
|
|
302
|
+
raise Exit()
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _display_results(results: dict[str, list[DocstringError]], quiet: bool, verbose: bool) -> int:
|
|
306
|
+
"""
|
|
307
|
+
!!! note "Summary"
|
|
308
|
+
Display the results of docstring checking.
|
|
309
|
+
|
|
310
|
+
Params:
|
|
311
|
+
results (dict[str, list[DocstringError]]):
|
|
312
|
+
Dictionary mapping file paths to lists of errors
|
|
313
|
+
quiet (bool):
|
|
314
|
+
Whether to suppress success messages
|
|
315
|
+
verbose (bool):
|
|
316
|
+
Whether to show detailed output
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
(int):
|
|
320
|
+
Exit code (`0` for success, `1` for errors found)
|
|
321
|
+
"""
|
|
322
|
+
if not results:
|
|
323
|
+
if not quiet:
|
|
324
|
+
console.print("[green]✓ All docstrings are valid![/green]")
|
|
325
|
+
return 0
|
|
326
|
+
|
|
327
|
+
# Count total errors
|
|
328
|
+
total_errors: int = sum(len(errors) for errors in results.values())
|
|
329
|
+
total_files: int = len(results)
|
|
330
|
+
|
|
331
|
+
if verbose:
|
|
332
|
+
# Show detailed table
|
|
333
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
334
|
+
table.add_column("File", style="cyan", no_wrap=False)
|
|
335
|
+
table.add_column("Line", justify="right", style="white")
|
|
336
|
+
table.add_column("Item", style="yellow")
|
|
337
|
+
table.add_column("Type", style="blue")
|
|
338
|
+
table.add_column("Error", style="red")
|
|
339
|
+
|
|
340
|
+
for file_path, errors in results.items():
|
|
341
|
+
for i, error in enumerate(errors):
|
|
342
|
+
file_display: str = file_path if i == 0 else ""
|
|
343
|
+
table.add_row(
|
|
344
|
+
file_display,
|
|
345
|
+
str(error.line_number) if error.line_number > 0 else "",
|
|
346
|
+
error.item_name,
|
|
347
|
+
error.item_type,
|
|
348
|
+
error.message,
|
|
349
|
+
)
|
|
350
|
+
console.print(table)
|
|
351
|
+
|
|
352
|
+
else:
|
|
353
|
+
# Show compact output
|
|
354
|
+
for file_path, errors in results.items():
|
|
355
|
+
console.print(f"{NEW_LINE}[cyan]{file_path}[/cyan]")
|
|
356
|
+
for error in errors:
|
|
357
|
+
if error.line_number > 0:
|
|
358
|
+
console.print(
|
|
359
|
+
f" [red]Line {error.line_number}[/red] - {error.item_type} '{error.item_name}': {error.message}"
|
|
360
|
+
)
|
|
361
|
+
else:
|
|
362
|
+
console.print(f" [red]Error[/red]: {error.message}")
|
|
363
|
+
|
|
364
|
+
# Summary
|
|
365
|
+
console.print(f"{NEW_LINE}[red]Found {total_errors} error(s) in {total_files} file(s)[/red]")
|
|
366
|
+
|
|
367
|
+
return 1
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
# ---------------------------------------------------------------------------- #
|
|
371
|
+
# #
|
|
372
|
+
# Main Logic ####
|
|
373
|
+
# #
|
|
374
|
+
# ---------------------------------------------------------------------------- #
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
# This will be the default behavior when no command is specified
|
|
378
|
+
def _check_docstrings(
|
|
379
|
+
path: str,
|
|
380
|
+
config: Optional[str] = None,
|
|
381
|
+
recursive: bool = True,
|
|
382
|
+
exclude: Optional[list[str]] = None,
|
|
383
|
+
quiet: bool = False,
|
|
384
|
+
verbose: bool = False,
|
|
385
|
+
) -> None:
|
|
386
|
+
"""
|
|
387
|
+
!!! note "Summary"
|
|
388
|
+
Core logic for checking docstrings.
|
|
389
|
+
|
|
390
|
+
Params:
|
|
391
|
+
path (str):
|
|
392
|
+
The path to the file or directory to check.
|
|
393
|
+
config (Optional[str]):
|
|
394
|
+
The path to the configuration file.
|
|
395
|
+
recursive (bool):
|
|
396
|
+
Whether to check files recursively.
|
|
397
|
+
exclude (Optional[list[str]]):
|
|
398
|
+
List of glob patterns to exclude from checking.
|
|
399
|
+
quiet (bool):
|
|
400
|
+
Whether to suppress output.
|
|
401
|
+
verbose (bool):
|
|
402
|
+
Whether to show detailed output.
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
(None):
|
|
406
|
+
Nothing is returned.
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
target_path = Path(path)
|
|
410
|
+
|
|
411
|
+
# Validate target path
|
|
412
|
+
if not target_path.exists():
|
|
413
|
+
console.print(f"[red]Error: Path does not exist: {path}[/red]")
|
|
414
|
+
raise Exit(1)
|
|
415
|
+
|
|
416
|
+
# Load configuration
|
|
417
|
+
try:
|
|
418
|
+
if config:
|
|
419
|
+
config_path = Path(config)
|
|
420
|
+
if not config_path.exists():
|
|
421
|
+
console.print(f"[red]Error: Configuration file does not exist: {config}[/red]")
|
|
422
|
+
raise Exit(1)
|
|
423
|
+
sections_config = load_config(config_path)
|
|
424
|
+
else:
|
|
425
|
+
# Try to find config file automatically
|
|
426
|
+
found_config: Union[Path, None] = find_config_file(
|
|
427
|
+
target_path if target_path.is_dir() else target_path.parent
|
|
428
|
+
)
|
|
429
|
+
if found_config:
|
|
430
|
+
if verbose:
|
|
431
|
+
console.print(f"[blue]Using configuration from: {found_config}[/blue]")
|
|
432
|
+
sections_config: list[SectionConfig] = load_config(found_config)
|
|
433
|
+
else:
|
|
434
|
+
if verbose:
|
|
435
|
+
console.print("[blue]Using default configuration[/blue]")
|
|
436
|
+
sections_config: list[SectionConfig] = load_config()
|
|
437
|
+
|
|
438
|
+
except Exception as e:
|
|
439
|
+
console.print(f"[red]Error loading configuration: {e}[/red]")
|
|
440
|
+
raise Exit(1)
|
|
441
|
+
|
|
442
|
+
# Initialize checker
|
|
443
|
+
checker = DocstringChecker(sections_config)
|
|
444
|
+
|
|
445
|
+
# Check files
|
|
446
|
+
try:
|
|
447
|
+
if target_path.is_file():
|
|
448
|
+
if verbose:
|
|
449
|
+
console.print(f"[blue]Checking file: {target_path}[/blue]")
|
|
450
|
+
errors: list[DocstringError] = checker.check_file(target_path)
|
|
451
|
+
results: dict[str, list[DocstringError]] = {str(target_path): errors} if errors else {}
|
|
452
|
+
else:
|
|
453
|
+
if verbose:
|
|
454
|
+
console.print(f"[blue]Checking directory: {target_path} (recursive={recursive})[/blue]")
|
|
455
|
+
results: dict[str, list[DocstringError]] = checker.check_directory(
|
|
456
|
+
target_path, recursive=recursive, exclude_patterns=exclude
|
|
457
|
+
)
|
|
458
|
+
except Exception as e:
|
|
459
|
+
console.print(f"[red]Error during checking: {e}[/red]")
|
|
460
|
+
raise Exit(1)
|
|
461
|
+
|
|
462
|
+
# Display results
|
|
463
|
+
exit_code: int = _display_results(results, quiet, verbose)
|
|
464
|
+
|
|
465
|
+
if exit_code != 0:
|
|
466
|
+
raise Exit(exit_code)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
# ---------------------------------------------------------------------------- #
|
|
470
|
+
# #
|
|
471
|
+
# App Operators ####
|
|
472
|
+
# #
|
|
473
|
+
# ---------------------------------------------------------------------------- #
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
# Simple callback that only handles global options and delegates to subcommands
|
|
477
|
+
@app.callback(invoke_without_command=True)
|
|
478
|
+
def main(
|
|
479
|
+
ctx: Context,
|
|
480
|
+
version: Optional[bool] = Option(
|
|
481
|
+
None,
|
|
482
|
+
"--version",
|
|
483
|
+
"-v",
|
|
484
|
+
callback=_version_callback,
|
|
485
|
+
is_eager=True,
|
|
486
|
+
help="Show version and exit",
|
|
487
|
+
),
|
|
488
|
+
examples: Optional[bool] = Option(
|
|
489
|
+
None,
|
|
490
|
+
"--examples",
|
|
491
|
+
"-e",
|
|
492
|
+
callback=_show_examples_callback,
|
|
493
|
+
is_eager=True,
|
|
494
|
+
help="Show usage examples and exit",
|
|
495
|
+
),
|
|
496
|
+
help_flag: Optional[bool] = Option(
|
|
497
|
+
None,
|
|
498
|
+
"--help",
|
|
499
|
+
"-h",
|
|
500
|
+
callback=_help_callback,
|
|
501
|
+
is_eager=True,
|
|
502
|
+
help="Show this message and exit",
|
|
503
|
+
),
|
|
504
|
+
) -> None:
|
|
505
|
+
"""
|
|
506
|
+
!!! note "Summary"
|
|
507
|
+
Check Python docstring formatting and completeness.
|
|
508
|
+
|
|
509
|
+
???+ abstract "Details"
|
|
510
|
+
This tool analyzes Python files and validates that functions, methods, and classes have properly formatted docstrings according to the configured sections.
|
|
511
|
+
|
|
512
|
+
Params:
|
|
513
|
+
ctx (Context):
|
|
514
|
+
The context object for the command.
|
|
515
|
+
version (Optional[bool]):
|
|
516
|
+
Show version and exit.
|
|
517
|
+
examples (Optional[bool]):
|
|
518
|
+
Show usage examples and exit.
|
|
519
|
+
help_flag (Optional[bool]):
|
|
520
|
+
Show help message and exit.
|
|
521
|
+
|
|
522
|
+
Returns:
|
|
523
|
+
(None):
|
|
524
|
+
Nothing is returned.
|
|
525
|
+
"""
|
|
526
|
+
# If no subcommand is provided, show help
|
|
527
|
+
if ctx.invoked_subcommand is None:
|
|
528
|
+
echo(ctx.get_help())
|
|
529
|
+
raise Exit()
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
@app.command(
|
|
533
|
+
rich_help_panel="Commands",
|
|
534
|
+
add_help_option=False, # Disable automatic help so we can add our own with -h
|
|
535
|
+
)
|
|
536
|
+
def check(
|
|
537
|
+
path: str = Argument(..., help="Path to Python file or directory to check"),
|
|
538
|
+
config: Optional[str] = Option(None, "--config", "-c", help="Path to configuration file (TOML format)"),
|
|
539
|
+
recursive: str = Option(
|
|
540
|
+
"true",
|
|
541
|
+
"--recursive",
|
|
542
|
+
"-r",
|
|
543
|
+
help="Check directories recursively (default: true). Accepts: true/false, t/f, yes/no, y/n, 1/0, on/off",
|
|
544
|
+
),
|
|
545
|
+
exclude: Optional[list[str]] = Option(
|
|
546
|
+
None,
|
|
547
|
+
"--exclude",
|
|
548
|
+
"-x",
|
|
549
|
+
help="Glob patterns to exclude (can be used multiple times)",
|
|
550
|
+
),
|
|
551
|
+
quiet: bool = Option(False, "--quiet", "-q", help="Only show errors, no success messages"),
|
|
552
|
+
verbose: bool = Option(False, "--verbose", "-n", help="Show detailed output"),
|
|
553
|
+
examples: Optional[bool] = Option(
|
|
554
|
+
None,
|
|
555
|
+
"--examples",
|
|
556
|
+
"-e",
|
|
557
|
+
callback=_show_check_examples_callback,
|
|
558
|
+
is_eager=True,
|
|
559
|
+
help="Show usage examples and exit",
|
|
560
|
+
),
|
|
561
|
+
help_flag: Optional[bool] = Option(
|
|
562
|
+
None,
|
|
563
|
+
"--help",
|
|
564
|
+
"-h",
|
|
565
|
+
callback=_help_callback,
|
|
566
|
+
is_eager=True,
|
|
567
|
+
help="Show this message and exit",
|
|
568
|
+
),
|
|
569
|
+
) -> None:
|
|
570
|
+
"""
|
|
571
|
+
!!! note "Summary"
|
|
572
|
+
Check docstrings in Python files.
|
|
573
|
+
|
|
574
|
+
???+ abstract "Details"
|
|
575
|
+
This command checks the docstrings in the specified Python file or directory.
|
|
576
|
+
|
|
577
|
+
Params:
|
|
578
|
+
path (str):
|
|
579
|
+
The path to the Python file or directory to check.
|
|
580
|
+
config (Optional[str]):
|
|
581
|
+
The path to the configuration file (TOML format).
|
|
582
|
+
recursive (bool):
|
|
583
|
+
Whether to check directories recursively.
|
|
584
|
+
exclude (list[str]):
|
|
585
|
+
Glob patterns to exclude (can be used multiple times).
|
|
586
|
+
quiet (bool):
|
|
587
|
+
Whether to only show errors, no success messages.
|
|
588
|
+
verbose (bool):
|
|
589
|
+
Whether to show detailed output.
|
|
590
|
+
examples (Optional[bool]):
|
|
591
|
+
Show usage examples and exit.
|
|
592
|
+
help_flag (Optional[bool]):
|
|
593
|
+
Show help message and exit.
|
|
594
|
+
|
|
595
|
+
Returns:
|
|
596
|
+
(None):
|
|
597
|
+
Nothing is returned.
|
|
598
|
+
"""
|
|
599
|
+
# Parse the recursive string value into a boolean
|
|
600
|
+
try:
|
|
601
|
+
recursive_bool: bool = _parse_recursive_flag(recursive)
|
|
602
|
+
except ValueError as e:
|
|
603
|
+
raise BadParameter(
|
|
604
|
+
message=(
|
|
605
|
+
f"Invalid value for --recursive: '{recursive}'.{NEW_LINE}"
|
|
606
|
+
"Use one of: true/false, t/f, yes/no, y/n, 1/0, or on/off."
|
|
607
|
+
)
|
|
608
|
+
) from e
|
|
609
|
+
_check_docstrings(path, config, recursive_bool, exclude, quiet, verbose)
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
@app.command(
|
|
613
|
+
rich_help_panel="Commands",
|
|
614
|
+
add_help_option=False, # Disable automatic help so we can add our own with -h
|
|
615
|
+
)
|
|
616
|
+
def config_example(
|
|
617
|
+
help_flag: Optional[bool] = Option(
|
|
618
|
+
None,
|
|
619
|
+
"--help",
|
|
620
|
+
"-h",
|
|
621
|
+
callback=_help_callback,
|
|
622
|
+
is_eager=True,
|
|
623
|
+
help="Show this message and exit",
|
|
624
|
+
),
|
|
625
|
+
) -> None:
|
|
626
|
+
"""
|
|
627
|
+
!!! note "Summary"
|
|
628
|
+
Show example configuration file.
|
|
629
|
+
|
|
630
|
+
Params:
|
|
631
|
+
help_flag (Optional[bool]):
|
|
632
|
+
Show help message and exit.
|
|
633
|
+
|
|
634
|
+
Returns:
|
|
635
|
+
(None):
|
|
636
|
+
Nothing is returned.
|
|
637
|
+
"""
|
|
638
|
+
example_config: str = dedent(
|
|
639
|
+
"""
|
|
640
|
+
# Example configuration for docstring-format-checker
|
|
641
|
+
# Place this in your pyproject.toml file
|
|
642
|
+
|
|
643
|
+
[tool.dfc]
|
|
644
|
+
# or [tool.docstring-format-checker]
|
|
645
|
+
|
|
646
|
+
[[tool.dfc.sections]]
|
|
647
|
+
order = 1
|
|
648
|
+
name = "summary"
|
|
649
|
+
type = "free_text"
|
|
650
|
+
admonition = "note"
|
|
651
|
+
prefix = "!!!"
|
|
652
|
+
required = true
|
|
653
|
+
|
|
654
|
+
[[tool.dfc.sections]]
|
|
655
|
+
order = 2
|
|
656
|
+
name = "details"
|
|
657
|
+
type = "free_text"
|
|
658
|
+
admonition = "info"
|
|
659
|
+
prefix = "???+"
|
|
660
|
+
required = false
|
|
661
|
+
|
|
662
|
+
[[tool.dfc.sections]]
|
|
663
|
+
order = 3
|
|
664
|
+
name = "params"
|
|
665
|
+
type = "list_name_and_type"
|
|
666
|
+
required = true
|
|
667
|
+
|
|
668
|
+
[[tool.dfc.sections]]
|
|
669
|
+
order = 4
|
|
670
|
+
name = "returns"
|
|
671
|
+
type = "list_name_and_type"
|
|
672
|
+
required = false
|
|
673
|
+
|
|
674
|
+
[[tool.dfc.sections]]
|
|
675
|
+
order = 5
|
|
676
|
+
name = "yields"
|
|
677
|
+
type = "list_type"
|
|
678
|
+
required = false
|
|
679
|
+
|
|
680
|
+
[[tool.dfc.sections]]
|
|
681
|
+
order = 6
|
|
682
|
+
name = "raises"
|
|
683
|
+
type = "list_type"
|
|
684
|
+
required = false
|
|
685
|
+
|
|
686
|
+
[[tool.dfc.sections]]
|
|
687
|
+
order = 7
|
|
688
|
+
name = "examples"
|
|
689
|
+
type = "free_text"
|
|
690
|
+
admonition = "example"
|
|
691
|
+
prefix = "???+"
|
|
692
|
+
required = false
|
|
693
|
+
|
|
694
|
+
[[tool.dfc.sections]]
|
|
695
|
+
order = 8
|
|
696
|
+
name = "notes"
|
|
697
|
+
type = "free_text"
|
|
698
|
+
admonition = "note"
|
|
699
|
+
prefix = "???"
|
|
700
|
+
required = false
|
|
701
|
+
""".strip()
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
print(example_config)
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
def entry_point() -> None:
|
|
708
|
+
"""
|
|
709
|
+
!!! note "Summary"
|
|
710
|
+
Entry point for the CLI scripts defined in pyproject.toml.
|
|
711
|
+
"""
|
|
712
|
+
app()
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
if __name__ == "__main__":
|
|
716
|
+
app()
|