Commit 66296e1c by Celine Mercier

adding the breathe files

parent 7e74b40b
__version__ = '4.0.0'
def setup(app):
# We can't do the import at the module scope as setup.py has to be able to
# import this file to read __version__ without hitting any syntax errors
# from both Python 2 & Python 3.
# By the time this function is called, the directives code will have been
# converted with 2to3 if appropriate
from . import directives
directives.setup(app)
from ..renderer.rst.doxygen.base import RenderContext
from ..renderer.rst.doxygen import format_parser_error
from ..parser import ParserError, FileIOError
from docutils import nodes
from docutils.parsers import rst
class WarningHandler(object):
def __init__(self, state, context):
self.state = state
self.context = context
def warn(self, raw_text, rendered_nodes=None):
raw_text = self.format(raw_text)
if rendered_nodes is None:
rendered_nodes = [nodes.paragraph("", "", nodes.Text(raw_text))]
return [
nodes.warning("", *rendered_nodes),
self.state.document.reporter.warning(raw_text, line=self.context['lineno'])
]
def format(self, text):
return text.format(**self.context)
def create_warning(project_info, state, lineno, **kwargs):
tail = ''
if project_info:
tail = 'in doxygen xml output for project "{project}" from directory: {path}'.format(
project=project_info.name(),
path=project_info.project_path()
)
context = dict(
lineno=lineno,
tail=tail,
**kwargs
)
return WarningHandler(state, context)
class BaseDirective(rst.Directive):
def __init__(self, root_data_object, renderer_factory_creator_constructor, finder_factory,
project_info_factory, filter_factory, target_handler_factory, parser_factory, *args):
rst.Directive.__init__(self, *args)
self.directive_args = list(args) # Convert tuple to list to allow modification.
self.root_data_object = root_data_object
self.renderer_factory_creator_constructor = renderer_factory_creator_constructor
self.finder_factory = finder_factory
self.project_info_factory = project_info_factory
self.filter_factory = filter_factory
self.target_handler_factory = target_handler_factory
self.parser_factory = parser_factory
def render(self, node_stack, project_info, options, filter_, target_handler, mask_factory):
"Standard render process used by subclasses"
renderer_factory_creator = self.renderer_factory_creator_constructor.create_factory_creator(
project_info,
self.state.document,
options,
target_handler
)
try:
renderer_factory = renderer_factory_creator.create_factory(
node_stack,
self.state,
self.state.document,
filter_,
target_handler,
)
except ParserError as e:
return format_parser_error("doxygenclass", e.error, e.filename, self.state,
self.lineno, True)
except FileIOError as e:
return format_parser_error("doxygenclass", e.error, e.filename, self.state, self.lineno)
context = RenderContext(node_stack, mask_factory, self.directive_args)
object_renderer = renderer_factory.create_renderer(context)
return object_renderer.render()
from ..renderer.rst.doxygen.base import RenderContext
from ..renderer.rst.doxygen.mask import NullMaskFactory
from ..directive.base import BaseDirective
from ..project import ProjectError
from .base import create_warning
from docutils.parsers.rst.directives import unchanged_required, flag
from docutils.parsers import rst
class BaseFileDirective(BaseDirective):
"""Base class handle the main work when given the appropriate file and project info to work
from.
"""
# We use inheritance here rather than a separate object and composition, because so much
# information is present in the Directive class from the docutils framework that we'd have to
# pass way too much stuff to a helper object to be reasonable.
def handle_contents(self, file_, project_info):
finder = self.finder_factory.create_finder(project_info)
finder_filter = self.filter_factory.create_file_finder_filter(file_)
matches = []
finder.filter_(finder_filter, matches)
if len(matches) > 1:
warning = create_warning(None, self.state, self.lineno, file=file_,
directivename=self.directive_name)
return warning.warn('{directivename}: Found multiple matches for file "{file} {tail}')
elif not matches:
warning = create_warning(None, self.state, self.lineno, file=file_,
directivename=self.directive_name)
return warning.warn('{directivename}: Cannot find file "{file} {tail}')
target_handler = self.target_handler_factory.create_target_handler(
self.options, project_info, self.state.document)
filter_ = self.filter_factory.create_file_filter(file_, self.options)
renderer_factory_creator = self.renderer_factory_creator_constructor.create_factory_creator(
project_info,
self.state.document,
self.options,
target_handler
)
node_list = []
for node_stack in matches:
renderer_factory = renderer_factory_creator.create_factory(
node_stack,
self.state,
self.state.document,
filter_,
target_handler,
)
mask_factory = NullMaskFactory()
context = RenderContext(node_stack, mask_factory, self.directive_args)
object_renderer = renderer_factory.create_renderer(context)
node_list.extend(object_renderer.render())
return node_list
class DoxygenFileDirective(BaseFileDirective):
directive_name = 'doxygenfile'
required_arguments = 0
optional_arguments = 2
option_spec = {
"path": unchanged_required,
"project": unchanged_required,
"outline": flag,
"no-link": flag,
}
has_content = False
def run(self):
"""Get the file from the argument and the project info from the factory."""
file_ = self.arguments[0]
try:
project_info = self.project_info_factory.create_project_info(self.options)
except ProjectError as e:
warning = create_warning(None, self.state, self.lineno)
return warning.warn('doxygenfile: %s' % e)
return self.handle_contents(file_, project_info)
class AutoDoxygenFileDirective(BaseFileDirective):
directive_name = 'autodoxygenfile'
required_arguments = 1
option_spec = {
"project": unchanged_required,
"outline": flag,
"no-link": flag,
}
has_content = False
def run(self):
"""Get the file from the argument and extract the associated project info for the named
project given that it is an auto-project.
"""
file_ = self.arguments[0]
try:
project_info = self.project_info_factory.retrieve_project_info_for_auto(self.options)
except ProjectError as e:
warning = create_warning(None, self.state, self.lineno)
return warning.warn('autodoxygenfile: %s' % e)
return self.handle_contents(file_, project_info)
from ..renderer.rst.doxygen.base import RenderContext
from ..renderer.rst.doxygen.mask import NullMaskFactory
from ..renderer.rst.doxygen import format_parser_error
from ..directive.base import BaseDirective
from ..project import ProjectError
from ..parser import ParserError, FileIOError
from .base import create_warning
from docutils.parsers import rst
from docutils.parsers.rst.directives import unchanged_required, flag
class BaseIndexDirective(BaseDirective):
"""Base class handle the main work when given the appropriate project info to work from.
"""
# We use inheritance here rather than a separate object and composition, because so much
# information is present in the Directive class from the docutils framework that we'd have to
# pass way too much stuff to a helper object to be reasonable.
def handle_contents(self, project_info):
try:
finder = self.finder_factory.create_finder(project_info)
except ParserError as e:
return format_parser_error(self.name, e.error, e.filename, self.state,
self.lineno, True)
except FileIOError as e:
return format_parser_error(self.name, e.error, e.filename, self.state, self.lineno)
data_object = finder.root()
target_handler = self.target_handler_factory.create_target_handler(
self.options, project_info, self.state.document)
filter_ = self.filter_factory.create_index_filter(self.options)
renderer_factory_creator = self.renderer_factory_creator_constructor.create_factory_creator(
project_info,
self.state.document,
self.options,
target_handler
)
renderer_factory = renderer_factory_creator.create_factory(
[data_object],
self.state,
self.state.document,
filter_,
target_handler,
)
mask_factory = NullMaskFactory()
context = RenderContext([data_object, self.root_data_object], mask_factory, self.directive_args)
object_renderer = renderer_factory.create_renderer(context)
try:
node_list = object_renderer.render()
except ParserError as e:
return format_parser_error(self.name, e.error, e.filename, self.state,
self.lineno, True)
except FileIOError as e:
return format_parser_error(self.name, e.error, e.filename, self.state, self.lineno)
return node_list
class DoxygenIndexDirective(BaseIndexDirective):
required_arguments = 0
optional_arguments = 2
option_spec = {
"path": unchanged_required,
"project": unchanged_required,
"outline": flag,
"no-link": flag,
}
has_content = False
def run(self):
"""Extract the project info and pass it to the helper method"""
try:
project_info = self.project_info_factory.create_project_info(self.options)
except ProjectError as e:
warning = create_warning(None, self.state, self.lineno)
return warning.warn('doxygenindex: %s' % e)
return self.handle_contents(project_info)
class AutoDoxygenIndexDirective(BaseIndexDirective):
required_arguments = 0
final_argument_whitespace = True
option_spec = {
"project": unchanged_required,
"outline": flag,
"no-link": flag,
}
has_content = False
def run(self):
"""Extract the project info from the auto project info store and pass it to the helper
method
"""
try:
project_info = self.project_info_factory.retrieve_project_info_for_auto(self.options)
except ProjectError as e:
warning = create_warning(None, self.state, self.lineno)
return warning.warn('autodoxygenindex: %s' % e)
return self.handle_contents(project_info)
class BreatheError(Exception):
pass
class FakeParentNode(object):
node_type = "fakeparent"
class Finder(object):
def __init__(self, root, item_finder_factory):
self._root = root
self.item_finder_factory = item_finder_factory
def filter_(self, filter_, matches):
"""Adds all nodes which match the filter into the matches list"""
item_finder = self.item_finder_factory.create_finder(self._root)
item_finder.filter_([FakeParentNode()], filter_, matches)
def root(self):
return self._root
class FinderFactory(object):
def __init__(self, parser, item_finder_factory_creator):
self.parser = parser
self.item_finder_factory_creator = item_finder_factory_creator
def create_finder(self, project_info):
root = self.parser.parse(project_info)
item_finder_factory = self.item_finder_factory_creator.create_factory(project_info)
return Finder(root, item_finder_factory)
def create_finder_from_root(self, root, project_info):
item_finder_factory = self.item_finder_factory_creator.create_factory(project_info)
return Finder(root, item_finder_factory)
class ItemFinder(object):
def __init__(self, project_info, data_object, item_finder_factory):
self.data_object = data_object
self.item_finder_factory = item_finder_factory
self.project_info = project_info
def stack(element, list_):
"""Stack an element on to the start of a list and return as a new list"""
# Copy list first so we have a new list to insert into
output = list_[:]
output.insert(0, element)
return output
from .base import ItemFinder, stack
class DoxygenTypeSubItemFinder(ItemFinder):
def filter_(self, ancestors, filter_, matches):
"""Find nodes which match the filter. Doesn't test this node, only its children"""
node_stack = stack(self.data_object, ancestors)
compound_finder = self.item_finder_factory.create_finder(self.data_object.compounddef)
compound_finder.filter_(node_stack, filter_, matches)
class CompoundDefTypeSubItemFinder(ItemFinder):
def filter_(self, ancestors, filter_, matches):
"""Finds nodes which match the filter and continues checks to children"""
node_stack = stack(self.data_object, ancestors)
if filter_.allow(node_stack):
matches.append(node_stack)
for sectiondef in self.data_object.sectiondef:
finder = self.item_finder_factory.create_finder(sectiondef)
finder.filter_(node_stack, filter_, matches)
for innerclass in self.data_object.innerclass:
finder = self.item_finder_factory.create_finder(innerclass)
finder.filter_(node_stack, filter_, matches)
class SectionDefTypeSubItemFinder(ItemFinder):
def filter_(self, ancestors, filter_, matches):
"""Find nodes which match the filter. Doesn't test this node, only its children"""
node_stack = stack(self.data_object, ancestors)
if filter_.allow(node_stack):
matches.append(node_stack)
for memberdef in self.data_object.memberdef:
finder = self.item_finder_factory.create_finder(memberdef)
finder.filter_(node_stack, filter_, matches)
class MemberDefTypeSubItemFinder(ItemFinder):
def filter_(self, ancestors, filter_, matches):
data_object = self.data_object
node_stack = stack(data_object, ancestors)
if filter_.allow(node_stack):
matches.append(node_stack)
if data_object.kind == 'enum':
for value in data_object.enumvalue:
value_stack = stack(value, node_stack)
if filter_.allow(value_stack):
matches.append(value_stack)
class RefTypeSubItemFinder(ItemFinder):
def filter_(self, ancestors, filter_, matches):
node_stack = stack(self.data_object, ancestors)
if filter_.allow(node_stack):
matches.append(node_stack)
from . import index as indexfinder
from . import compound as compoundfinder
class CreateCompoundTypeSubFinder(object):
def __init__(self, parser_factory, matcher_factory):
self.parser_factory = parser_factory
self.matcher_factory = matcher_factory
def __call__(self, project_info, *args):
compound_parser = self.parser_factory.create_compound_parser(project_info)
return indexfinder.CompoundTypeSubItemFinder(self.matcher_factory, compound_parser,
project_info, *args)
class DoxygenItemFinderFactory(object):
def __init__(self, finders, project_info):
self.finders = finders
self.project_info = project_info
def create_finder(self, data_object):
return self.finders[data_object.node_type](self.project_info, data_object, self)
class DoxygenItemFinderFactoryCreator(object):
def __init__(self, parser_factory, filter_factory):
self.parser_factory = parser_factory
self.filter_factory = filter_factory
def create_factory(self, project_info):
finders = {
"doxygen": indexfinder.DoxygenTypeSubItemFinder,
"compound": CreateCompoundTypeSubFinder(self.parser_factory, self.filter_factory),
"member": indexfinder.MemberTypeSubItemFinder,
"doxygendef": compoundfinder.DoxygenTypeSubItemFinder,
"compounddef": compoundfinder.CompoundDefTypeSubItemFinder,
"sectiondef": compoundfinder.SectionDefTypeSubItemFinder,
"memberdef": compoundfinder.MemberDefTypeSubItemFinder,
"ref": compoundfinder.RefTypeSubItemFinder,
}
return DoxygenItemFinderFactory(finders, project_info)
from .base import ItemFinder, stack
class DoxygenTypeSubItemFinder(ItemFinder):
def filter_(self, ancestors, filter_, matches):
"""Find nodes which match the filter. Doesn't test this node, only its children"""
compounds = self.data_object.get_compound()
node_stack = stack(self.data_object, ancestors)
for compound in compounds:
compound_finder = self.item_finder_factory.create_finder(compound)
compound_finder.filter_(node_stack, filter_, matches)
class CompoundTypeSubItemFinder(ItemFinder):
def __init__(self, filter_factory, compound_parser, *args):
ItemFinder.__init__(self, *args)
self.filter_factory = filter_factory
self.compound_parser = compound_parser
def filter_(self, ancestors, filter_, matches):
"""Finds nodes which match the filter and continues checks to children
Requires parsing the xml files referenced by the children for which we use the compound
parser and continue at the top level of that pretending that this node is the parent of the
top level node of the compound file.
"""
node_stack = stack(self.data_object, ancestors)
# Match against compound object
if filter_.allow(node_stack):
matches.append(node_stack)
# Descend to member children
members = self.data_object.get_member()
member_matches = []
for member in members:
member_finder = self.item_finder_factory.create_finder(member)
member_finder.filter_(node_stack, filter_, member_matches)
results = []
# If there are members in this compound that match the criteria
# then load up the file for this compound and get the member data objects
if member_matches:
file_data = self.compound_parser.parse(self.data_object.refid)
finder = self.item_finder_factory.create_finder(file_data)
for member_stack in member_matches:
ref_filter = self.filter_factory.create_id_filter('memberdef', member_stack[0].refid)
finder.filter_(node_stack, ref_filter, matches)
else:
# Read in the xml file referenced by the compound and descend into that as well
file_data = self.compound_parser.parse(self.data_object.refid)
finder = self.item_finder_factory.create_finder(file_data)
finder.filter_(node_stack, filter_, matches)
class MemberTypeSubItemFinder(ItemFinder):
def filter_(self, ancestors, filter_, matches):
node_stack = stack(self.data_object, ancestors)
# Match against member object
if filter_.allow(node_stack):
matches.append(node_stack)
import breathe.parser.doxygen.index
import breathe.parser.doxygen.compound
class ParserError(Exception):
def __init__(self, error, filename):
Exception.__init__(self, error)
self.error = error
self.filename = filename
class FileIOError(Exception):
def __init__(self, error, filename):
Exception.__init__(self, error)
self.error = error
self.filename = filename
class Parser(object):
def __init__(self, cache, path_handler, file_state_cache):
self.cache = cache
self.path_handler = path_handler
self.file_state_cache = file_state_cache
class DoxygenIndexParser(Parser):
def __init__(self, cache, path_handler, file_state_cache):
Parser.__init__(self, cache, path_handler, file_state_cache)
def parse(self, project_info):
filename = self.path_handler.resolve_path(
project_info.project_path(),
"index.xml"
)
self.file_state_cache.update(filename)
try:
# Try to get from our cache
return self.cache[filename]
except KeyError:
# If that fails, parse it