A Python docstring linter that checks arguments, returns, yields, and raises sections
—
Comprehensive set of utility classes and functions for programmatic docstring analysis, AST processing, and argument handling.
Classes for representing and manipulating function arguments from both AST nodes and docstring parameters.
class Arg:
"""
Represents a function argument with name and type hint information.
Provides methods for comparing arguments and checking type hint presence,
with factory methods for creating from different sources.
"""
name: str
typeHint: str
def __init__(self, name: str, typeHint: str) -> None:
"""
Initialize argument with name and type hint.
Parameters:
- name: Argument name
- typeHint: Type hint string (empty string if no type hint)
"""
def nameEquals(self, other: 'Arg') -> bool:
"""
Check if argument names are equal.
Parameters:
- other: Another Arg object to compare with
Returns:
bool: True if names match
"""
def hasTypeHint(self) -> bool:
"""
Check if argument has a type hint.
Returns:
bool: True if type hint is present and non-empty
"""
def isStarArg(self) -> bool:
"""
Check if this is a star argument (*args or **kwargs).
Returns:
bool: True if argument name starts with * or **
"""
def notStarArg(self) -> bool:
"""
Check if this is not a star argument.
Returns:
bool: True if argument name doesn't start with * or **
"""
@classmethod
def fromDocstringParam(cls, param: DocstringParam) -> 'Arg':
"""
Create Arg from docstring parameter.
Parameters:
- param: Docstring parameter object
Returns:
Arg: New argument object
"""
@classmethod
def fromDocstringAttr(cls, attr: DocstringAttr) -> 'Arg':
"""
Create Arg from docstring attribute.
Parameters:
- attr: Docstring attribute object
Returns:
Arg: New argument object representing class attribute
"""
@classmethod
def fromAstArg(cls, astArg: ast.arg) -> 'Arg':
"""
Create Arg from AST argument node.
Parameters:
- astArg: AST argument node
Returns:
Arg: New argument object
"""
class ArgList:
"""
Container for multiple Arg objects with list-like operations.
Provides methods for comparing argument lists, filtering, and
various operations needed for docstring validation.
"""
infoList: list[Arg]
def __init__(self, infoList: list[Arg]) -> None:
"""
Initialize argument list.
Parameters:
- infoList: List of Arg objects
"""
@classmethod
def fromDocstringParam(cls, params: list[DocstringParam]) -> 'ArgList':
"""
Create ArgList from docstring parameters.
Parameters:
- params: List of docstring parameter objects
Returns:
ArgList: New argument list
"""
@classmethod
def fromDocstringAttr(cls, attrs: list[DocstringAttr]) -> 'ArgList':
"""
Create ArgList from docstring attributes.
Parameters:
- attrs: List of docstring attribute objects
Returns:
ArgList: New argument list for class attributes
"""
def noTypeHints(self) -> bool:
"""
Check if no arguments have type hints.
Returns:
bool: True if no arguments have type hints
"""
def notAllArgsHaveTypeHints(self) -> bool:
"""
Check if not all arguments have type hints.
Returns:
bool: True if some arguments lack type hints
"""
def exists(self) -> bool:
"""
Check if argument list is not empty.
Returns:
bool: True if list contains arguments
"""
def length(self) -> int:
"""
Get number of arguments.
Returns:
int: Number of arguments in list
"""
def equals(self, other: 'ArgList') -> bool:
"""
Check if two argument lists have same names.
Parameters:
- other: Another ArgList to compare
Returns:
bool: True if argument names match
"""
def subtract(self, other: 'ArgList') -> 'ArgList':
"""
Subtract another argument list from this one.
Parameters:
- other: ArgList to subtract
Returns:
ArgList: New list with arguments not in other list
"""Class for parsing and representing docstring content with style-aware parsing.
class Doc:
"""
Represents a parsed docstring with style-aware section extraction.
Parses docstrings in numpy, google, or sphinx style and provides
access to different sections like arguments, returns, yields, etc.
"""
def __init__(self, docstring: str, style: str = 'numpy') -> None:
"""
Initialize docstring parser.
Parameters:
- docstring: Raw docstring text
- style: Docstring style ('numpy', 'google', 'sphinx')
"""
@property
def isShortDocstring(self) -> bool:
"""
Check if docstring contains only a short summary.
Returns:
bool: True if docstring has no parameter/return sections
"""
@property
def argList(self) -> ArgList:
"""
Get argument list from docstring parameters section.
Returns:
ArgList: Arguments documented in docstring
"""
@property
def attrList(self) -> ArgList:
"""
Get attribute list from docstring attributes section.
Returns:
ArgList: Class attributes documented in docstring
"""
@property
def hasReturnsSection(self) -> bool:
"""
Check if docstring has a returns section.
Returns:
bool: True if returns section is present
"""
@property
def hasYieldsSection(self) -> bool:
"""
Check if docstring has a yields section.
Returns:
bool: True if yields section is present
"""
@property
def hasRaisesSection(self) -> bool:
"""
Check if docstring has a raises section.
Returns:
bool: True if raises section is present
"""
@property
def returns(self) -> list[DocstringParam]:
"""
Get returns section parameters.
Returns:
list[DocstringParam]: Return value documentation
"""
@property
def yields(self) -> list[DocstringParam]:
"""
Get yields section parameters.
Returns:
list[DocstringParam]: Yield value documentation
"""
@property
def raises(self) -> list[DocstringParam]:
"""
Get raises section parameters.
Returns:
list[DocstringParam]: Exception documentation
"""Data classes for representing return and yield information.
@dataclass
class ReturnArg:
"""
Represents return value information from docstring or annotation.
Contains type information and description for function return values.
"""
type: str
description: str
def __post_init__(self) -> None:
"""Post-initialization processing."""
@dataclass
class YieldArg:
"""
Represents yield value information from docstring or annotation.
Contains type information and description for generator yield values.
"""
type: str
description: str
def __post_init__(self) -> None:
"""Post-initialization processing."""Functions for analyzing AST nodes to extract return, yield, and raise information.
def hasReturnAnnotation(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if function has return type annotation.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if return annotation is present
"""
def isReturnAnnotationNone(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if return annotation is None.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if return annotation is None
"""
def isReturnAnnotationNoReturn(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if return annotation is NoReturn.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if return annotation is NoReturn
"""
def hasGeneratorAsReturnAnnotation(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if return annotation is a Generator type.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if return annotation indicates generator
"""
def hasIteratorOrIterableAsReturnAnnotation(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if return annotation is Iterator or Iterable.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if return annotation is Iterator/Iterable
"""
def hasYieldStatements(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if function contains yield statements.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if function yields values
"""
def hasReturnStatements(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if function contains return statements.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if function has return statements
"""
def hasBareReturnStatements(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if function contains bare return statements (return without value).
Parameters:
- node: Function or async function AST node
Returns:
bool: True if function has bare return statements
"""
def hasRaiseStatements(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if function contains raise statements.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if function raises exceptions
"""
def hasAssertStatements(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if function contains assert statements.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if function has assert statements
"""
def getRaisedExceptions(node: FuncOrAsyncFuncDef) -> list[str]:
"""
Get list of exceptions raised by function.
Parameters:
- node: Function or async function AST node
Returns:
list[str]: Names of exceptions that may be raised
"""Functions for detecting special method types and decorators.
def checkIsAbstractMethod(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if method is decorated with @abstractmethod.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if method is abstract
"""
def checkIsPropertyMethod(node: FuncOrAsyncFuncDef) -> bool:
"""
Check if method is decorated with @property.
Parameters:
- node: Function or async function AST node
Returns:
bool: True if method is a property
"""
def checkMethodContainsSpecifiedDecorator(
node: FuncOrAsyncFuncDef,
decorator_name: str
) -> bool:
"""
Check if method has specific decorator.
Parameters:
- node: Function or async function AST node
- decorator_name: Name of decorator to check for
Returns:
bool: True if decorator is present
"""Functions for parsing docstrings in different styles.
def parseDocstring(
docstring: str,
style: str,
filename: str = '<unknown>',
lineNum: int = 0
) -> Doc | None:
"""
Parse docstring with error handling.
Parameters:
- docstring: Raw docstring text
- style: Docstring style ('numpy', 'google', 'sphinx')
- filename: Source filename for error reporting
- lineNum: Line number for error reporting
Returns:
Doc | None: Parsed docstring object, or None if parsing fails
"""
def parseDocstringInGivenStyle(docstring: str, style: str) -> Doc | None:
"""
Parse docstring in specific style without error handling.
Parameters:
- docstring: Raw docstring text
- style: Docstring style to use
Returns:
Doc | None: Parsed docstring object, or None if parsing fails
"""Core utility functions for AST processing and string manipulation.
def collectFuncArgs(node: FuncOrAsyncFuncDef) -> list[ast.arg]:
"""
Collect all function arguments from AST node.
Parameters:
- node: Function or async function AST node
Returns:
list[ast.arg]: All function arguments
"""
def getFunctionId(node: FuncOrAsyncFuncDef) -> tuple[int, int, str]:
"""
Get function identifier information.
Parameters:
- node: Function or async function AST node
Returns:
tuple containing:
- int: Line number
- int: Column offset
- str: Function name
"""
def detectMethodType(node: FuncOrAsyncFuncDef) -> MethodType:
"""
Detect the type of method (function, method, classmethod, etc.).
Parameters:
- node: Function or async function AST node
Returns:
MethodType: Detected method type
"""
def getDocstring(node: ClassOrFunctionDef) -> str:
"""
Extract docstring from class or function node.
Parameters:
- node: Class or function definition AST node
Returns:
str: Docstring text, or empty string if none
"""
def getNodeName(node: ast.AST) -> str:
"""
Get name from AST node.
Parameters:
- node: AST node
Returns:
str: Node name if available, otherwise empty string
"""
def stripQuotes(string: str | None) -> str | None:
"""
Remove surrounding quotes from string.
Parameters:
- string: String that may have quotes
Returns:
str | None: String without quotes, or None if input is None
"""
def specialEqual(str1: str, str2: str) -> bool:
"""
Special equality check for type hints and arguments.
Parameters:
- str1: First string to compare
- str2: Second string to compare
Returns:
bool: True if strings are considered equal
"""
def stripCommentsFromTypeHints(typeHint: str) -> str:
"""
Remove comments from type hint strings.
Parameters:
- typeHint: Type hint string that may contain comments
Returns:
str: Type hint with comments removed
"""class EdgeCaseError(Exception):
"""
Exception raised for edge cases in docstring analysis.
Used to handle unusual or unexpected scenarios during
AST analysis and docstring parsing.
"""
passimport ast
from pydoclint.utils.arg import Arg, ArgList
from pydoclint.utils.generic import collectFuncArgs
# Parse function and analyze arguments
source = '''
def example_func(x: int, y: str = "default", *args, **kwargs) -> bool:
"""Example function."""
return True
'''
tree = ast.parse(source)
func_node = tree.body[0]
# Get AST arguments
ast_args = collectFuncArgs(func_node)
# Create Arg objects
args = [Arg.fromAstArg(arg) for arg in ast_args]
arg_list = ArgList(args)
print(f"Function has {arg_list.length()} arguments")
print(f"All have type hints: {not arg_list.notAllArgsHaveTypeHints()}")
# Check individual arguments
for arg in args:
print(f"Arg '{arg.name}': type hint = '{arg.typeHint}', is star = {arg.isStarArg()}")from pydoclint.utils.parse_docstring import parseDocstring
from pydoclint.utils.doc import Doc
docstring = '''
Example function.
Parameters
----------
x : int
First parameter
y : str
Second parameter
Returns
-------
bool
Success flag
'''
# Parse docstring
doc = parseDocstring(docstring, "numpy")
if doc:
print(f"Is short docstring: {doc.isShortDocstring}")
print(f"Has returns section: {doc.hasReturnsSection}")
print(f"Arguments: {[arg.name for arg in doc.argList.infoList]}")
# Compare with function signature
# ... validation logic herefrom pydoclint.utils.return_yield_raise import (
hasReturnAnnotation, hasYieldStatements, hasRaiseStatements
)
# Analyze function characteristics
if hasReturnAnnotation(func_node):
print("Function has return annotation")
if hasYieldStatements(func_node):
print("Function is a generator")
if hasRaiseStatements(func_node):
exceptions = getRaisedExceptions(func_node)
print(f"Function may raise: {exceptions}")# Union types for AST nodes
FuncOrAsyncFuncDef = Union[ast.FunctionDef, ast.AsyncFunctionDef]
ClassOrFunctionDef = Union[ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef]
# Method type enumeration
class MethodType(Enum):
FUNCTION = "function"
METHOD = "method"
CLASSMETHOD = "classmethod"
STATICMETHOD = "staticmethod"
PROPERTY = "property"
# Docstring parsing types from docstring_parser_fork
DocstringParam = Any # Parameter from parsed docstring
DocstringAttr = Any # Attribute from parsed docstringInstall with Tessl CLI
npx tessl i tessl/pypi-pydoclint