docstring-format-checker 1.0.1__tar.gz → 1.2.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-1.0.1 → docstring_format_checker-1.2.0}/PKG-INFO +2 -1
- {docstring_format_checker-1.0.1 → docstring_format_checker-1.2.0}/pyproject.toml +2 -1
- {docstring_format_checker-1.0.1 → docstring_format_checker-1.2.0}/src/docstring_format_checker/cli.py +132 -127
- {docstring_format_checker-1.0.1 → docstring_format_checker-1.2.0}/README.md +0 -0
- {docstring_format_checker-1.0.1 → docstring_format_checker-1.2.0}/src/docstring_format_checker/__init__.py +0 -0
- {docstring_format_checker-1.0.1 → docstring_format_checker-1.2.0}/src/docstring_format_checker/config.py +0 -0
- {docstring_format_checker-1.0.1 → docstring_format_checker-1.2.0}/src/docstring_format_checker/core.py +0 -0
- {docstring_format_checker-1.0.1 → docstring_format_checker-1.2.0}/src/docstring_format_checker/utils/__init__.py +0 -0
- {docstring_format_checker-1.0.1 → docstring_format_checker-1.2.0}/src/docstring_format_checker/utils/exceptions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docstring-format-checker
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.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>
|
|
@@ -23,6 +23,7 @@ Requires-Dist: typer>=0.9.0
|
|
|
23
23
|
Requires-Dist: tomli>=2.0.0 ; python_full_version < '3.11'
|
|
24
24
|
Requires-Dist: rich>=13.0.0
|
|
25
25
|
Requires-Dist: toolbox-python==1.*
|
|
26
|
+
Requires-Dist: pyfiglet==1.*
|
|
26
27
|
Maintainer: Chris Mahoney
|
|
27
28
|
Maintainer-email: Chris Mahoney <docstring-format-checker@data-science-extensions.com>
|
|
28
29
|
Requires-Python: >=3.9
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "docstring-format-checker"
|
|
3
|
-
version = "1.0
|
|
3
|
+
version = "1.2.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"
|
|
@@ -32,6 +32,7 @@ dependencies = [
|
|
|
32
32
|
"tomli>=2.0.0;python_version<'3.11'",
|
|
33
33
|
"rich>=13.0.0",
|
|
34
34
|
"toolbox-python==1.*",
|
|
35
|
+
"pyfiglet==1.*",
|
|
35
36
|
]
|
|
36
37
|
|
|
37
38
|
[project.urls]
|
|
@@ -43,12 +43,14 @@
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
# ## Python StdLib Imports ----
|
|
46
|
+
import os
|
|
46
47
|
from functools import partial
|
|
47
48
|
from pathlib import Path
|
|
48
49
|
from textwrap import dedent
|
|
49
50
|
from typing import Optional
|
|
50
51
|
|
|
51
52
|
# ## Python Third Party Imports ----
|
|
53
|
+
import pyfiglet
|
|
52
54
|
from rich.console import Console
|
|
53
55
|
from rich.panel import Panel
|
|
54
56
|
from rich.table import Table
|
|
@@ -160,29 +162,6 @@ def _version_callback(ctx: Context, param: CallbackParam, value: bool) -> None:
|
|
|
160
162
|
raise Exit()
|
|
161
163
|
|
|
162
164
|
|
|
163
|
-
def _help_callback_main(ctx: Context, param: CallbackParam, value: bool) -> None:
|
|
164
|
-
"""
|
|
165
|
-
!!! note "Summary"
|
|
166
|
-
Show help and exit.
|
|
167
|
-
|
|
168
|
-
Params:
|
|
169
|
-
ctx (Context):
|
|
170
|
-
The context object.
|
|
171
|
-
param (CallbackParam):
|
|
172
|
-
The parameter object.
|
|
173
|
-
value (bool):
|
|
174
|
-
The boolean value indicating if the flag was set.
|
|
175
|
-
|
|
176
|
-
Returns:
|
|
177
|
-
(None):
|
|
178
|
-
Nothing is returned.
|
|
179
|
-
"""
|
|
180
|
-
if not value or ctx.resilient_parsing:
|
|
181
|
-
return
|
|
182
|
-
echo(ctx.get_help())
|
|
183
|
-
raise Exit()
|
|
184
|
-
|
|
185
|
-
|
|
186
165
|
def _example_callback(ctx: Context, param: CallbackParam, value: Optional[str]) -> None:
|
|
187
166
|
"""
|
|
188
167
|
!!! note "Summary"
|
|
@@ -211,6 +190,7 @@ def _example_callback(ctx: Context, param: CallbackParam, value: Optional[str])
|
|
|
211
190
|
else:
|
|
212
191
|
console.print(_red(f"Error: Invalid example type '{value}'. Use 'config' or 'usage'."))
|
|
213
192
|
raise Exit(1)
|
|
193
|
+
raise Exit()
|
|
214
194
|
|
|
215
195
|
|
|
216
196
|
def _show_usage_examples_callback() -> None:
|
|
@@ -233,30 +213,33 @@ def _show_usage_examples_callback() -> None:
|
|
|
233
213
|
|
|
234
214
|
examples_content: str = dedent(
|
|
235
215
|
f"""
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
{
|
|
239
|
-
{
|
|
240
|
-
{
|
|
241
|
-
{
|
|
242
|
-
{
|
|
243
|
-
{
|
|
244
|
-
{
|
|
245
|
-
{
|
|
246
|
-
{
|
|
216
|
+
Execute the below commands in any terminal after installing the package.
|
|
217
|
+
|
|
218
|
+
{_blue("dfc myfile.py")} {_green("# Check a single Python file (list output)")}
|
|
219
|
+
{_blue("dfc myfile.py other_file.py")} {_green("# Check multiple Python files")}
|
|
220
|
+
{_blue("dfc src/")} {_green("# Check all Python files in src/ directory")}
|
|
221
|
+
{_blue("dfc -x src/app/__init__.py src/")} {_green("# Check all Python files in src/ directory, excluding one init file")}
|
|
222
|
+
{_blue("dfc --output=table myfile.py")} {_green("# Check with table output format")}
|
|
223
|
+
{_blue("dfc -o list myfile.py")} {_green("# Check with list output format (default)")}
|
|
224
|
+
{_blue("dfc --check myfile.py")} {_green("# Check and exit with error if issues found")}
|
|
225
|
+
{_blue("dfc --quiet myfile.py")} {_green("# Check quietly, only show pass/fail")}
|
|
226
|
+
{_blue("dfc --quiet --check myfile.py")} {_green("# Check quietly and exit with error if issues found")}
|
|
227
|
+
{_blue("dfc . --exclude '*/tests/*'")} {_green("# Check current directory, excluding tests")}
|
|
228
|
+
{_blue("dfc . -c custom.toml")} {_green("# Use custom configuration file")}
|
|
229
|
+
{_blue("dfc --example=config")} {_green("# Show example configuration")}
|
|
230
|
+
{_blue("dfc -e usage")} {_green("# Show usage examples (this help)")}
|
|
247
231
|
"""
|
|
248
232
|
).strip()
|
|
249
233
|
|
|
250
234
|
panel = Panel(
|
|
251
235
|
examples_content,
|
|
252
|
-
title="Examples",
|
|
236
|
+
title="Usage Examples",
|
|
253
237
|
title_align="left",
|
|
254
238
|
border_style="dim",
|
|
255
239
|
padding=(0, 1),
|
|
256
240
|
)
|
|
257
241
|
|
|
258
242
|
console.print(panel)
|
|
259
|
-
raise Exit()
|
|
260
243
|
|
|
261
244
|
|
|
262
245
|
def _show_config_example_callback() -> None:
|
|
@@ -278,73 +261,84 @@ def _show_config_example_callback() -> None:
|
|
|
278
261
|
"""
|
|
279
262
|
|
|
280
263
|
example_config: str = dedent(
|
|
281
|
-
"""
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
[tool.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
[[
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
type = "free_text"
|
|
300
|
-
admonition = "info"
|
|
301
|
-
prefix = "???+"
|
|
302
|
-
required = false
|
|
303
|
-
|
|
304
|
-
[[tool.dfc.sections]]
|
|
305
|
-
order = 3
|
|
306
|
-
name = "params"
|
|
307
|
-
type = "list_name_and_type"
|
|
308
|
-
required = true
|
|
309
|
-
|
|
310
|
-
[[tool.dfc.sections]]
|
|
311
|
-
order = 4
|
|
312
|
-
name = "returns"
|
|
313
|
-
type = "list_name_and_type"
|
|
314
|
-
required = false
|
|
315
|
-
|
|
316
|
-
[[tool.dfc.sections]]
|
|
317
|
-
order = 5
|
|
318
|
-
name = "yields"
|
|
319
|
-
type = "list_type"
|
|
320
|
-
required = false
|
|
321
|
-
|
|
322
|
-
[[tool.dfc.sections]]
|
|
323
|
-
order = 6
|
|
324
|
-
name = "raises"
|
|
325
|
-
type = "list_type"
|
|
326
|
-
required = false
|
|
327
|
-
|
|
328
|
-
[[tool.dfc.sections]]
|
|
329
|
-
order = 7
|
|
330
|
-
name = "examples"
|
|
331
|
-
type = "free_text"
|
|
332
|
-
admonition = "example"
|
|
333
|
-
prefix = "???+"
|
|
334
|
-
required = false
|
|
335
|
-
|
|
336
|
-
[[tool.dfc.sections]]
|
|
337
|
-
order = 8
|
|
338
|
-
name = "notes"
|
|
339
|
-
type = "free_text"
|
|
340
|
-
admonition = "note"
|
|
341
|
-
prefix = "???"
|
|
342
|
-
required = false
|
|
264
|
+
r"""
|
|
265
|
+
Place the below config in your `pyproject.toml` file.
|
|
266
|
+
|
|
267
|
+
[blue]\[tool.dfc][/blue]
|
|
268
|
+
[green]# or \[tool.docstring-format-checker][/green]
|
|
269
|
+
[blue]allow_undefined_sections = false[/blue]
|
|
270
|
+
[blue]require_docstrings = true[/blue]
|
|
271
|
+
[blue]check_private = true[/blue]
|
|
272
|
+
[blue]sections = [[/blue]
|
|
273
|
+
[blue]{ order = 1, name = "summary", type = "free_text", required = true, admonition = "note", prefix = "!!!" },[/blue]
|
|
274
|
+
[blue]{ order = 2, name = "details", type = "free_text", required = false, admonition = "abstract", prefix = "???+" },[/blue]
|
|
275
|
+
[blue]{ order = 3, name = "params", type = "list_name_and_type", required = false },[/blue]
|
|
276
|
+
[blue]{ order = 4, name = "raises", type = "list_type", required = false },[/blue]
|
|
277
|
+
[blue]{ order = 5, name = "returns", type = "list_name_and_type", required = false },[/blue]
|
|
278
|
+
[blue]{ order = 6, name = "yields", type = "list_type", required = false },[/blue]
|
|
279
|
+
[blue]{ order = 7, name = "examples", type = "free_text", required = false, admonition = "example", prefix = "???+" },[/blue]
|
|
280
|
+
[blue]{ order = 8, name = "notes", type = "free_text", required = false, admonition = "note", prefix = "???" },[/blue]
|
|
281
|
+
[blue]][/blue]
|
|
343
282
|
"""
|
|
344
283
|
).strip()
|
|
345
284
|
|
|
285
|
+
panel = Panel(
|
|
286
|
+
example_config,
|
|
287
|
+
title="Configuration Example",
|
|
288
|
+
title_align="left",
|
|
289
|
+
border_style="dim",
|
|
290
|
+
padding=(0, 1),
|
|
291
|
+
)
|
|
292
|
+
|
|
346
293
|
# Print without Rich markup processing to avoid bracket interpretation
|
|
347
|
-
console.print(
|
|
294
|
+
console.print(panel)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def _help_callback_main(ctx: Context, param: CallbackParam, value: bool) -> None:
|
|
298
|
+
"""
|
|
299
|
+
!!! note "Summary"
|
|
300
|
+
Show help and exit.
|
|
301
|
+
|
|
302
|
+
Params:
|
|
303
|
+
ctx (Context):
|
|
304
|
+
The context object.
|
|
305
|
+
param (CallbackParam):
|
|
306
|
+
The parameter object.
|
|
307
|
+
value (bool):
|
|
308
|
+
The boolean value indicating if the flag was set.
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
(None):
|
|
312
|
+
Nothing is returned.
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
# Early exit if help flag is set
|
|
316
|
+
if not value or ctx.resilient_parsing:
|
|
317
|
+
return
|
|
318
|
+
|
|
319
|
+
# Determine terminal width for ASCII art
|
|
320
|
+
try:
|
|
321
|
+
terminal_width: int = os.get_terminal_size().columns
|
|
322
|
+
except OSError:
|
|
323
|
+
terminal_width = 80
|
|
324
|
+
|
|
325
|
+
# Determine title based on terminal width
|
|
326
|
+
title: str = "dfc" if terminal_width < 130 else "docstring-format-checker"
|
|
327
|
+
|
|
328
|
+
# Print ASCII art title
|
|
329
|
+
console.print(
|
|
330
|
+
pyfiglet.figlet_format(title, font="standard", justify="left", width=140),
|
|
331
|
+
style="magenta",
|
|
332
|
+
markup=False,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# Show help message
|
|
336
|
+
echo(ctx.get_help())
|
|
337
|
+
|
|
338
|
+
# Show usage and config examples
|
|
339
|
+
_show_usage_examples_callback()
|
|
340
|
+
_show_config_example_callback()
|
|
341
|
+
|
|
348
342
|
raise Exit()
|
|
349
343
|
|
|
350
344
|
|
|
@@ -497,7 +491,7 @@ def _display_results(results: dict[str, list[DocstringError]], quiet: bool, outp
|
|
|
497
491
|
|
|
498
492
|
# This will be the default behavior when no command is specified
|
|
499
493
|
def check_docstrings(
|
|
500
|
-
|
|
494
|
+
paths: list[str],
|
|
501
495
|
config: Optional[str] = None,
|
|
502
496
|
exclude: Optional[list[str]] = None,
|
|
503
497
|
quiet: bool = False,
|
|
@@ -509,8 +503,8 @@ def check_docstrings(
|
|
|
509
503
|
Core logic for checking docstrings.
|
|
510
504
|
|
|
511
505
|
Params:
|
|
512
|
-
|
|
513
|
-
The path to the file or directory to check.
|
|
506
|
+
paths (list[str]):
|
|
507
|
+
The path(s) to the file(s) or directory(ies) to check.
|
|
514
508
|
config (Optional[str]):
|
|
515
509
|
The path to the configuration file.
|
|
516
510
|
Default: `None`.
|
|
@@ -532,14 +526,20 @@ def check_docstrings(
|
|
|
532
526
|
Nothing is returned.
|
|
533
527
|
"""
|
|
534
528
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
if not
|
|
539
|
-
|
|
529
|
+
# Validate all target paths
|
|
530
|
+
path_objs: list[Path] = [Path(path) for path in paths]
|
|
531
|
+
target_paths: list[Path] = [p for p in path_objs if p.exists()]
|
|
532
|
+
invalid_paths: list[Path] = [p for p in path_objs if not p.exists()]
|
|
533
|
+
|
|
534
|
+
if len(invalid_paths) > 0:
|
|
535
|
+
console.print(
|
|
536
|
+
_red(f"[bold]Error: Paths do not exist:[/bold]"),
|
|
537
|
+
NEW_LINE,
|
|
538
|
+
NEW_LINE.join([f"- '{invalid_path}'" for invalid_path in invalid_paths]),
|
|
539
|
+
)
|
|
540
540
|
raise Exit(1)
|
|
541
541
|
|
|
542
|
-
# Load configuration
|
|
542
|
+
# Load configuration (use first path for config discovery if no config specified)
|
|
543
543
|
try:
|
|
544
544
|
if config:
|
|
545
545
|
config_path = Path(config)
|
|
@@ -548,8 +548,9 @@ def check_docstrings(
|
|
|
548
548
|
raise Exit(1)
|
|
549
549
|
config_obj = load_config(config_path)
|
|
550
550
|
else:
|
|
551
|
-
# Try to find config file automatically
|
|
552
|
-
|
|
551
|
+
# Try to find config file automatically using the first path
|
|
552
|
+
first_path: Path = target_paths[0]
|
|
553
|
+
found_config: Optional[Path] = find_config_file(first_path if first_path.is_dir() else first_path.parent)
|
|
553
554
|
if found_config:
|
|
554
555
|
config_obj: Config = load_config(found_config)
|
|
555
556
|
else:
|
|
@@ -562,19 +563,27 @@ def check_docstrings(
|
|
|
562
563
|
# Initialize checker
|
|
563
564
|
checker = DocstringChecker(config_obj)
|
|
564
565
|
|
|
565
|
-
# Check
|
|
566
|
+
# Check all paths and collect results
|
|
567
|
+
all_results: dict[str, list[DocstringError]] = {}
|
|
568
|
+
|
|
566
569
|
try:
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
570
|
+
for target_path in target_paths:
|
|
571
|
+
if target_path.is_file():
|
|
572
|
+
errors: list[DocstringError] = checker.check_file(target_path)
|
|
573
|
+
if errors:
|
|
574
|
+
all_results[str(target_path)] = errors
|
|
575
|
+
else:
|
|
576
|
+
directory_results: dict[str, list[DocstringError]] = checker.check_directory(
|
|
577
|
+
target_path, exclude_patterns=exclude
|
|
578
|
+
)
|
|
579
|
+
all_results.update(directory_results)
|
|
580
|
+
|
|
572
581
|
except Exception as e:
|
|
573
582
|
console.print(_red(f"Error during checking: {e}"))
|
|
574
583
|
raise Exit(1)
|
|
575
584
|
|
|
576
585
|
# Display results
|
|
577
|
-
exit_code: int = _display_results(
|
|
586
|
+
exit_code: int = _display_results(all_results, quiet, output, check)
|
|
578
587
|
|
|
579
588
|
# Always exit with error code if issues are found, regardless of check flag
|
|
580
589
|
if exit_code != 0:
|
|
@@ -592,7 +601,7 @@ def check_docstrings(
|
|
|
592
601
|
@app.callback(invoke_without_command=True)
|
|
593
602
|
def main(
|
|
594
603
|
ctx: Context,
|
|
595
|
-
|
|
604
|
+
paths: Optional[list[str]] = Argument(None, help="Path(s) to Python file(s) or directory(s) for DFC to check"),
|
|
596
605
|
config: Optional[str] = Option(None, "--config", "-f", help="Path to configuration file (TOML format)"),
|
|
597
606
|
exclude: Optional[list[str]] = Option(
|
|
598
607
|
None,
|
|
@@ -654,8 +663,8 @@ def main(
|
|
|
654
663
|
Params:
|
|
655
664
|
ctx (Context):
|
|
656
665
|
The context object for the command.
|
|
657
|
-
|
|
658
|
-
Path to Python file or directory to check.
|
|
666
|
+
paths (Optional[list[str]]):
|
|
667
|
+
Path(s) to Python file(s) or directory(ies) to check.
|
|
659
668
|
config (Optional[str]):
|
|
660
669
|
Path to configuration file (TOML format).
|
|
661
670
|
exclude (Optional[list[str]]):
|
|
@@ -678,8 +687,8 @@ def main(
|
|
|
678
687
|
Nothing is returned.
|
|
679
688
|
"""
|
|
680
689
|
|
|
681
|
-
# If no
|
|
682
|
-
if
|
|
690
|
+
# If no paths are provided, show help
|
|
691
|
+
if not paths:
|
|
683
692
|
echo(ctx.get_help())
|
|
684
693
|
raise Exit(0)
|
|
685
694
|
|
|
@@ -689,7 +698,7 @@ def main(
|
|
|
689
698
|
raise Exit(1)
|
|
690
699
|
|
|
691
700
|
check_docstrings(
|
|
692
|
-
|
|
701
|
+
paths=paths,
|
|
693
702
|
config=config,
|
|
694
703
|
exclude=exclude,
|
|
695
704
|
quiet=quiet,
|
|
@@ -704,7 +713,3 @@ def entry_point() -> None:
|
|
|
704
713
|
Entry point for the CLI scripts defined in pyproject.toml.
|
|
705
714
|
"""
|
|
706
715
|
app()
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
if __name__ == "__main__":
|
|
710
|
-
app()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|