Create Python API documentation in Markdown format
—
Helper functions and classes for common operations including docspec manipulation, template processing, file watching, and page management.
Functions for working with docspec objects and API analysis.
def get_members_of_type(objs: Union[docspec.ApiObject, List[docspec.ApiObject]], type_: Type[T]) -> List[T]:
"""
Get all members of specified type from API objects.
Args:
objs: Single API object or list of API objects to search
type_: Type to filter for (e.g., docspec.Function, docspec.Class)
Returns:
List of objects matching the specified type
"""
def format_function_signature(func: docspec.Function, exclude_self: bool = False) -> str:
"""
Format function signature with arguments and return type.
Args:
func: Function object to format
exclude_self: Whether to exclude 'self' parameter from signature
Returns:
Formatted signature string like "(arg1, arg2) -> ReturnType"
"""
def is_function(obj: docspec.ApiObject) -> TypeGuard[docspec.Function]:
"""
Type guard to check if object is a function.
Args:
obj: API object to check
Returns:
True if object is a docspec.Function
"""
def is_method(obj: docspec.ApiObject) -> TypeGuard[docspec.Function]:
"""
Type guard to check if object is a method (function inside a class).
Args:
obj: API object to check
Returns:
True if object is a method
"""
def is_property(obj: docspec.ApiObject) -> TypeGuard[docspec.Function]:
"""
Type guard to check if object is a property (function with @property decorator).
Args:
obj: API object to check
Returns:
True if object is a property
"""
def is_attr(obj: docspec.ApiObject) -> TypeGuard[docspec.Variable]:
"""
Type guard to check if object is a class attribute.
Args:
obj: API object to check
Returns:
True if object is a class attribute
"""
def get_object_description(obj: docspec.ApiObject) -> str:
"""
Get descriptive text for an API object.
Args:
obj: API object to describe
Returns:
Description like "module", "class", "function", "method", etc.
"""Wrapper class for working with collections of API objects.
class ApiSuite:
"""
Wrapper for API object collections with utility methods.
Provides convenient access to docspec objects with type filtering,
relationship analysis, and other collection operations.
"""
def get_members_of_type(self, type_: Type[T]) -> List[T]:
"""
Get all members of specified type from the suite.
Args:
type_: Type to filter for
Returns:
List of objects matching the specified type
"""YAML template loading with variable substitution.
def load(filename: str, context: Dict[str, Any]) -> Any:
"""
Load YAML template file with variable substitution.
Args:
filename: Path to YAML template file
context: Dictionary of variables for substitution
Returns:
Parsed YAML data with variables substituted
"""
class Attributor:
"""
Attribute accessor for template variables.
Provides dot-notation access to dictionary data for use in templates.
"""
def __init__(self, data: Dict[str, Any]):
"""
Initialize with data dictionary.
Args:
data: Dictionary to provide attribute access for
"""
def __getattr__(self, name: str) -> Any:
"""
Get attribute value from underlying data.
Args:
name: Attribute name to access
Returns:
Value from data dictionary
Raises:
AttributeError: If attribute not found
"""File system monitoring for development workflows.
def watch_paths(paths: List[str]) -> Tuple[Observer, Event]:
"""
Set up file system watching for specified paths.
Args:
paths: List of file/directory paths to watch for changes
Returns:
Tuple of (Observer, Event) where Event is set when changes occur
"""Utilities for managing documentation pages and collections.
def collect_pages(directory: str, pattern: str = "*.md") -> List[str]:
"""
Collect documentation pages from directory.
Args:
directory: Directory to search for pages
pattern: File pattern to match (default: "*.md")
Returns:
List of page file paths
"""Text processing utilities for Markdown generation.
def escape_except_blockquotes(text: str) -> str:
"""
Escape Markdown special characters except in blockquotes.
Args:
text: Text to escape
Returns:
Text with Markdown characters escaped appropriately
"""Additional utility functions for common operations.
def dotted_name(obj: docspec.ApiObject) -> str:
"""
Get fully qualified dotted name for an API object.
Args:
obj: API object to get name for
Returns:
Dotted name like "module.Class.method"
"""from pydoc_markdown.util.docspec import get_members_of_type, is_method, format_function_signature
import docspec
# Get all functions from modules
modules = config.load_modules()
all_functions = get_members_of_type(modules, docspec.Function)
# Filter for methods only
methods = [f for f in all_functions if is_method(f)]
# Format signatures
for method in methods:
signature = format_function_signature(method, exclude_self=True)
print(f"{method.name}{signature}")from pydoc_markdown.util.docspec import is_function, is_method, is_property, is_attr
for obj in module.members:
if is_function(obj):
if is_method(obj):
print(f"Method: {obj.name}")
elif is_property(obj):
print(f"Property: {obj.name}")
else:
print(f"Function: {obj.name}")
elif is_attr(obj):
print(f"Attribute: {obj.name}")from pydoc_markdown.util.ytemplate import load, Attributor
import os
# Load template with environment variables
context = {"env": Attributor(os.environ)}
config_data = load("pydoc-markdown.yml.template", context)
# Template file might contain:
# loaders:
# - type: python
# modules: ["{{ env.PACKAGE_NAME }}"]from pydoc_markdown.util.watchdog import watch_paths
import time
# Watch source files for changes
source_files = ["src/mypackage/", "docs/"]
observer, event = watch_paths(source_files)
try:
while True:
if event.wait(timeout=1.0):
print("Files changed, regenerating docs...")
# Regenerate documentation
event.clear()
else:
time.sleep(0.1)
finally:
observer.stop()from pydoc_markdown.util.pages import collect_pages
# Collect all markdown files in docs directory
doc_pages = collect_pages("docs/", "*.md")
# Collect specific patterns
api_pages = collect_pages("docs/api/", "*.md")
examples = collect_pages("examples/", "*.py")from pydoc_markdown.util.misc import escape_except_blockquotes
# Safely escape markdown while preserving blockquotes
text = """
This text has *special* characters that need escaping.
> But this blockquote should remain unchanged
> with its *formatting* intact.
"""
escaped = escape_except_blockquotes(text)from pydoc_markdown.contrib.renderers.markdown import dotted_name
# Get full dotted names for API objects
for obj in module.members:
full_name = dotted_name(obj)
print(f"Full name: {full_name}")
# Output: "mypackage.MyClass.my_method"from pydoc_markdown.interfaces import Processor
from pydoc_markdown.util.docspec import get_members_of_type, is_method
import docspec
class MethodDocumentationProcessor(Processor):
def process(self, modules: List[docspec.Module], resolver: Optional[Resolver]) -> None:
# Get all methods across all modules
methods = get_members_of_type(modules, docspec.Function)
methods = [m for m in methods if is_method(m)]
# Add standard documentation for undocumented methods
for method in methods:
if not method.docstring:
signature = format_function_signature(method, exclude_self=True)
method.docstring = f"Method {method.name}{signature}"from pydoc_markdown.interfaces import Renderer
from pydoc_markdown.util.docspec import get_object_description, dotted_name
from pydoc_markdown.util.misc import escape_except_blockquotes
class CustomTableRenderer(Renderer):
def render(self, modules: List[docspec.Module]) -> None:
with open("api-table.md", "w") as f:
f.write("# API Reference Table\n\n")
f.write("| Name | Type | Description |\n")
f.write("|------|------|-------------|\n")
for module in modules:
for obj in module.members:
name = dotted_name(obj)
obj_type = get_object_description(obj)
desc = obj.docstring or "No description"
desc = escape_except_blockquotes(desc.split('\n')[0]) # First line only
f.write(f"| {name} | {obj_type} | {desc} |\n")from pydoc_markdown.util.watchdog import watch_paths
from pydoc_markdown.util.pages import collect_pages
from pydoc_markdown import PydocMarkdown
class DocumentationWatcher:
def __init__(self, config_file: str):
self.config_file = config_file
self.config = PydocMarkdown()
self.config.load_config(config_file)
def start_watching(self):
# Collect all relevant files to watch
source_files = []
# Add Python source files
for loader in self.config.loaders:
if hasattr(loader, 'search_path'):
source_files.extend(loader.search_path)
# Add documentation files
doc_files = collect_pages("docs/", "*.md")
source_files.extend(doc_files)
# Add config file
source_files.append(self.config_file)
# Start watching
observer, event = watch_paths(source_files)
try:
while True:
if event.wait(timeout=2.0):
print("Changes detected, regenerating documentation...")
self.regenerate_docs()
event.clear()
finally:
observer.stop()
def regenerate_docs(self):
modules = self.config.load_modules()
self.config.process(modules)
self.config.render(modules)Install with Tessl CLI
npx tessl i tessl/pypi-pydoc-markdown