docstring-format-checker 0.5.0__tar.gz → 0.6.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.4
2
2
  Name: docstring-format-checker
3
- Version: 0.5.0
3
+ Version: 0.6.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.5.0"
3
+ version = "v0.6.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"
@@ -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.5.0"
7
+ __version__ = "v0.6.0"
8
8
  __author__ = "Chris Mahoney"
9
9
  __email__ = "docstring-format-checker@data-science-extensions.com"
10
10
 
@@ -376,13 +376,36 @@ def _display_results(results: dict[str, list[DocstringError]], quiet: bool, outp
376
376
  console.print(_green("✓ All docstrings are valid!"))
377
377
  return 0
378
378
 
379
- # Count total errors
380
- total_errors: int = sum(len(errors) for errors in results.values())
379
+ # Count total errors (individual error messages, not error objects)
380
+ total_individual_errors: int = 0
381
+ total_functions: int = 0
382
+
383
+ for errors in results.values():
384
+ total_functions += len(errors) # Count functions/items with errors
385
+ for error in errors:
386
+ # Count individual error messages within each error object
387
+ if "; " in error.message:
388
+ individual_errors = [msg.strip() for msg in error.message.split("; ") if msg.strip()]
389
+ total_individual_errors += len(individual_errors)
390
+ else:
391
+ total_individual_errors += 1
392
+
393
+ total_errors: int = total_individual_errors
381
394
  total_files: int = len(results)
382
395
 
383
396
  if quiet:
384
- # In quiet mode, only show summary
385
- console.print(_red(f"{NEW_LINE}Found {total_errors} error(s) in {total_files} file(s)"))
397
+ # In quiet mode, only show summary with improved format
398
+ if total_functions == 1:
399
+ functions_text = f"1 function"
400
+ else:
401
+ functions_text = f"{total_functions} functions"
402
+
403
+ if total_files == 1:
404
+ files_text = f"1 file"
405
+ else:
406
+ files_text = f"{total_files} files"
407
+
408
+ console.print(_red(f"{NEW_LINE}Found {total_errors} error(s) in {functions_text} over {files_text}"))
386
409
  return 1
387
410
 
388
411
  if output == "table":
@@ -411,22 +434,43 @@ def _display_results(results: dict[str, list[DocstringError]], quiet: bool, outp
411
434
  console.print(table)
412
435
 
413
436
  else:
414
- # Show compact output
437
+ # Show compact output - each individual error on its own line
415
438
  for file_path, errors in results.items():
416
439
  console.print(f"{NEW_LINE}{_cyan(file_path)}")
417
440
  for error in errors:
418
- # Format error message with improved formatting
419
- formatted_error_message: str = _format_error_messages(error.message)
420
-
421
- if error.line_number > 0:
422
- console.print(
423
- f" [red]Line {error.line_number}[/red] - {error.item_type} '{error.item_name}': {formatted_error_message}"
424
- )
441
+ # Split error message into individual errors for list mode
442
+ if "; " in error.message:
443
+ individual_errors = [msg.strip() for msg in error.message.split("; ") if msg.strip()]
444
+ for individual_error in individual_errors:
445
+ formatted_error = f"- {individual_error}"
446
+ if error.line_number > 0:
447
+ console.print(
448
+ f" [red]Line {error.line_number}[/red] - {error.item_type} '{error.item_name}': {formatted_error}"
449
+ )
450
+ else:
451
+ console.print(f" {_red('Error')}: {formatted_error}")
425
452
  else:
426
- console.print(f" {_red('Error')}: {formatted_error_message}")
453
+ # Single error message
454
+ formatted_error = f"- {error.message.strip()}"
455
+ if error.line_number > 0:
456
+ console.print(
457
+ f" [red]Line {error.line_number}[/red] - {error.item_type} '{error.item_name}': {formatted_error}"
458
+ )
459
+ else:
460
+ console.print(f" {_red('Error')}: {formatted_error}")
461
+
462
+ # Summary - more descriptive message
463
+ if total_functions == 1:
464
+ functions_text = f"1 function"
465
+ else:
466
+ functions_text = f"{total_functions} functions"
467
+
468
+ if total_files == 1:
469
+ files_text = f"1 file"
470
+ else:
471
+ files_text = f"{total_files} files"
427
472
 
428
- # Summary
429
- console.print(_red(f"{NEW_LINE}Found {total_errors} error(s) in {total_files} file(s)"))
473
+ console.print(_red(f"{NEW_LINE}Found {total_errors} error(s) in {functions_text} over {files_text}"))
430
474
 
431
475
  return 1
432
476
 
@@ -439,7 +483,7 @@ def _display_results(results: dict[str, list[DocstringError]], quiet: bool, outp
439
483
 
440
484
 
441
485
  # This will be the default behavior when no command is specified
442
- def _check_docstrings(
486
+ def check_docstrings(
443
487
  path: str,
444
488
  config: Optional[str] = None,
445
489
  exclude: Optional[list[str]] = None,
@@ -456,14 +500,19 @@ def _check_docstrings(
456
500
  The path to the file or directory to check.
457
501
  config (Optional[str]):
458
502
  The path to the configuration file.
503
+ Default: `None`.
459
504
  exclude (Optional[list[str]]):
460
505
  List of glob patterns to exclude from checking.
506
+ Default: `None`.
461
507
  quiet (bool):
462
508
  Whether to suppress output.
509
+ Default: `False`.
463
510
  output (str):
464
511
  Output format: 'table' or 'list'.
512
+ Default: `'list'`.
465
513
  check (bool):
466
514
  Whether to throw error if issues are found.
515
+ Default: `False`.
467
516
 
468
517
  Returns:
469
518
  (None):
@@ -626,7 +675,7 @@ def main(
626
675
  console.print(_red(f"Error: Invalid output format '{output}'. Use 'table' or 'list'."))
627
676
  raise Exit(1)
628
677
 
629
- _check_docstrings(
678
+ check_docstrings(
630
679
  path=path,
631
680
  config=config,
632
681
  exclude=exclude,
@@ -962,9 +962,41 @@ class DocstringChecker:
962
962
  if current_section and stripped_line and not stripped_line.startswith(("!", "?", "#")):
963
963
  # Look for parameter/type definitions
964
964
  if ":" in stripped_line:
965
+ # Skip description lines that start with common description words
966
+ description_prefixes = [
967
+ "default:",
968
+ "note:",
969
+ "example:",
970
+ "see:",
971
+ "warning:",
972
+ "info:",
973
+ "tip:",
974
+ "returns:",
975
+ ]
976
+ is_description_line = any(
977
+ stripped_line.lower().startswith(prefix) for prefix in description_prefixes
978
+ )
979
+
980
+ # Skip lines that are clearly descriptions (containing "Default:", etc.)
981
+ if (
982
+ is_description_line
983
+ or "Default:" in stripped_line
984
+ or "Output format:" in stripped_line
985
+ or "Show examples:" in stripped_line
986
+ ):
987
+ continue
988
+
965
989
  # For list_name_and_type sections, check format like "name (type):" or "(type):"
966
990
  if current_section.type == "list_name_and_type":
967
991
  # Pattern: name (type): or (type):
992
+ # But skip if it doesn't look like a parameter definition (e.g., has multiple words before the colon)
993
+ colon_part = stripped_line.split(":")[0].strip()
994
+ # Skip if it contains phrases that indicate it's a description, not a parameter
995
+ if any(
996
+ word in colon_part.lower() for word in ["default", "output", "format", "show", "example"]
997
+ ):
998
+ continue
999
+
968
1000
  if not re.search(r"\([^)]+\):", stripped_line):
969
1001
  errors.append(
970
1002
  f"Section '{current_section.name}' (type: '{current_section.type}') requires "