CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pydoclint

A Python docstring linter that checks arguments, returns, yields, and raises sections

Pending
Overview
Eval results
Files

violations.mddocs/

Violation System

Comprehensive violation reporting system with specific error codes (DOC0xx-DOC6xx) covering all categories of docstring issues, from formatting to argument mismatches.

Capabilities

Violation Class

Core class representing individual docstring violations with detailed error information.

class Violation:
    """
    Represents a docstring violation with detailed error information.
    
    Provides comprehensive violation reporting including error codes,
    line numbers, and formatted messages for both CLI and flake8 output.
    """
    
    code: int  # Violation code number (1-6xx range)
    line: int  # Line number where violation occurs
    msg: str  # Complete violation message
    msgPostfix: str  # Additional message content
    
    def __init__(
        self,
        line: int,
        code: int,
        msgPrefix: str = '',
        msgPostfix: str = '',
    ) -> None:
        """
        Initialize violation with error details.
        
        Parameters:
        - line: Line number of violation (0 for file-level issues)
        - code: Violation code number
        - msgPrefix: Prefix for violation message (deprecated)
        - msgPostfix: Additional information to append to standard message
        """

    @property
    def fullErrorCode(self) -> str:
        """
        Get full error code with DOC prefix.
        
        Returns:
        str: Full error code (e.g., "DOC101", "DOC201")
        """

    def getInfoForFlake8(self) -> tuple[int, int, str]:
        """
        Format violation information for flake8 output.
        
        Returns:
        tuple containing:
        - int: Line number
        - int: Column offset (always 0)
        - str: Formatted error message with DOC code
        """

    def __str__(self) -> str:
        """
        String representation of violation.
        
        Returns:
        str: Formatted violation message
        """

Violation Codes Reference

Complete mapping of violation codes to their standard error messages.

VIOLATION_CODES: dict[int, str] = {
    # General and formatting issues (DOC0xx)
    1: "Potential formatting errors in docstring. Error message:",
    2: "Syntax errors; cannot parse this Python file. Error message:",
    3: "Docstring style mismatch. (Please read more at https://jsh9.github.io/pydoclint/style_mismatch.html ).",
    
    # Argument-related violations (DOC1xx)
    101: "Docstring contains fewer arguments than in function signature.",
    102: "Docstring contains more arguments than in function signature.",
    103: "Docstring arguments are different from function arguments. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ).",
    104: "Arguments are the same in the docstring and the function signature, but are in a different order.",
    105: "Argument names match, but type hints in these args do not match:",
    106: "The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature",
    107: "The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints",
    108: "The option `--arg-type-hints-in-signature` is `False` but there are argument type hints in the signature",
    109: "The option `--arg-type-hints-in-docstring` is `True` but there are no type hints in the docstring arg list",
    110: "The option `--arg-type-hints-in-docstring` is `True` but not all args in the docstring arg list have type hints",
    111: "The option `--arg-type-hints-in-docstring` is `False` but there are type hints in the docstring arg list",
    
    # Return-related violations (DOC2xx)
    201: "does not have a return section in docstring",
    202: "has a return section in docstring, but there are no return statements or annotations",
    203: "return type(s) in docstring not consistent with the return annotation.",
    
    # Class and __init__ violations (DOC3xx)
    301: "__init__() should not have a docstring; please combine it with the docstring of the class",
    302: "The class docstring does not need a \"Returns\" section, because __init__() cannot return anything",
    303: "The __init__() docstring does not need a \"Returns\" section, because it cannot return anything",
    304: "Class docstring has an argument/parameter section; please put it in the __init__() docstring",
    305: "Class docstring has a \"Raises\" section; please put it in the __init__() docstring",
    306: "The class docstring does not need a \"Yields\" section, because __init__() cannot yield anything",
    307: "The __init__() docstring does not need a \"Yields\" section, because __init__() cannot yield anything",
    
    # Yield-related violations (DOC4xx)
    402: "has \"yield\" statements, but the docstring does not have a \"Yields\" section",
    403: "has a \"Yields\" section in the docstring, but there are no \"yield\" statements, or the return annotation is not a Generator/Iterator/Iterable. (Or it could be because the function lacks a return annotation.)",
    404: "yield type(s) in docstring not consistent with the return annotation.",
    405: "has both \"return\" and \"yield\" statements. Please use Generator[YieldType, SendType, ReturnType] as the return type annotation, and put your yield type in YieldType and return type in ReturnType. More details in https://jsh9.github.io/pydoclint/notes_generator_vs_iterator.html",
    
    # Raises-related violations (DOC5xx)
    501: "has raise statements, but the docstring does not have a \"Raises\" section",
    502: "has a \"Raises\" section in the docstring, but there are not \"raise\" statements in the body",
    503: "exceptions in the \"Raises\" section in the docstring do not match those in the function body.",
    504: "has assert statements, but the docstring does not have a \"Raises\" section. (Assert statements could raise \"AssertError\".)",
    
    # Class attribute violations (DOC6xx)
    601: "Class docstring contains fewer class attributes than actual class attributes.",
    602: "Class docstring contains more class attributes than in actual class attributes.",
    603: "Class docstring attributes are different from actual class attributes. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ).",
    604: "Attributes are the same in docstring and class def, but are in a different order",
    605: "Attribute names match, but type hints in these attributes do not match",
}

Usage Examples

Creating and Using Violations

from pydoclint.utils.violation import Violation, VIOLATION_CODES

# Create a violation for missing arguments
violation = Violation(
    code=101,
    line=15,
    msgPostfix="Missing arguments: x, y"
)

print(violation.fullErrorCode)  # "DOC101"
print(str(violation))  # Full formatted message
print(violation.getInfoForFlake8())  # (15, 0, "DOC101: Docstring contains fewer arguments...")

# Check violation code meaning
print(VIOLATION_CODES[101])  # "Docstring contains fewer arguments than in function signature."

Processing Violations from Analysis

from pydoclint.main import _checkFile
from pathlib import Path

# Analyze file and process violations
violations = _checkFile(Path("example.py"), style="numpy")

for violation in violations:
    print(f"Line {violation.line}: {violation.fullErrorCode}")
    print(f"  {violation.msg}")
    
    # Handle specific violation types
    if violation.code in [101, 102, 103]:
        print("  -> Argument mismatch issue")
    elif violation.code in [201, 202, 203]:
        print("  -> Return section issue")
    elif violation.code in [402, 403, 404]:
        print("  -> Yield section issue")

Filtering and Categorizing Violations

def categorize_violations(violations: list[Violation]) -> dict[str, list[Violation]]:
    """Categorize violations by type."""
    categories = {
        "general": [],      # DOC001-DOC003
        "arguments": [],    # DOC101-DOC111
        "returns": [],      # DOC201-DOC203
        "class_init": [],   # DOC301-DOC307
        "yields": [],       # DOC402-DOC405
        "raises": [],       # DOC501-DOC502
        "class_attrs": [],  # DOC601-DOC603
    }
    
    for violation in violations:
        if 1 <= violation.code <= 3:
            categories["general"].append(violation)
        elif 101 <= violation.code <= 111:
            categories["arguments"].append(violation)
        elif 201 <= violation.code <= 203:
            categories["returns"].append(violation)
        elif 301 <= violation.code <= 307:
            categories["class_init"].append(violation)
        elif 402 <= violation.code <= 405:
            categories["yields"].append(violation)
        elif 501 <= violation.code <= 502:
            categories["raises"].append(violation)
        elif 601 <= violation.code <= 603:
            categories["class_attrs"].append(violation)
    
    return categories

# Usage
violations = _checkFile(Path("example.py"))
categorized = categorize_violations(violations)

print(f"Argument issues: {len(categorized['arguments'])}")
print(f"Return issues: {len(categorized['returns'])}")

Custom Violation Processing

class ViolationProcessor:
    """Process and format violations for different outputs."""
    
    def __init__(self, show_filenames: bool = False):
        self.show_filenames = show_filenames
    
    def format_for_console(self, filename: str, violations: list[Violation]) -> str:
        """Format violations for console output."""
        if not violations:
            return ""
        
        output = []
        if not self.show_filenames:
            output.append(f"{filename}:")
        
        for violation in violations:
            prefix = f"{filename}:" if self.show_filenames else "    "
            output.append(f"{prefix}{violation.line}: {violation.fullErrorCode}: {violation.msg}")
        
        return "\n".join(output)
    
    def format_for_json(self, filename: str, violations: list[Violation]) -> dict:
        """Format violations for JSON output."""
        return {
            "file": filename,
            "violations": [
                {
                    "line": v.line,
                    "code": v.fullErrorCode,
                    "message": v.msg,
                    "severity": self._get_severity(v.code)
                }
                for v in violations
            ]
        }
    
    def _get_severity(self, code: int) -> str:
        """Determine violation severity."""
        if code in [1, 2]:
            return "error"
        elif code in [101, 102, 201, 402, 501]:
            return "warning"
        else:
            return "info"

# Usage
processor = ViolationProcessor(show_filenames=True)
violations = _checkFile(Path("example.py"))

# Console output
console_output = processor.format_for_console("example.py", violations)
print(console_output)

# JSON output
json_output = processor.format_for_json("example.py", violations)
import json
print(json.dumps(json_output, indent=2))

Violation Code Categories

General Issues (DOC001-DOC003)

  • DOC001: Docstring parsing/formatting errors
  • DOC002: Python syntax errors preventing analysis
  • DOC003: Docstring style mismatch (e.g., Google style in numpy-configured project)

Argument Issues (DOC101-DOC111)

  • DOC101-DOC104: Argument count and order mismatches
  • DOC105: Type hint inconsistencies
  • DOC106-DOC111: Type hint presence/absence violations

Return Issues (DOC201-DOC203)

  • DOC201: Missing return section
  • DOC202: Unnecessary return section
  • DOC203: Return type inconsistencies

Class and Init Issues (DOC301-DOC307)

  • DOC301: Improper init docstring placement
  • DOC302-DOC303: Inappropriate return sections in class/init
  • DOC304-DOC305: Misplaced argument/raises sections
  • DOC306-DOC307: Inappropriate yields sections

Yield Issues (DOC402-DOC405)

  • DOC402: Missing yields section for generators
  • DOC403: Unnecessary yields section
  • DOC404: Yield type inconsistencies
  • DOC405: Mixed return/yield usage

Raises Issues (DOC501-DOC502)

  • DOC501: Missing raises section
  • DOC502: Unnecessary raises section

Class Attribute Issues (DOC601-DOC603)

  • DOC601-DOC603: Class attribute documentation mismatches

Install with Tessl CLI

npx tessl i tessl/pypi-pydoclint

docs

baseline.md

cli.md

configuration.md

core-analysis.md

flake8-plugin.md

index.md

utility-apis.md

violations.md

tile.json