CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pdoc

API Documentation for Python Projects with focus on simplicity and automatic HTML generation from docstrings

Pending
Overview
Eval results
Files

ast-processing.mddocs/

AST Processing and Source Analysis

Abstract syntax tree processing for extracting Python code structure, type annotations, and source code metadata. Provides deep analysis of Python source code to generate accurate documentation with proper type information and cross-references.

Capabilities

AST Parsing and Analysis

Parse Python objects and source code into abstract syntax trees for analysis.

def parse(obj: Any) -> ast.AST | None:
    """
    Parse Python object into abstract syntax tree.
    
    Parameters:
    - obj: Any - Python object to parse (module, class, function, etc.)
    
    Returns:
    - ast.AST | None: Parsed AST node, None if parsing fails
    
    Features:
    - Handles various Python object types
    - Preserves source location information
    - Robust error handling for unparseable objects
    """

def unparse(tree: ast.AST) -> str:
    """
    Convert AST back to Python source code.
    
    Parameters:
    - tree: ast.AST - AST node to convert
    
    Returns:
    - str: Python source code representation
    
    Features:
    - Preserves original formatting where possible
    - Handles complex expressions and statements
    - Compatible with various Python versions
    """

Source Code Extraction

Extract source code and metadata from Python objects.

def get_source(obj: Any) -> str | None:
    """
    Get source code for Python object.
    
    Parameters:
    - obj: Any - Python object to get source for
    
    Returns:
    - str | None: Source code string, None if unavailable
    
    Features:
    - Works with modules, classes, functions, methods
    - Handles dynamically created objects gracefully
    - Preserves indentation and formatting
    """

AST Tree Traversal

Traverse and analyze AST structures recursively.

def walk_tree(tree: ast.AST) -> Iterator[ast.AST]:
    """
    Walk AST tree recursively, yielding all nodes.
    
    Parameters:
    - tree: ast.AST - Root AST node to walk
    
    Yields:
    - ast.AST: Each AST node in depth-first order
    
    Features:
    - Depth-first traversal of entire tree
    - Handles all AST node types
    - Preserves parent-child relationships
    """

Source-Based Sorting

Sort documentation objects by their source code position.

def sort_by_source(items: list[Doc]) -> list[Doc]:
    """
    Sort documentation objects by source file position.
    
    Parameters:
    - items: list[Doc] - Documentation objects to sort
    
    Returns:
    - list[Doc]: Sorted list in source file order
    
    Features:
    - Maintains natural source code ordering
    - Handles objects from multiple files
    - Preserves relative positions within files
    """

Type Checking Analysis

Analyze TYPE_CHECKING blocks and conditional imports.

def type_checking_sections(tree: ast.AST) -> list[tuple[int, int]]:
    """
    Find TYPE_CHECKING conditional blocks in AST.
    
    Parameters:
    - tree: ast.AST - Module AST to analyze
    
    Returns:
    - list[tuple[int, int]]: List of (start_line, end_line) for TYPE_CHECKING blocks
    
    Features:
    - Identifies typing.TYPE_CHECKING conditions
    - Handles various conditional patterns
    - Supports forward reference resolution
    """

Data Structures

AST Information Container

Container for AST-related metadata and analysis results.

class AstInfo:
    """
    Container for AST information and metadata.
    
    Stores parsed AST data along with source location,
    type information, and analysis results.
    """
    pass

Usage Examples

Basic AST Analysis

from pdoc.doc_ast import parse, get_source, unparse
import ast

def analyze_function(func):
    """Analyze a function's AST structure"""
    
    # Get source code
    source = get_source(func)
    if source:
        print(f"Source code:\n{source}")
    
    # Parse into AST
    tree = parse(func)
    if tree:
        print(f"AST type: {type(tree).__name__}")
        
        # Convert back to source
        reconstructed = unparse(tree)
        print(f"Reconstructed:\n{reconstructed}")

# Example usage
def example_function(x: int, y: str = "default") -> bool:
    """Example function for AST analysis."""
    return len(y) > x

analyze_function(example_function)

AST Tree Walking

from pdoc.doc_ast import parse, walk_tree
import ast

def analyze_ast_structure(obj):
    """Walk through AST and analyze structure"""
    
    tree = parse(obj)
    if not tree:
        return
        
    node_counts = {}
    for node in walk_tree(tree):
        node_type = type(node).__name__
        node_counts[node_type] = node_counts.get(node_type, 0) + 1
        
        # Print function definitions
        if isinstance(node, ast.FunctionDef):
            print(f"Function: {node.name}")
            print(f"  Args: {len(node.args.args)}")
            print(f"  Line: {node.lineno}")
        
        # Print class definitions
        elif isinstance(node, ast.ClassDef):
            print(f"Class: {node.name}")
            print(f"  Bases: {len(node.bases)}")
            print(f"  Line: {node.lineno}")
    
    print(f"\nAST node counts: {node_counts}")

# Example usage
class ExampleClass:
    def method1(self, x: int) -> str:
        return str(x)
    
    def method2(self, y: list) -> int:
        return len(y)

analyze_ast_structure(ExampleClass)

Source Code Ordering

from pdoc.doc_ast import sort_by_source
from pdoc.doc import Module

def display_source_order(module_name: str):
    """Display module members in source file order"""
    
    module = Module.from_name(module_name)
    
    # Get all members as list
    members = list(module.members.values())
    
    # Sort by source position
    sorted_members = sort_by_source(members)
    
    print(f"Members of {module_name} in source order:")
    for member in sorted_members:
        print(f"  {member.name} ({type(member).__name__})")

# Example usage
display_source_order("math")

Type Checking Analysis

from pdoc.doc_ast import type_checking_sections, parse
import ast

def analyze_type_checking(module_source: str):
    """Analyze TYPE_CHECKING blocks in module source"""
    
    # Parse module source
    tree = ast.parse(module_source)
    
    # Find TYPE_CHECKING sections
    sections = type_checking_sections(tree)
    
    if sections:
        print("TYPE_CHECKING blocks found:")
        for start, end in sections:
            print(f"  Lines {start}-{end}")
            
            # Extract the conditional block
            lines = module_source.split('\n')
            block_lines = lines[start-1:end]
            print("  Content:")
            for line in block_lines:
                print(f"    {line}")
    else:
        print("No TYPE_CHECKING blocks found")

# Example module source with TYPE_CHECKING
example_source = '''
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from collections.abc import Sequence
    from typing import Optional

def process_data(items):
    return len(items)
'''

analyze_type_checking(example_source)

Advanced AST Processing

from pdoc.doc_ast import parse, walk_tree, get_source
import ast

class DocstringExtractor(ast.NodeVisitor):
    """Custom AST visitor to extract docstrings"""
    
    def __init__(self):
        self.docstrings = {}
    
    def visit_FunctionDef(self, node):
        """Visit function definitions and extract docstrings"""
        docstring = ast.get_docstring(node)
        if docstring:
            self.docstrings[node.name] = docstring
        self.generic_visit(node)
    
    def visit_ClassDef(self, node):
        """Visit class definitions and extract docstrings"""
        docstring = ast.get_docstring(node)
        if docstring:
            self.docstrings[node.name] = docstring
        self.generic_visit(node)

def extract_all_docstrings(obj):
    """Extract all docstrings from Python object"""
    
    source = get_source(obj)
    if not source:
        return {}
        
    tree = ast.parse(source)
    extractor = DocstringExtractor()
    extractor.visit(tree)
    
    return extractor.docstrings

# Example usage
class Example:
    """Class docstring"""
    
    def method(self):
        """Method docstring"""
        pass

docstrings = extract_all_docstrings(Example)
for name, doc in docstrings.items():
    print(f"{name}: {doc}")

Integration with Documentation Generation

from pdoc.doc_ast import parse, sort_by_source, get_source
from pdoc.doc import Module, Function, Class

def enhanced_module_analysis(module_name: str):
    """Enhanced module analysis using AST processing"""
    
    module = Module.from_name(module_name)
    
    # Sort members by source order
    sorted_members = sort_by_source(list(module.members.values()))
    
    print(f"Analysis of {module_name}:")
    
    for member in sorted_members:
        print(f"\n{member.name} ({type(member).__name__}):")
        
        # Get source code
        source = get_source(member.obj)
        if source:
            lines = len(source.split('\n'))
            print(f"  Source lines: {lines}")
        
        # Parse AST for additional analysis
        tree = parse(member.obj)
        if tree:
            if isinstance(member, Function) and isinstance(tree, ast.FunctionDef):
                print(f"  Parameters: {len(tree.args.args)}")
                print(f"  Has return annotation: {tree.returns is not None}")
            elif isinstance(member, Class) and isinstance(tree, ast.ClassDef):
                print(f"  Base classes: {len(tree.bases)}")
                methods = [n for n in tree.body if isinstance(n, ast.FunctionDef)]
                print(f"  Methods: {len(methods)}")

# Example usage
enhanced_module_analysis("json")

Error Handling

The AST processing system handles various error conditions gracefully:

  • Unparseable source: Returns None for objects without accessible source
  • Syntax errors: Catches and logs parsing errors without crashing
  • Missing files: Handles cases where source files are not available
  • Dynamic objects: Gracefully handles runtime-created objects
  • Encoding issues: Robust handling of various source file encodings

Install with Tessl CLI

npx tessl i tessl/pypi-pdoc

docs

ast-processing.md

cli-interface.md

doc-objects.md

docstring-processing.md

html-rendering.md

index.md

main-api.md

module-extraction.md

search.md

web-server.md

tile.json