Sphinx extension that beautifully integrates Doxygen-generated documentation into Sphinx-based documentation systems
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Breathe's parser system processes Doxygen's XML output format, providing cached access to parsed XML data with comprehensive error handling. The system handles both index files (project overview) and compound files (detailed element documentation).
Factory for creating XML parsers with shared caching to improve performance across multiple parsing operations.
class DoxygenParserFactory:
def __init__(self, app: Sphinx):
"""
Initialize parser factory with Sphinx application.
Args:
app: Sphinx application instance
"""
def create_index_parser(self) -> DoxygenIndexParser:
"""
Create parser for Doxygen index.xml files.
Returns:
DoxygenIndexParser instance with shared cache
"""
def create_compound_parser(self, project_info: ProjectInfo) -> DoxygenCompoundParser:
"""
Create parser for Doxygen compound XML files.
Args:
project_info: Project configuration for XML location
Returns:
DoxygenCompoundParser instance for the specified project
"""Parses Doxygen's index.xml files which contain the project-wide overview and references to all documented elements.
class DoxygenIndexParser(Parser):
def parse(self, project_info: ProjectInfo):
"""
Parse the index.xml file for a project.
Handles caching and file state tracking. The index.xml file contains
the master list of all documented compounds (classes, files, etc.)
with their reference IDs.
Args:
project_info: Project configuration specifying XML location
Returns:
Parsed index data structure
Raises:
ParserError: If XML parsing fails
FileIOError: If file cannot be read
"""Parses individual compound XML files containing detailed documentation for specific elements (classes, files, namespaces, etc.).
class DoxygenCompoundParser(Parser):
def __init__(self, app: Sphinx, cache: dict, project_info: ProjectInfo):
"""
Initialize compound parser for specific project.
Args:
app: Sphinx application instance
cache: Shared parser cache
project_info: Project configuration for XML location
"""
def parse(self, refid: str):
"""
Parse a compound XML file by reference ID.
Compound files contain detailed documentation for specific elements
like classes, files, namespaces, etc. Each compound has a unique
reference ID used as the filename (e.g., "classMyClass.xml").
Args:
refid: Reference ID of the compound to parse
Returns:
Parsed compound data structure
Raises:
ParserError: If XML parsing fails
FileIOError: If file cannot be read
"""Common functionality shared by all parser types.
class Parser:
def __init__(self, app: Sphinx, cache: dict):
"""
Initialize base parser functionality.
Args:
app: Sphinx application instance
cache: Shared cache for parsed results
"""Comprehensive error handling for XML parsing operations.
class ParserError(Exception):
def __init__(self, error: Exception, filename: Path):
"""
XML parsing error with file context.
Args:
error: Underlying parsing exception
filename: Path to file that failed to parse
"""
def __str__(self) -> str:
"""Return string representation including filename and error."""
@property
def error(self) -> Exception:
"""Get the underlying parsing error."""
@property
def filename(self) -> Path:
"""Get the path to file that failed to parse."""
class FileIOError(Exception):
def __init__(self, error: Exception, filename: Path):
"""
File I/O error with file context.
Args:
error: Underlying I/O exception
filename: Path to file that couldn't be accessed
"""
def __str__(self) -> str:
"""Return string representation including filename and error."""
@property
def error(self) -> Exception:
"""Get the underlying I/O error."""
@property
def filename(self) -> Path:
"""Get the path to file that couldn't be accessed."""The parser system works with Doxygen's standard XML output structure:
Contains project overview and compound references:
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<doxygenindex>
<compound refid="classMyClass" kind="class">
<name>MyClass</name>
<member refid="classMyClass_1a123" kind="function">
<name>myMethod</name>
</member>
</compound>
<compound refid="namespaceMyNamespace" kind="namespace">
<name>MyNamespace</name>
</compound>
</doxygenindex>Contain detailed documentation for specific elements:
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<doxygen>
<compounddef id="classMyClass" kind="class">
<name>MyClass</name>
<briefdescription>Brief description of MyClass</briefdescription>
<detaileddescription>Detailed description...</detaileddescription>
<sectiondef kind="public-func">
<memberdef kind="function" id="classMyClass_1a123">
<name>myMethod</name>
<type>void</type>
<definition>void MyClass::myMethod</definition>
</memberdef>
</sectiondef>
</compounddef>
</doxygen>The parser system implements intelligent caching to improve performance:
# Cache is automatically managed
factory = DoxygenParserFactory(app)
parser = factory.create_index_parser()
# First parse - loads and caches
result1 = parser.parse(project_info)
# Second parse - returns cached result
result2 = parser.parse(project_info) # Fast cached access
# If XML file changes, cache is invalidated automaticallyfrom breathe.parser import DoxygenParserFactory
from breathe.project import ProjectInfo
# Create factory
factory = DoxygenParserFactory(app)
# Parse project index
index_parser = factory.create_index_parser()
index_data = index_parser.parse(project_info)
# Parse specific compound
compound_parser = factory.create_compound_parser(project_info)
class_data = compound_parser.parse("classMyClass")from breathe.parser import ParserError, FileIOError
try:
index_data = index_parser.parse(project_info)
except ParserError as e:
print(f"XML parsing failed: {e.error}")
print(f"File: {e.filename}")
except FileIOError as e:
print(f"File I/O error: {e.error}")
print(f"File: {e.filename}")# In directive implementation
try:
parser = self.parser_factory.create_compound_parser(project_info)
compound_data = parser.parse(refid)
# Process parsed data...
except ParserError as e:
return format_parser_error(
self.name, e.error, e.filename, self.state, self.lineno, True
)# Access parser factory from directive
factory = self.env.temp_data["breathe_parser_factory"]
# Create parsers as needed
index_parser = factory.create_index_parser()
compound_parser = factory.create_compound_parser(project_info)
# Parse XML data
index_data = index_parser.parse(project_info)
for compound in index_data.compounds:
compound_data = compound_parser.parse(compound.refid)
# Process compound data...The parser system includes generated modules for XML schema handling:
Install with Tessl CLI
npx tessl i tessl/pypi-breathe