Create Python API documentation in Markdown format
—
Abstract interfaces and base classes that define the plugin architecture for loaders, processors, renderers, and additional functionality like source linking and development servers.
Base interfaces that form the foundation of pydoc-markdown's plugin system.
class Context:
"""
Context data passed to plugins during initialization.
Attributes:
directory: Working directory for plugin operations
"""
directory: str
def __init__(self, directory: str) -> None:
"""
Initialize context with working directory.
Args:
directory: Working directory path
"""
class PluginBase(ABC):
"""
Abstract base class for all pydoc-markdown plugins.
Provides basic plugin lifecycle management.
"""
def init(self, context: Context) -> None:
"""
Initialize plugin with context data.
Args:
context: Context containing directory and other initialization data
"""Interface for loading documentation data from various sources.
class Loader(PluginBase):
"""
Interface for loading documentation data.
Loaders extract API information from source code, documentation files,
or other sources and convert them into docspec.Module objects.
"""
def load(self) -> Iterable[docspec.Module]:
"""
Load documentation data.
Returns:
Iterable of docspec.Module objects containing API information
Raises:
LoaderError: If loading fails
"""
class LoaderError(Exception):
"""Exception raised when loader operations fail."""Interface for transforming and enhancing loaded documentation data.
class Processor(PluginBase):
"""
Interface for processing and transforming docspec.Module objects.
Processors typically modify docstrings, filter content, resolve references,
or apply other transformations to prepare data for rendering.
"""
def process(self, modules: List[docspec.Module], resolver: Optional[Resolver]) -> None:
"""
Process modules in place.
Args:
modules: List of modules to process (modified in place)
resolver: Optional resolver for handling cross-references
"""Interface for generating documentation output in various formats.
class Renderer(PluginBase):
"""
Interface for rendering docspec.Module objects to output files.
Renderers generate final documentation in formats like Markdown, HTML,
or integration with static site generators.
"""
def process(self, modules: List[docspec.Module], resolver: Optional[Resolver]) -> None:
"""
Optional processing step before rendering.
Args:
modules: List of modules to process
resolver: Optional resolver for cross-references
"""
def get_resolver(self, modules: List[docspec.Module]) -> Optional[Resolver]:
"""
Get resolver for cross-reference handling.
Args:
modules: List of modules for resolver context
Returns:
Resolver instance or None if not supported
"""
def render(self, modules: List[docspec.Module]) -> None:
"""
Render modules to output format.
Args:
modules: List of modules to render
"""Interfaces for resolving cross-references between API objects.
class Resolver(ABC):
"""
Interface for resolving cross-references to hyperlinks.
Used by processors to convert references in docstrings to URLs or other
link formats appropriate for the target documentation format.
"""
def resolve_ref(self, scope: docspec.ApiObject, ref: str) -> Optional[str]:
"""
Resolve reference to a hyperlink.
Args:
scope: API object containing the reference
ref: Reference string to resolve
Returns:
Resolved hyperlink or None if resolution fails
"""
class ResolverV2(ABC):
"""
New-style resolver interface that returns resolved objects directly.
Provides more flexibility than the original Resolver interface by
returning the actual resolved API object instead of a string representation.
"""
def resolve_reference(self, suite: ApiSuite, scope: docspec.ApiObject, ref: str) -> Optional[docspec.ApiObject]:
"""
Resolve reference to an API object.
Args:
suite: API suite containing all available objects
scope: API object containing the reference
ref: Reference string to resolve
Returns:
Resolved API object or None if resolution fails
"""Specialized renderer interfaces for specific rendering capabilities.
class SinglePageRenderer(PluginBase):
"""
Interface for renderers that can generate single-page output.
"""
def render_single_page(
self,
fp: TextIO,
modules: List[docspec.Module],
page_title: Optional[str] = None
) -> None:
"""
Render modules to a single page.
Args:
fp: File object to write output to
modules: List of modules to render
page_title: Optional title for the page
"""
class SingleObjectRenderer(PluginBase):
"""
Interface for renderers that can render individual API objects.
"""
def render_object(self, fp: TextIO, obj: docspec.ApiObject, options: Dict[str, Any]) -> None:
"""
Render a single API object.
Args:
fp: File object to write output to
obj: API object to render
options: Rendering options and configuration
"""Interface for development server functionality.
class Server(ABC):
"""
Interface for development server capabilities.
Renderers implementing this interface can provide live preview
functionality with automatic reloading when source files change.
"""
def get_server_url(self) -> str:
"""
Get the development server URL.
Returns:
URL where the development server is accessible
"""
def start_server(self) -> subprocess.Popen:
"""
Start the development server process.
Returns:
Process handle for the running server
"""
def reload_server(self, process: subprocess.Popen) -> subprocess.Popen:
"""
Reload server process when files change.
Args:
process: Current server process
Returns:
New server process or same process if reload not needed
"""Interface for build functionality after rendering.
class Builder(ABC):
"""
Interface for renderers that support building final output.
Builders can generate final static sites, optimize output,
or perform other post-rendering operations.
"""
def build(self, site_dir: str) -> None:
"""
Build final output after rendering.
Args:
site_dir: Directory where build output should be placed
"""Interface for linking documentation to source code.
class SourceLinker(PluginBase):
"""
Interface for generating links to source code.
Source linkers determine URLs to the original source code for
API objects, enabling documentation to include "view source" links.
"""
def get_source_url(self, obj: docspec.ApiObject) -> Optional[str]:
"""
Get URL to source code for an API object.
Args:
obj: API object to get source URL for
Returns:
URL to source code or None if not available
"""from pydoc_markdown.interfaces import Loader, Context
import docspec
class CustomLoader(Loader):
def __init__(self, source_path: str):
self.source_path = source_path
def init(self, context: Context) -> None:
# Initialize with context
self.working_dir = context.directory
def load(self) -> Iterable[docspec.Module]:
# Load from custom source
module = docspec.Module(
name="custom_module",
location=docspec.Location("custom.py", 1),
docstring="Custom loaded module"
)
return [module]from pydoc_markdown.interfaces import Processor, Resolver
import docspec
class CustomProcessor(Processor):
def __init__(self, transform_pattern: str):
self.transform_pattern = transform_pattern
def process(self, modules: List[docspec.Module], resolver: Optional[Resolver]) -> None:
for module in modules:
for obj in module.members:
if obj.docstring:
# Apply custom transformation
obj.docstring = obj.docstring.replace(
self.transform_pattern,
"**" + self.transform_pattern + "**"
)from pydoc_markdown.interfaces import Renderer, Resolver
import docspec
class CustomRenderer(Renderer):
def __init__(self, output_file: str):
self.output_file = output_file
def render(self, modules: List[docspec.Module]) -> None:
with open(self.output_file, 'w') as f:
for module in modules:
f.write(f"# {module.name}\n\n")
if module.docstring:
f.write(f"{module.docstring}\n\n")
for obj in module.members:
f.write(f"## {obj.name}\n\n")
if obj.docstring:
f.write(f"{obj.docstring}\n\n")from pydoc_markdown.interfaces import SourceLinker
import docspec
class GitHubSourceLinker(SourceLinker):
def __init__(self, repo_url: str, branch: str = "main"):
self.repo_url = repo_url.rstrip('/')
self.branch = branch
def get_source_url(self, obj: docspec.ApiObject) -> Optional[str]:
if obj.location and obj.location.filename:
return f"{self.repo_url}/blob/{self.branch}/{obj.location.filename}#L{obj.location.lineno}"
return NonePlugins are typically registered via entry points in setup.py or pyproject.toml:
[tool.poetry.plugins."pydoc_markdown.interfaces.Loader"]
custom = "mypackage.loaders:CustomLoader"
[tool.poetry.plugins."pydoc_markdown.interfaces.Processor"]
custom = "mypackage.processors:CustomProcessor"
[tool.poetry.plugins."pydoc_markdown.interfaces.Renderer"]
custom = "mypackage.renderers:CustomRenderer"
[tool.poetry.plugins."pydoc_markdown.interfaces.SourceLinker"]
custom = "mypackage.linkers:CustomSourceLinker"# pydoc-markdown.yml
loaders:
- type: custom
source_path: "/path/to/source"
processors:
- type: custom
transform_pattern: "TODO"
renderer:
type: custom
output_file: "custom-docs.md"Renderers can implement multiple interfaces for enhanced functionality:
class AdvancedRenderer(Renderer, Server, Builder, SinglePageRenderer):
def render(self, modules: List[docspec.Module]) -> None:
# Standard rendering
pass
def get_server_url(self) -> str:
return "http://localhost:8000"
def start_server(self) -> subprocess.Popen:
# Start development server
pass
def build(self, site_dir: str) -> None:
# Build final output
pass
def render_single_page(self, fp: TextIO, modules: List[docspec.Module], page_title: Optional[str] = None) -> None:
# Single page rendering
passCheck renderer capabilities at runtime:
from pydoc_markdown.interfaces import Server, Builder
# Check if renderer supports server
if isinstance(renderer, Server):
server_url = renderer.get_server_url()
process = renderer.start_server()
# Check if renderer supports building
if isinstance(renderer, Builder):
renderer.build("/path/to/site/")Install with Tessl CLI
npx tessl i tessl/pypi-pydoc-markdown