CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-griffe

Extract Python API signatures and detect breaking changes for documentation generation.

Pending
Overview
Eval results
Files

agents.mddocs/

Agents

Analysis agents for extracting API information from Python code. Griffe provides two complementary approaches: static analysis through AST parsing (visit) and dynamic analysis through runtime inspection (inspect). These agents form the foundation of Griffe's code analysis capabilities.

Capabilities

Static Analysis (Visitor)

Parse and analyze Python source code using Abstract Syntax Tree (AST) parsing.

def visit(
    module: Module,
    filepath: str | Path,
    code: str | None = None,
    extensions: Extensions | None = None,
    parent: Module | None = None,
    in_try_block: bool = False,
) -> Module:
    """
    Parse and visit a module file using static analysis.
    
    Creates Griffe objects from AST nodes by parsing Python source code.
    This approach analyzes code structure without executing it, making it
    safe for analyzing any Python code.
    
    Args:
        module: Module object to populate with visited data
        filepath: Path to the Python file to analyze  
        code: Source code string (if None, reads from filepath)
        extensions: Extensions to apply during visiting
        parent: Parent module for submodule analysis
        in_try_block: Whether this module is in a try block
        
    Returns:
        Module: The populated module with analyzed contents
        
    Raises:
        LoadingError: If file cannot be read or parsed
        
    Examples:
        Visit a module file:
        >>> module = griffe.Module("mymodule")
        >>> visited = griffe.visit(module, "path/to/mymodule.py")
        
        Visit with custom code:
        >>> code = "def hello(): return 'world'"
        >>> visited = griffe.visit(module, "virtual.py", code=code)
    """

class Visitor:
    """
    AST visitor class that traverses Python source code.
    
    Creates Griffe objects from AST nodes by walking through
    the abstract syntax tree and extracting relevant information.
    """
    
    def __init__(
        self,
        module: Module,
        filepath: str | Path,
        code: str,
        extensions: Extensions | None = None,
        parent: Module | None = None,
        in_try_block: bool = False,
    ) -> None:
        """
        Initialize the visitor.
        
        Args:
            module: Module to populate
            filepath: Path to source file
            code: Source code to parse
            extensions: Extensions to apply
            parent: Parent module
            in_try_block: Whether in try block context
        """
    
    def visit(self) -> None:
        """
        Visit the module and populate it with objects.
        
        Parses the source code and creates appropriate Griffe objects
        for all discovered Python constructs.
        """
    
    def visit_module(self, node: ast.Module) -> None:
        """Visit a module AST node."""
    
    def visit_classdef(self, node: ast.ClassDef) -> None:
        """Visit a class definition AST node."""
    
    def visit_functiondef(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> None:
        """Visit a function definition AST node."""
    
    def visit_assign(self, node: ast.Assign) -> None:
        """Visit an assignment AST node."""
    
    def visit_annassign(self, node: ast.AnnAssign) -> None:
        """Visit an annotated assignment AST node."""

Dynamic Analysis (Inspector)

Inspect live Python objects at runtime to extract API information.

def inspect(
    module_name: str,
    filepath: str | Path | None = None,
    parent: Module | None = None,
) -> Module:
    """
    Inspect a module dynamically at runtime.
    
    Creates Griffe objects from live Python objects by importing
    and examining modules at runtime. This approach can access
    runtime-generated attributes and dynamic behavior.
    
    Args:
        module_name: Name of module to inspect
        filepath: Path to module file (optional)
        parent: Parent module for submodules
        
    Returns:
        Module: Module populated with inspected data
        
    Raises:
        UnimportableModuleError: If module cannot be imported
        
    Examples:
        Inspect an installed package:
        >>> module = griffe.inspect("requests")
        
        Inspect with specific filepath:
        >>> module = griffe.inspect("mymodule", filepath="path/to/mymodule.py")
    """

class Inspector:
    """
    Runtime inspector class that examines live Python objects.
    
    Creates Griffe representations by importing modules and
    using Python's introspection capabilities to extract information.
    """
    
    def __init__(
        self,
        module_name: str,
        filepath: str | Path | None = None,
        parent: Module | None = None,
    ) -> None:
        """
        Initialize the inspector.
        
        Args:
            module_name: Name of module to inspect
            filepath: Path to module file
            parent: Parent module
        """
    
    def inspect(self) -> Module:
        """
        Inspect the module and return populated Module object.
        
        Returns:
            Module: Module with inspected contents
        """
    
    def inspect_module(self, module: types.ModuleType) -> Module:
        """Inspect a module object."""
    
    def inspect_class(self, class_obj: type, parent: Module | Class) -> Class:
        """Inspect a class object."""
    
    def inspect_function(
        self, 
        func_obj: types.FunctionType | types.MethodType,
        parent: Module | Class
    ) -> Function:
        """Inspect a function or method object."""
    
    def inspect_attribute(
        self,
        name: str,
        value: Any,
        parent: Module | Class
    ) -> Attribute:
        """Inspect an attribute."""

Decorator Recognition

Built-in decorator sets that Griffe recognizes and handles specially.

builtin_decorators: set[str]
"""Set of built-in Python decorators recognized by Griffe."""

stdlib_decorators: set[str]  
"""Set of standard library decorators recognized by Griffe."""

typing_overload: str
"""Reference to typing.overload decorator for function overloads."""

AST Utilities

Helper functions for working with Abstract Syntax Tree nodes during static analysis.

def ast_children(node: ast.AST) -> Iterator[ast.AST]:
    """
    Get child nodes of an AST node.
    
    Args:
        node: AST node to examine
        
    Yields:
        ast.AST: Child nodes
    """

def ast_first_child(node: ast.AST) -> ast.AST | None:
    """
    Get the first child node of an AST node.
    
    Args:
        node: AST node to examine
        
    Returns:
        ast.AST | None: First child or None if no children
    """

def ast_last_child(node: ast.AST) -> ast.AST | None:
    """
    Get the last child node of an AST node.
    
    Args:
        node: AST node to examine
        
    Returns:
        ast.AST | None: Last child or None if no children
    """

def ast_next(node: ast.AST) -> ast.AST | None:
    """
    Get the next sibling of an AST node.
    
    Args:
        node: AST node to examine
        
    Returns:
        ast.AST | None: Next sibling or None
    """

def ast_previous(node: ast.AST) -> ast.AST | None:
    """
    Get the previous sibling of an AST node.
    
    Args:
        node: AST node to examine
        
    Returns:
        ast.AST | None: Previous sibling or None
    """

def ast_siblings(node: ast.AST) -> Iterator[ast.AST]:
    """
    Get all siblings of an AST node.
    
    Args:
        node: AST node to examine
        
    Yields:
        ast.AST: Sibling nodes
    """

Node Processing Functions

Functions for extracting specific information from AST nodes.

def get_docstring(node: ast.AST) -> str | None:
    """
    Extract docstring from an AST node.
    
    Args:
        node: AST node (function, class, or module)
        
    Returns:
        str | None: Docstring text or None if not found
    """

def get_parameters(node: ast.FunctionDef | ast.AsyncFunctionDef) -> Parameters:
    """
    Extract function parameters from an AST node.
    
    Args:
        node: Function definition AST node
        
    Returns:
        Parameters: Extracted parameters
    """

def get_name(node: ast.AST) -> str | None:
    """
    Get name from an assignment AST node.
    
    Args:
        node: Assignment AST node
        
    Returns:
        str | None: Variable name or None
    """

def get_names(node: ast.AST) -> list[str]:
    """
    Get multiple names from an assignment AST node.
    
    Args:
        node: Assignment AST node
        
    Returns:
        list[str]: List of variable names
    """

def get_value(node: ast.AST) -> Expr | None:
    """
    Extract value from an AST node as a Griffe expression.
    
    Args:
        node: AST node with value
        
    Returns:
        Expr | None: Griffe expression or None
    """

def safe_get_value(node: ast.AST) -> Expr | None:
    """
    Safely extract value from AST node, returns None on error.
    
    Args:
        node: AST node with value
        
    Returns:
        Expr | None: Griffe expression or None if extraction fails
    """

Usage Examples

Static Analysis with Visit

import griffe

# Create a module and visit source code
module = griffe.Module("mymodule")

# Visit from file
visited_module = griffe.visit(
    module=module,
    filepath="path/to/mymodule.py"
)

# Visit from code string
code = '''
def hello(name: str) -> str:
    """Say hello to someone."""
    return f"Hello, {name}!"

class Greeter:
    """A class for greeting."""
    
    def __init__(self, greeting: str = "Hello"):
        self.greeting = greeting
    
    def greet(self, name: str) -> str:
        return f"{self.greeting}, {name}!"
'''

visited_from_code = griffe.visit(
    module=griffe.Module("example"),
    filepath="example.py", 
    code=code
)

print("Functions:", list(visited_from_code.functions.keys()))
print("Classes:", list(visited_from_code.classes.keys()))

Dynamic Analysis with Inspect

import griffe

# Inspect installed packages
requests_module = griffe.inspect("requests")
print("Requests classes:", list(requests_module.classes.keys()))

# Inspect with error handling
try:
    custom_module = griffe.inspect("my_custom_module")
except griffe.UnimportableModuleError as e:
    print(f"Cannot import module: {e}")

# Compare static vs dynamic analysis
static_module = griffe.visit(
    griffe.Module("example"),
    "example.py"
)

dynamic_module = griffe.inspect("example")

print("Static analysis found:", len(static_module.functions))
print("Dynamic analysis found:", len(dynamic_module.functions))

Using Both Agents Together

import griffe

# Load using both agents (this is what load() does internally)
loader = griffe.GriffeLoader(allow_inspection=True)

# This will try static analysis first, fall back to inspection
module = loader.load("some_package")

# Manual combination
try:
    # Try static analysis first
    static_result = griffe.visit(
        griffe.Module("mypackage"),
        "path/to/mypackage/__init__.py"
    )
except Exception:
    # Fall back to dynamic analysis
    static_result = griffe.inspect("mypackage")

Working with Extensions

import griffe

# Load extensions for enhanced analysis
extensions = griffe.load_extensions(["dataclasses"])

# Use with visitor
module = griffe.Module("mymodule")
visited = griffe.visit(
    module=module,
    filepath="mymodule.py",
    extensions=extensions
)

# Custom visitor with extensions
visitor = griffe.Visitor(
    module=module,
    filepath="mymodule.py", 
    code=source_code,
    extensions=extensions
)
visitor.visit()

AST Analysis Utilities

import ast
import griffe

# Parse Python code
source = "def hello(): return 'world'"
tree = ast.parse(source)

# Use AST utilities
for node in griffe.ast_children(tree):
    if isinstance(node, ast.FunctionDef):
        print(f"Function: {node.name}")
        
        # Get function details
        docstring = griffe.get_docstring(node)
        parameters = griffe.get_parameters(node)
        
        print(f"  Docstring: {docstring}")
        print(f"  Parameters: {[p.name for p in parameters]}")

Types

import ast
import types
from pathlib import Path
from typing import Iterator, Any

# AST node types from Python's ast module
AST = ast.AST
Module = ast.Module
ClassDef = ast.ClassDef
FunctionDef = ast.FunctionDef
AsyncFunctionDef = ast.AsyncFunctionDef

# Runtime types from Python's types module  
ModuleType = types.ModuleType
FunctionType = types.FunctionType
MethodType = types.MethodType

# Griffe types
from griffe import Module, Class, Function, Attribute, Extensions, Parameters, Expr

# Parameter extraction type
ParametersType = Parameters

Install with Tessl CLI

npx tessl i tessl/pypi-griffe

docs

agents.md

breaking-changes.md

cli.md

docstrings.md

extensions.md

index.md

loaders.md

models.md

serialization.md

tile.json