Extract Python API signatures and detect breaking changes for documentation generation.
—
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.
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."""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."""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."""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
"""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
"""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()))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))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")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()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]}")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 = ParametersInstall with Tessl CLI
npx tessl i tessl/pypi-griffe