docstring-format-checker 0.6.0__tar.gz → 0.8.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.6.0
3
+ Version: 0.8.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.6.0"
3
+ version = "v0.8.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.6.0"
7
+ __version__ = "v0.8.0"
8
8
  __author__ = "Chris Mahoney"
9
9
  __email__ = "docstring-format-checker@data-science-extensions.com"
10
10
 
@@ -434,30 +434,24 @@ def _display_results(results: dict[str, list[DocstringError]], quiet: bool, outp
434
434
  console.print(table)
435
435
 
436
436
  else:
437
- # Show compact output - each individual error on its own line
437
+ # Show compact output with grouped errors under function/class headers
438
438
  for file_path, errors in results.items():
439
439
  console.print(f"{NEW_LINE}{_cyan(file_path)}")
440
440
  for error in errors:
441
- # Split error message into individual errors for list mode
441
+ # Print the header line with line number, item type and name
442
+ if error.line_number > 0:
443
+ console.print(f" [red]Line {error.line_number}[/red] - {error.item_type} '{error.item_name}':")
444
+ else:
445
+ console.print(f" {_red('Error')} - {error.item_type} '{error.item_name}':")
446
+
447
+ # Split error message into individual errors and indent them
442
448
  if "; " in error.message:
443
449
  individual_errors = [msg.strip() for msg in error.message.split("; ") if msg.strip()]
444
450
  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}")
451
+ console.print(f" - {individual_error}")
452
452
  else:
453
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}")
454
+ console.print(f" - {error.message.strip()}")
461
455
 
462
456
  # Summary - more descriptive message
463
457
  if total_functions == 1:
@@ -924,6 +924,7 @@ class DocstringChecker:
924
924
  # Check each line in the docstring
925
925
  lines: list[str] = docstring.split("\n")
926
926
  current_section = None
927
+ type_line_indent = None # Track indentation of type definition lines
927
928
 
928
929
  for i, line in enumerate(lines):
929
930
  stripped_line: str = line.strip()
@@ -938,6 +939,7 @@ class DocstringChecker:
938
939
  current_section: Optional[SectionConfig] = next(
939
940
  (s for s in parentheses_sections if s.name.lower() == section_name), None
940
941
  )
942
+ type_line_indent = None # Reset for new section
941
943
  continue
942
944
 
943
945
  # Non-admonition sections - only match actual section headers, not indented content
@@ -955,6 +957,7 @@ class DocstringChecker:
955
957
  current_section = next(
956
958
  (s for s in parentheses_sections if s.name.lower() == section_name), None
957
959
  )
960
+ type_line_indent = None # Reset for new section
958
961
  continue
959
962
  # If it doesn't match a known section, fall through to content processing
960
963
 
@@ -962,6 +965,9 @@ class DocstringChecker:
962
965
  if current_section and stripped_line and not stripped_line.startswith(("!", "?", "#")):
963
966
  # Look for parameter/type definitions
964
967
  if ":" in stripped_line:
968
+ # Calculate current line indentation
969
+ current_indent = len(line) - len(line.lstrip())
970
+
965
971
  # Skip description lines that start with common description words
966
972
  description_prefixes = [
967
973
  "default:",
@@ -986,30 +992,65 @@ class DocstringChecker:
986
992
  ):
987
993
  continue
988
994
 
995
+ # For list_type sections, we need special handling
996
+ if current_section.type == "list_type":
997
+ # Check if this line has parentheses at the beginning
998
+ if re.search(r"^\s*\([^)]+\):", stripped_line):
999
+ # This is a valid type definition line, remember its indentation
1000
+ type_line_indent = current_indent
1001
+ continue
1002
+ else:
1003
+ # If no type definition has been found yet, allow lines with colons as possible descriptions
1004
+ if type_line_indent is None:
1005
+ continue
1006
+ # Check if this is a description line (more indented than type line)
1007
+ if current_indent > type_line_indent:
1008
+ # This is a description line, skip validation
1009
+ continue
1010
+ else:
1011
+ # This should be a type definition but doesn't have proper format
1012
+ errors.append(
1013
+ f"Section '{current_section.name}' (type: '{current_section.type}') requires "
1014
+ f"parenthesized types, see: '{stripped_line}'"
1015
+ )
989
1016
  # For list_name_and_type sections, check format like "name (type):" or "(type):"
990
- if current_section.type == "list_name_and_type":
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
- ):
1017
+ elif current_section.type == "list_name_and_type":
1018
+ # Check if this line has parentheses and looks like a parameter definition
1019
+ if re.search(r"\([^)]+\):", stripped_line):
1020
+ # This is a valid parameter definition line, remember its indentation
1021
+ type_line_indent = current_indent
998
1022
  continue
999
-
1000
- if not re.search(r"\([^)]+\):", stripped_line):
1001
- errors.append(
1002
- f"Section '{current_section.name}' (type: '{current_section.type}') requires "
1003
- f"parenthesized types, see: '{stripped_line}'"
1004
- )
1005
-
1006
- # For list_type sections, check format like "(Type):"
1007
- elif current_section.type == "list_type":
1008
- # Pattern: (Type):
1009
- if not re.search(r"^\s*\([^)]+\):", stripped_line):
1010
- errors.append(
1011
- f"Section '{current_section.name}' (type: '{current_section.type}') requires "
1012
- f"parenthesized types, see: '{stripped_line}'"
1013
- )
1023
+ else:
1024
+ # Check if this is likely a description line based on various criteria
1025
+ colon_part = stripped_line.split(":")[0].strip()
1026
+
1027
+ # Skip if it contains phrases that indicate it's a description, not a parameter
1028
+ if any(
1029
+ word in colon_part.lower()
1030
+ for word in ["default", "output", "format", "show", "example"]
1031
+ ):
1032
+ continue
1033
+
1034
+ # Skip if it starts with bullet points or list markers
1035
+ if stripped_line.strip().startswith(("-", "*", "•", "+")):
1036
+ continue
1037
+
1038
+ # If we have found a parameter definition, check if this is a description line
1039
+ if type_line_indent is not None:
1040
+ # Skip if this is more indented than the parameter definition (description line)
1041
+ if current_indent > type_line_indent:
1042
+ continue
1043
+
1044
+ # Skip if the line before the colon contains multiple words (likely description)
1045
+ words_before_colon = colon_part.split()
1046
+ if len(words_before_colon) > 2: # More than "param_name (type)"
1047
+ continue
1048
+
1049
+ # Only flag lines that could reasonably be parameter definitions
1050
+ if ":" in stripped_line and not stripped_line.strip().startswith("#"):
1051
+ errors.append(
1052
+ f"Section '{current_section.name}' (type: '{current_section.type}') requires "
1053
+ f"parenthesized types, see: '{stripped_line}'"
1054
+ )
1014
1055
 
1015
1056
  return errors