Browse Source

Auto format all python files with black

Excluding the parser files which are auto-generated once upon a time
possibly best left out for the moment.
pull/743/head
Michael Jones 11 months ago
parent
commit
55208900c2
  1. 3
      breathe-apidoc.py
  2. 8
      breathe/__init__.py
  3. 169
      breathe/apidoc.py
  4. 57
      breathe/directives/__init__.py
  5. 9
      breathe/directives/class_like.py
  6. 15
      breathe/directives/content_block.py
  7. 10
      breathe/directives/file.py
  8. 143
      breathe/directives/function.py
  9. 22
      breathe/directives/index.py
  10. 19
      breathe/directives/item.py
  11. 73
      breathe/directives/setup.py
  12. 1
      breathe/exception.py
  13. 10
      breathe/file_state_cache.py
  14. 3
      breathe/finder/__init__.py
  15. 2
      breathe/finder/compound.py
  16. 3
      breathe/finder/factory.py
  17. 3
      breathe/finder/index.py
  18. 2
      breathe/path_handler.py
  19. 26
      breathe/process.py
  20. 36
      breathe/project.py
  21. 22
      breathe/renderer/__init__.py
  22. 323
      breathe/renderer/filter.py
  23. 3
      breathe/renderer/mask.py
  24. 832
      breathe/renderer/sphinxrenderer.py
  25. 5
      breathe/renderer/target.py
  26. 261
      documentation/source/conf.py
  27. 9
      examples/doxygen/docstring.py
  28. 9
      examples/doxygen/pyexample.py
  29. 51
      setup.py
  30. 415
      tests/test_renderer.py
  31. 40
      tests/test_utils.py
  32. 158
      tests/warnings/source/conf.py

3
breathe-apidoc.py

@ -3,6 +3,7 @@
import sys
if __name__ == '__main__':
if __name__ == "__main__":
from breathe.apidoc import main
sys.exit(main())

8
breathe/__init__.py

@ -4,7 +4,7 @@ from breathe.renderer.sphinxrenderer import setup as renderer_setup
from sphinx.application import Sphinx
__version__ = '4.31.0'
__version__ = "4.31.0"
def setup(app: Sphinx):
@ -12,8 +12,4 @@ def setup(app: Sphinx):
file_state_cache_setup(app)
renderer_setup(app)
return {
'version': __version__,
'parallel_read_safe': True,
'parallel_write_safe': True
}
return {"version": __version__, "parallel_read_safe": True, "parallel_write_safe": True}

169
breathe/apidoc.py

@ -35,22 +35,18 @@ except NameError:
# Reference: Doxygen XSD schema file, CompoundKind only
# Only what breathe supports are included
# Translates identifier to English
TYPEDICT = {'class': 'Class',
'interface': 'Interface',
'struct': 'Struct',
'union': 'Union',
'file': 'File',
'namespace': 'Namespace',
'group': 'Group'}
TYPEDICT = {
"class": "Class",
"interface": "Interface",
"struct": "Struct",
"union": "Union",
"file": "File",
"namespace": "Namespace",
"group": "Group",
}
# Types that accept the :members: option.
MEMBERS_TYPES = [
'class',
'group',
'interface',
'namespace',
'struct'
]
MEMBERS_TYPES = ["class", "group", "interface", "namespace", "struct"]
def print_info(msg, args):
@ -60,14 +56,14 @@ def print_info(msg, args):
def write_file(name, text, args):
"""Write the output file for module/package <name>."""
fname = os.path.join(args.destdir, '%s.%s' % (name, args.suffix))
fname = os.path.join(args.destdir, "%s.%s" % (name, args.suffix))
if args.dryrun:
print_info('Would create file %s.' % fname, args)
print_info("Would create file %s." % fname, args)
return
if not args.force and os.path.isfile(fname):
print_info('File %s already exists, skipping.' % fname, args)
print_info("File %s already exists, skipping." % fname, args)
else:
print_info('Creating file %s.' % fname, args)
print_info("Creating file %s." % fname, args)
if not os.path.exists(os.path.dirname(fname)):
try:
os.makedirs(os.path.dirname(fname))
@ -75,32 +71,34 @@ def write_file(name, text, args):
if exc.errno != errno.EEXIST:
raise
try:
with open(fname, 'r') as target:
with open(fname, "r") as target:
orig = target.read()
if orig == text:
print_info('File %s up to date, skipping.' % fname, args)
print_info("File %s up to date, skipping." % fname, args)
return
except FileNotFoundError:
# Don't mind if it isn't there
pass
with open(fname, 'w') as target:
with open(fname, "w") as target:
target.write(text)
def format_heading(level, text):
"""Create a heading of <level> [1, 2 or 3 supported]."""
underlining = ['=', '-', '~', ][level - 1] * len(text)
return '%s\n%s\n\n' % (text, underlining)
underlining = ["=", "-", "~",][
level - 1
] * len(text)
return "%s\n%s\n\n" % (text, underlining)
def format_directive(package_type, package, args):
"""Create the breathe directive and add the options."""
directive = '.. doxygen%s:: %s\n' % (package_type, package)
directive = ".. doxygen%s:: %s\n" % (package_type, package)
if args.project:
directive += ' :project: %s\n' % args.project
directive += " :project: %s\n" % args.project
if args.members and package_type in MEMBERS_TYPES:
directive += ' :members:\n'
directive += " :members:\n"
return directive
@ -109,7 +107,7 @@ def create_package_file(package, package_type, package_id, args):
# Skip over types that weren't requested
if package_type not in args.outtypes:
return
text = format_heading(1, '%s %s' % (TYPEDICT[package_type], package))
text = format_heading(1, "%s %s" % (TYPEDICT[package_type], package))
text += format_directive(package_type, package, args)
write_file(os.path.join(package_type, package_id), text, args)
@ -119,12 +117,12 @@ def create_modules_toc_file(key, value, args):
"""Create the module's index."""
if not os.path.isdir(os.path.join(args.destdir, key)):
return
text = format_heading(1, '%s list' % value)
text += '.. toctree::\n'
text += ' :glob:\n\n'
text += ' %s/*\n' % key
text = format_heading(1, "%s list" % value)
text += ".. toctree::\n"
text += " :glob:\n\n"
text += " %s/*\n" % key
write_file('%slist' % key, text, args)
write_file("%slist" % key, text, args)
def recurse_tree(args):
@ -132,22 +130,23 @@ def recurse_tree(args):
Look for every file in the directory tree and create the corresponding
ReST files.
"""
index = xml.etree.ElementTree.parse(os.path.join(args.rootpath, 'index.xml'))
index = xml.etree.ElementTree.parse(os.path.join(args.rootpath, "index.xml"))
# Assuming this is a valid Doxygen XML
for compound in index.getroot():
create_package_file(compound.findtext('name'), compound.get('kind'),
compound.get('refid'), args)
create_package_file(
compound.findtext("name"), compound.get("kind"), compound.get("refid"), args
)
class TypeAction(argparse.Action):
def __init__(self, option_strings, dest, **kwargs):
super(TypeAction, self).__init__(option_strings, dest, **kwargs)
self.default = TYPEDICT.keys()
self.metavar = ','.join(TYPEDICT.keys())
self.metavar = ",".join(TYPEDICT.keys())
def __call__(self, parser, namespace, values, option_string=None):
value_list = values.split(',')
value_list = values.split(",")
for value in value_list:
if value not in TYPEDICT:
raise ValueError("%s not a valid option" % value)
@ -162,39 +161,79 @@ Parse XML created by Doxygen in <rootpath> and create one reST file with
breathe generation directives per definition in the <DESTDIR>.
Note: By default this script will not overwrite already created files.""",
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-o', '--output-dir', action='store', dest='destdir',
help='Directory to place all output', required=True)
parser.add_argument('-f', '--force', action='store_true', dest='force',
help='Overwrite existing files')
parser.add_argument('-m', '--members', action='store_true', dest='members',
help='Include members for types: %s' % MEMBERS_TYPES)
parser.add_argument('-n', '--dry-run', action='store_true', dest='dryrun',
help='Run the script without creating files')
parser.add_argument('-T', '--no-toc', action='store_true', dest='notoc',
help='Don\'t create a table of contents file')
parser.add_argument('-s', '--suffix', action='store', dest='suffix',
help='file suffix (default: rst)', default='rst')
parser.add_argument('-p', '--project', action='store', dest='project',
help='project to add to generated directives')
parser.add_argument('-g', '--generate', action=TypeAction, dest='outtypes',
help='types of output to generate, comma-separated list')
parser.add_argument('-q', '--quiet', action='store_true', dest='quiet',
help='suppress informational messages')
parser.add_argument('--version', action='version',
version='Breathe (breathe-apidoc) %s' % __version__)
parser.add_argument('rootpath', type=str,
help='The directory contains index.xml')
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"-o",
"--output-dir",
action="store",
dest="destdir",
help="Directory to place all output",
required=True,
)
parser.add_argument(
"-f", "--force", action="store_true", dest="force", help="Overwrite existing files"
)
parser.add_argument(
"-m",
"--members",
action="store_true",
dest="members",
help="Include members for types: %s" % MEMBERS_TYPES,
)
parser.add_argument(
"-n",
"--dry-run",
action="store_true",
dest="dryrun",
help="Run the script without creating files",
)
parser.add_argument(
"-T",
"--no-toc",
action="store_true",
dest="notoc",
help="Don't create a table of contents file",
)
parser.add_argument(
"-s",
"--suffix",
action="store",
dest="suffix",
help="file suffix (default: rst)",
default="rst",
)
parser.add_argument(
"-p",
"--project",
action="store",
dest="project",
help="project to add to generated directives",
)
parser.add_argument(
"-g",
"--generate",
action=TypeAction,
dest="outtypes",
help="types of output to generate, comma-separated list",
)
parser.add_argument(
"-q", "--quiet", action="store_true", dest="quiet", help="suppress informational messages"
)
parser.add_argument(
"--version", action="version", version="Breathe (breathe-apidoc) %s" % __version__
)
parser.add_argument("rootpath", type=str, help="The directory contains index.xml")
args = parser.parse_args()
if args.suffix.startswith('.'):
if args.suffix.startswith("."):
args.suffix = args.suffix[1:]
if not os.path.isdir(args.rootpath):
print('%s is not a directory.' % args.rootpath, file=sys.stderr)
print("%s is not a directory." % args.rootpath, file=sys.stderr)
sys.exit(1)
if 'index.xml' not in os.listdir(args.rootpath):
print('%s does not contain a index.xml' % args.rootpath, file=sys.stderr)
if "index.xml" not in os.listdir(args.rootpath):
print("%s does not contain a index.xml" % args.rootpath, file=sys.stderr)
sys.exit(1)
if not os.path.isdir(args.destdir):
if not args.dryrun:

57
breathe/directives/__init__.py

@ -21,14 +21,19 @@ class _WarningHandler:
self.state = state
self.context = context
def warn(self, raw_text: str, *, rendered_nodes: Sequence[nodes.Node] = None,
unformatted_suffix: str = '') -> List[nodes.Node]:
def warn(
self,
raw_text: str,
*,
rendered_nodes: Sequence[nodes.Node] = None,
unformatted_suffix: str = ""
) -> List[nodes.Node]:
raw_text = self.format(raw_text) + unformatted_suffix
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'])
self.state.document.reporter.warning(raw_text, line=self.context["lineno"]),
]
def format(self, text: str) -> str:
@ -42,10 +47,13 @@ class BaseDirective(SphinxDirective):
has_content: bool
final_argument_whitespace: bool
def __init__(self, finder_factory: FinderFactory,
project_info_factory: ProjectInfoFactory,
parser_factory: DoxygenParserFactory,
*args) -> None:
def __init__(
self,
finder_factory: FinderFactory,
project_info_factory: ProjectInfoFactory,
parser_factory: DoxygenParserFactory,
*args
) -> None:
super().__init__(*args)
self.directive_args = list(args) # Convert tuple to list to allow modification.
@ -61,22 +69,23 @@ class BaseDirective(SphinxDirective):
def create_warning(self, project_info: Optional[ProjectInfo], **kwargs) -> _WarningHandler:
if project_info:
tail = 'in doxygen xml output for project "{project}" from directory: {path}'.format(
project=project_info.name(),
path=project_info.project_path()
project=project_info.name(), path=project_info.project_path()
)
else:
tail = ''
tail = ""
context = dict(
lineno=self.lineno,
tail=tail,
**kwargs
)
context = dict(lineno=self.lineno, tail=tail, **kwargs)
return _WarningHandler(self.state, context)
def render(self, node_stack, project_info: ProjectInfo, filter_: Filter,
target_handler: TargetHandler, mask_factory: MaskFactoryBase,
directive_args) -> List[Node]:
def render(
self,
node_stack,
project_info: ProjectInfo,
filter_: Filter,
target_handler: TargetHandler,
mask_factory: MaskFactoryBase,
directive_args,
) -> List[Node]:
"Standard render process used by subclasses"
try:
@ -88,14 +97,16 @@ class BaseDirective(SphinxDirective):
self.state.document,
target_handler,
self.parser_factory.create_compound_parser(project_info),
filter_
filter_,
)
except ParserError as e:
return format_parser_error("doxygenclass", e.error, e.filename, self.state,
self.lineno, True)
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, True)
return format_parser_error(
"doxygenclass", e.error, e.filename, self.state, self.lineno, True
)
context = RenderContext(node_stack, mask_factory, directive_args)
return object_renderer.render(node_stack[0], context)

9
breathe/directives/class_like.py

@ -36,13 +36,13 @@ class _DoxygenClassLikeDirective(BaseDirective):
project_info = self.project_info_factory.create_project_info(self.options)
except ProjectError as e:
warning = self.create_warning(None, kind=self.kind)
return warning.warn('doxygen{kind}: %s' % e)
return warning.warn("doxygen{kind}: %s" % e)
try:
finder = self.finder_factory.create_finder(project_info)
except MTimeError as e:
warning = self.create_warning(None, kind=self.kind)
return warning.warn('doxygen{kind}: %s' % e)
return warning.warn("doxygen{kind}: %s" % e)
finder_filter = self.filter_factory.create_compound_finder_filter(name, self.kind)
@ -58,8 +58,9 @@ class _DoxygenClassLikeDirective(BaseDirective):
filter_ = self.filter_factory.create_class_filter(name, self.options)
mask_factory = NullMaskFactory()
return self.render(matches[0], project_info, filter_, target_handler, mask_factory,
self.directive_args)
return self.render(
matches[0], project_info, filter_, target_handler, mask_factory, self.directive_args
)
class DoxygenClassDirective(_DoxygenClassLikeDirective):

15
breathe/directives/content_block.py

@ -26,7 +26,7 @@ class _DoxygenContentBlockDirective(BaseDirective):
"protected-members": flag,
"private-members": flag,
"undoc-members": flag,
"no-link": flag
"no-link": flag,
}
has_content = False
@ -37,13 +37,13 @@ class _DoxygenContentBlockDirective(BaseDirective):
project_info = self.project_info_factory.create_project_info(self.options)
except ProjectError as e:
warning = self.create_warning(None, kind=self.kind)
return warning.warn('doxygen{kind}: %s' % e)
return warning.warn("doxygen{kind}: %s" % e)
try:
finder = self.finder_factory.create_finder(project_info)
except MTimeError as e:
warning = self.create_warning(None, kind=self.kind)
return warning.warn('doxygen{kind}: %s' % e)
return warning.warn("doxygen{kind}: %s" % e)
finder_filter = self.filter_factory.create_finder_filter(self.kind, name)
@ -57,15 +57,16 @@ class _DoxygenContentBlockDirective(BaseDirective):
warning = self.create_warning(project_info, name=name, kind=self.kind)
return warning.warn('doxygen{kind}: Cannot find {kind} "{name}" {tail}')
if 'content-only' in self.options and self.kind != "page":
if "content-only" in self.options and self.kind != "page":
# Unpack the single entry in the matches list
(node_stack,) = matches
filter_ = self.filter_factory.create_content_filter(self.kind, self.options)
# Having found the compound node for the namespace or group in the index we want to grab
# the contents of it which match the filter
contents_finder = self.finder_factory.create_finder_from_root(node_stack[0],
project_info)
contents_finder = self.finder_factory.create_finder_from_root(
node_stack[0], project_info
)
# TODO: find a more specific type for the Doxygen nodes
contents = [] # type: List[Any]
contents_finder.filter_(filter_, contents)
@ -86,7 +87,7 @@ class _DoxygenContentBlockDirective(BaseDirective):
self.state.document,
target_handler,
self.parser_factory.create_compound_parser(project_info),
filter_
filter_,
)
mask_factory = NullMaskFactory()

10
breathe/directives/file.py

@ -45,7 +45,7 @@ class _BaseFileDirective(BaseDirective):
self.state.document,
target_handler,
self.parser_factory.create_compound_parser(project_info),
filter_
filter_,
)
mask_factory = NullMaskFactory()
@ -56,7 +56,7 @@ class _BaseFileDirective(BaseDirective):
class DoxygenFileDirective(_BaseFileDirective):
directive_name = 'doxygenfile'
directive_name = "doxygenfile"
required_arguments = 0
optional_arguments = 3
@ -77,13 +77,13 @@ class DoxygenFileDirective(_BaseFileDirective):
project_info = self.project_info_factory.create_project_info(self.options)
except ProjectError as e:
warning = self.create_warning(None)
return warning.warn('doxygenfile: %s' % e)
return warning.warn("doxygenfile: %s" % e)
return self.handle_contents(file_, project_info)
class AutoDoxygenFileDirective(_BaseFileDirective):
directive_name = 'autodoxygenfile'
directive_name = "autodoxygenfile"
required_arguments = 1
option_spec = {
@ -104,6 +104,6 @@ class AutoDoxygenFileDirective(_BaseFileDirective):
project_info = self.project_info_factory.retrieve_project_info_for_auto(self.options)
except ProjectError as e:
warning = self.create_warning(None)
return warning.warn('autodoxygenfile: %s' % e)
return warning.warn("autodoxygenfile: %s" % e)
return self.handle_contents(file_, project_info)

143
breathe/directives/function.py

@ -5,9 +5,7 @@ from breathe.parser import ParserError, FileIOError
from breathe.project import ProjectError
from breathe.renderer import format_parser_error, RenderContext
from breathe.renderer.sphinxrenderer import WithContext
from breathe.renderer.mask import (
MaskFactory, NullMaskFactory, NoParameterNamesMask
)
from breathe.renderer.mask import MaskFactory, NullMaskFactory, NoParameterNamesMask
from breathe.renderer.sphinxrenderer import SphinxRenderer
from breathe.renderer.target import create_target_handler
@ -61,13 +59,13 @@ class DoxygenFunctionDirective(BaseDirective):
project_info = self.project_info_factory.create_project_info(self.options)
except ProjectError as e:
warning = self.create_warning(None)
return warning.warn('doxygenfunction: %s' % e)
return warning.warn("doxygenfunction: %s" % e)
try:
finder = self.finder_factory.create_finder(project_info)
except MTimeError as e:
warning = self.create_warning(None)
return warning.warn('doxygenfunction: %s' % e)
return warning.warn("doxygenfunction: %s" % e)
# Extract arguments from the function name.
try:
@ -75,16 +73,19 @@ class DoxygenFunctionDirective(BaseDirective):
except cpp.DefinitionError as e:
return self.create_warning(
project_info,
namespace='%s::' % namespace if namespace else '',
namespace="%s::" % namespace if namespace else "",
function=function_name,
args=str(args),
cpperror=str(e)
).warn('doxygenfunction: Unable to resolve function '
'"{namespace}{function}" with arguments "{args}".\n'
'Could not parse arguments. Parsing eror is\n{cpperror}')
cpperror=str(e),
).warn(
"doxygenfunction: Unable to resolve function "
'"{namespace}{function}" with arguments "{args}".\n'
"Could not parse arguments. Parsing eror is\n{cpperror}"
)
finder_filter = self.filter_factory.create_function_and_all_friend_finder_filter(
namespace, function_name)
namespace, function_name
)
# TODO: find a more specific type for the Doxygen nodes
matchesAll = [] # type: List[Any]
@ -94,7 +95,7 @@ class DoxygenFunctionDirective(BaseDirective):
# only take functions and friend functions
# ignore friend classes
node = m[0]
if node.kind == 'friend' and not node.argsstring:
if node.kind == "friend" and not node.argsstring:
continue
matches.append(m)
@ -102,55 +103,61 @@ class DoxygenFunctionDirective(BaseDirective):
# clauses below
warning = self.create_warning(
project_info,
namespace='%s::' % namespace if namespace else '',
namespace="%s::" % namespace if namespace else "",
function=function_name,
args=str(args)
args=str(args),
)
try:
node_stack = self._resolve_function(matches, args, project_info)
except _NoMatchingFunctionError:
return warning.warn('doxygenfunction: Cannot find function "{namespace}{function}" '
'{tail}')
return warning.warn(
'doxygenfunction: Cannot find function "{namespace}{function}" ' "{tail}"
)
except _UnableToResolveFunctionError as error:
message = 'doxygenfunction: Unable to resolve function ' \
'"{namespace}{function}" with arguments {args} {tail}.\n' \
'Potential matches:\n'
message = (
"doxygenfunction: Unable to resolve function "
'"{namespace}{function}" with arguments {args} {tail}.\n'
"Potential matches:\n"
)
text = ''
text = ""
for i, entry in enumerate(sorted(error.signatures)):
text += '- %s\n' % entry
block = nodes.literal_block('', '', nodes.Text(text))
text += "- %s\n" % entry
block = nodes.literal_block("", "", nodes.Text(text))
formatted_message = warning.format(message)
warning_nodes = [
nodes.paragraph("", "", nodes.Text(formatted_message)),
block
]
result = warning.warn(message, rendered_nodes=warning_nodes,
unformatted_suffix=text)
warning_nodes = [nodes.paragraph("", "", nodes.Text(formatted_message)), block]
result = warning.warn(message, rendered_nodes=warning_nodes, unformatted_suffix=text)
return result
except cpp.DefinitionError as error:
warning.context['cpperror'] = str(error)
warning.context["cpperror"] = str(error)
return warning.warn(
'doxygenfunction: Unable to resolve function '
"doxygenfunction: Unable to resolve function "
'"{namespace}{function}" with arguments "{args}".\n'
'Candidate function could not be parsed. Parsing error is\n{cpperror}')
"Candidate function could not be parsed. Parsing error is\n{cpperror}"
)
target_handler = create_target_handler(self.options, project_info, self.state.document)
filter_ = self.filter_factory.create_outline_filter(self.options)
return self.render(node_stack, project_info, filter_, target_handler, NullMaskFactory(),
self.directive_args)
return self.render(
node_stack,
project_info,
filter_,
target_handler,
NullMaskFactory(),
self.directive_args,
)
def _parse_args(self, function_description: str) -> Optional[cpp.ASTParametersQualifiers]:
# Note: the caller must catch cpp.DefinitionError
if function_description == '':
if function_description == "":
return None
parser = cpp.DefinitionParser(function_description,
location=self.get_source_info(),
config=self.config)
paramQual = parser._parse_parameters_and_qualifiers(paramMode='function')
parser = cpp.DefinitionParser(
function_description, location=self.get_source_info(), config=self.config
)
paramQual = parser._parse_parameters_and_qualifiers(paramMode="function")
# strip everything that doesn't contribute to overloading
def stripParamQual(paramQual):
@ -168,23 +175,26 @@ class DoxygenFunctionDirective(BaseDirective):
declarator = p.arg.type.decl
def stripDeclarator(declarator):
if hasattr(declarator, 'next'):
if hasattr(declarator, "next"):
stripDeclarator(declarator.next)
if isinstance(declarator, cpp.ASTDeclaratorParen):
assert hasattr(declarator, 'inner')
assert hasattr(declarator, "inner")
stripDeclarator(declarator.inner)
else:
assert isinstance(declarator, cpp.ASTDeclaratorNameParamQual)
assert hasattr(declarator, 'declId')
assert hasattr(declarator, "declId")
declarator.declId = None # type: ignore
if declarator.paramQual is not None:
stripParamQual(declarator.paramQual)
stripDeclarator(declarator)
stripParamQual(paramQual)
return paramQual
def _create_function_signature(self, node_stack, project_info, filter_, target_handler,
mask_factory, directive_args) -> str:
def _create_function_signature(
self, node_stack, project_info, filter_, target_handler, mask_factory, directive_args
) -> str:
"Standard render process used by subclasses"
try:
@ -199,11 +209,13 @@ class DoxygenFunctionDirective(BaseDirective):
filter_,
)
except ParserError as e:
return format_parser_error("doxygenclass", e.error, e.filename, self.state,
self.lineno, True)
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, False)
return format_parser_error(
"doxygenclass", e.error, e.filename, self.state, self.lineno, False
)
context = RenderContext(node_stack, mask_factory, directive_args)
node = node_stack[0]
@ -211,16 +223,18 @@ class DoxygenFunctionDirective(BaseDirective):
# this part should be kept in sync with visit_function in sphinxrenderer
name = node.get_name()
# assume we are only doing this for C++ declarations
declaration = ' '.join([
object_renderer.create_template_prefix(node),
''.join(n.astext() for n in object_renderer.render(node.get_type())),
name,
node.get_argsstring()
])
parser = cpp.DefinitionParser(declaration,
location=self.get_source_info(),
config=self.config)
ast = parser.parse_declaration('function', 'function')
declaration = " ".join(
[
object_renderer.create_template_prefix(node),
"".join(n.astext() for n in object_renderer.render(node.get_type())),
name,
node.get_argsstring(),
]
)
parser = cpp.DefinitionParser(
declaration, location=self.get_source_info(), config=self.config
)
ast = parser.parse_declaration("function", "function")
return str(ast)
def _resolve_function(self, matches, args: Optional[cpp.ASTParametersQualifiers], project_info):
@ -230,21 +244,22 @@ class DoxygenFunctionDirective(BaseDirective):
res = []
candSignatures = []
for entry in matches:
text_options = {'no-link': u'', 'outline': u''}
text_options = {"no-link": u"", "outline": u""}
# Render the matches to docutils nodes
target_handler = create_target_handler({'no-link': u''},
project_info, self.state.document)
target_handler = create_target_handler(
{"no-link": u""}, project_info, self.state.document
)
filter_ = self.filter_factory.create_outline_filter(text_options)
mask_factory = MaskFactory({'param': NoParameterNamesMask})
mask_factory = MaskFactory({"param": NoParameterNamesMask})
# Override the directive args for this render
directive_args = self.directive_args[:]
directive_args[2] = text_options
signature = self._create_function_signature(entry, project_info, filter_,
target_handler,
mask_factory, directive_args)
signature = self._create_function_signature(
entry, project_info, filter_, target_handler, mask_factory, directive_args
)
candSignatures.append(signature)
if args is not None:

22
breathe/directives/index.py

@ -15,8 +15,7 @@ class RootDataObject:
class _BaseIndexDirective(BaseDirective):
"""Base class handle the main work when given the appropriate project info to work from.
"""
"""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
@ -26,8 +25,9 @@ class _BaseIndexDirective(BaseDirective):
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)
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)
@ -44,18 +44,18 @@ class _BaseIndexDirective(BaseDirective):
self.state.document,
target_handler,
self.parser_factory.create_compound_parser(project_info),
filter_
filter_,
)
mask_factory = NullMaskFactory()
context = RenderContext([data_object, RootDataObject()], mask_factory,
self.directive_args)
context = RenderContext([data_object, RootDataObject()], mask_factory, self.directive_args)
try:
node_list = object_renderer.render(context.node_stack[0], context)
except ParserError as e:
return format_parser_error(self.name, e.error, e.filename, self.state,
self.lineno, True)
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)
@ -80,7 +80,7 @@ class DoxygenIndexDirective(_BaseIndexDirective):
project_info = self.project_info_factory.create_project_info(self.options)
except ProjectError as e:
warning = self.create_warning(None)
return warning.warn('doxygenindex: %s' % e)
return warning.warn("doxygenindex: %s" % e)
return self.handle_contents(project_info)
@ -104,6 +104,6 @@ class AutoDoxygenIndexDirective(_BaseIndexDirective):
project_info = self.project_info_factory.retrieve_project_info_for_auto(self.options)
except ProjectError as e:
warning = self.create_warning(None)
return warning.warn('autodoxygenindex: %s' % e)
return warning.warn("autodoxygenindex: %s" % e)
return self.handle_contents(project_info)

19
breathe/directives/item.py

@ -20,14 +20,13 @@ class _DoxygenBaseItemDirective(BaseDirective):
"project": unchanged_required,
"outline": flag,
"no-link": flag,
}
}
has_content = False
def create_finder_filter(self, namespace: str, name: str) -> Filter:
"""Creates a filter to find the node corresponding to this item."""
return self.filter_factory.create_member_finder_filter(
namespace, name, self.kind)
return self.filter_factory.create_member_finder_filter(namespace, name, self.kind)
def run(self) -> List[Node]:
try:
@ -39,13 +38,13 @@ class _DoxygenBaseItemDirective(BaseDirective):
project_info = self.project_info_factory.create_project_info(self.options)
except ProjectError as e:
warning = self.create_warning(None, kind=self.kind)
return warning.warn('doxygen{kind}: %s' % e)
return warning.warn("doxygen{kind}: %s" % e)
try:
finder = self.finder_factory.create_finder(project_info)
except MTimeError as e:
warning = self.create_warning(None, kind=self.kind)
return warning.warn('doxygen{kind}: %s' % e)
return warning.warn("doxygen{kind}: %s" % e)
finder_filter = self.create_finder_filter(namespace, name)
@ -55,8 +54,7 @@ class _DoxygenBaseItemDirective(BaseDirective):
if len(matches) == 0:
display_name = "%s::%s" % (namespace, name) if namespace else name
warning = self.create_warning(project_info, kind=self.kind,
display_name=display_name)
warning = self.create_warning(project_info, kind=self.kind, display_name=display_name)
return warning.warn('doxygen{kind}: Cannot find {kind} "{display_name}" {tail}')
target_handler = create_target_handler(self.options, project_info, self.state.document)
@ -64,8 +62,9 @@ class _DoxygenBaseItemDirective(BaseDirective):
node_stack = matches[0]
mask_factory = NullMaskFactory()
return self.render(node_stack, project_info, filter_, target_handler, mask_factory,
self.directive_args)
return self.render(
node_stack, project_info, filter_, target_handler, mask_factory, self.directive_args
)
class DoxygenVariableDirective(_DoxygenBaseItemDirective):
@ -100,4 +99,4 @@ class DoxygenUnionDirective(_DoxygenBaseItemDirective):
# type dependent
#
xml_name = "%s::%s" % (namespace, name) if namespace else name
return self.filter_factory.create_compound_finder_filter(xml_name, 'union')
return self.filter_factory.create_compound_finder_filter(xml_name, "union")

73
breathe/directives/setup.py

@ -1,16 +1,24 @@
from breathe.directives import BaseDirective
from breathe.directives.class_like import (
DoxygenStructDirective, DoxygenClassDirective, DoxygenInterfaceDirective,
DoxygenStructDirective,
DoxygenClassDirective,
DoxygenInterfaceDirective,
)
from breathe.directives.content_block import (
DoxygenNamespaceDirective, DoxygenGroupDirective, DoxygenPageDirective,
DoxygenNamespaceDirective,
DoxygenGroupDirective,
DoxygenPageDirective,
)
from breathe.directives.file import DoxygenFileDirective, AutoDoxygenFileDirective
from breathe.directives.function import DoxygenFunctionDirective
from breathe.directives.index import DoxygenIndexDirective, AutoDoxygenIndexDirective
from breathe.directives.item import (
DoxygenVariableDirective, DoxygenDefineDirective, DoxygenUnionDirective,
DoxygenEnumDirective, DoxygenEnumValueDirective, DoxygenTypedefDirective,
DoxygenVariableDirective,
DoxygenDefineDirective,
DoxygenUnionDirective,
DoxygenEnumDirective,
DoxygenEnumValueDirective,
DoxygenTypedefDirective,
)
from breathe.finder.factory import FinderFactory
from breathe.parser import DoxygenParserFactory
@ -26,9 +34,14 @@ from typing import Any, List, Optional, Type # noqa
class DirectiveContainer:
def __init__(self, app: Sphinx, directive: Type[BaseDirective],
finder_factory: FinderFactory, project_info_factory: ProjectInfoFactory,
parser_factory: DoxygenParserFactory):
def __init__(
self,
app: Sphinx,
directive: Type[BaseDirective],
finder_factory: FinderFactory,
project_info_factory: ProjectInfoFactory,
parser_factory: DoxygenParserFactory,
):
self.app = app
self.directive = directive
self.finder_factory = finder_factory
@ -43,11 +56,7 @@ class DirectiveContainer:
self.final_argument_whitespace = directive.final_argument_whitespace
def __call__(self, *args):
call_args = [
self.finder_factory,
self.project_info_factory,
self.parser_factory
]
call_args = [self.finder_factory, self.project_info_factory, self.parser_factory]
call_args.extend(args)
return self.directive(*call_args)
@ -82,34 +91,34 @@ def setup(app: Sphinx) -> None:
for name, directive in directives.items():
# ordinarily app.add_directive takes a class it self, but we need to inject extra arguments
# so we give a DirectiveContainer object which has an overloaded __call__ operator.
app.add_directive(name, DirectiveContainer( # type: ignore
app,
directive,
finder_factory,
project_info_factory,
parser_factory
))
app.add_directive(
name,
DirectiveContainer( # type: ignore
app, directive, finder_factory, project_info_factory, parser_factory
),
)
app.add_config_value("breathe_projects", {}, True) # Dict[str, str]
app.add_config_value("breathe_default_project", "", True) # str
# Provide reasonable defaults for domain_by_extension mapping. Can be overridden by users.
app.add_config_value("breathe_domain_by_extension",
{'py': 'py', 'cs': 'cs'}, True) # Dict[str, str]
app.add_config_value(
"breathe_domain_by_extension", {"py": "py", "cs": "cs"}, True
) # Dict[str, str]
app.add_config_value("breathe_domain_by_file_pattern", {}, True) # Dict[str, str]
app.add_config_value("breathe_projects_source", {}, True)
app.add_config_value("breathe_build_directory", '', True)
app.add_config_value("breathe_build_directory", "", True)
app.add_config_value("breathe_default_members", (), True)
app.add_config_value("breathe_show_define_initializer", False, 'env')
app.add_config_value("breathe_show_enumvalue_initializer", False, 'env')
app.add_config_value("breathe_implementation_filename_extensions", ['.c', '.cc', '.cpp'], True)
app.add_config_value("breathe_show_define_initializer", False, "env")
app.add_config_value("breathe_show_enumvalue_initializer", False, "env")
app.add_config_value("breathe_implementation_filename_extensions", [".c", ".cc", ".cpp"], True)
app.add_config_value("breathe_doxygen_config_options", {}, True)
app.add_config_value("breathe_doxygen_aliases", {}, True)
app.add_config_value("breathe_use_project_refids", False, "env")
app.add_config_value("breathe_order_parameters_first", False, 'env')
app.add_config_value("breathe_separate_member_pages", False, 'env')
app.add_config_value("breathe_order_parameters_first", False, "env")
app.add_config_value("breathe_separate_member_pages", False, "env")
breathe_css = "breathe.css"
if (os.path.exists(os.path.join(app.confdir, "_static", breathe_css))): # type: ignore
if os.path.exists(os.path.join(app.confdir, "_static", breathe_css)): # type: ignore
app.add_css_file(breathe_css)
def write_file(directory, filename, content):
@ -122,14 +131,14 @@ def setup(app: Sphinx) -> None:
f.write(content)
doxygen_handle = AutoDoxygenProcessHandle(
subprocess.check_call,
write_file,
project_info_factory)
subprocess.check_call, write_file, project_info_factory
)
def doxygen_hook(app):
doxygen_handle.generate_xml(
app.config.breathe_projects_source,
app.config.breathe_doxygen_config_options,
app.config.breathe_doxygen_aliases
app.config.breathe_doxygen_aliases,
)
app.connect("builder-inited", doxygen_hook)

1
breathe/exception.py

@ -1,3 +1,2 @@
class BreatheError(Exception):
pass

10
breathe/file_state_cache.py

@ -24,7 +24,7 @@ def _getmtime(filename: str):
try:
return os.path.getmtime(filename)
except OSError:
raise MTimeError('Cannot find file: %s' % os.path.realpath(filename))
raise MTimeError("Cannot find file: %s" % os.path.realpath(filename))
def update(app: Sphinx, source_file: str) -> None:
@ -33,7 +33,8 @@ def update(app: Sphinx, source_file: str) -> None:
new_mtime = _getmtime(source_file)
mtime, docnames = app.env.breathe_file_state.setdefault( # type: ignore
source_file, (new_mtime, set()))
source_file, (new_mtime, set())
)
assert app.env is not None
docnames.add(app.env.docname)
@ -41,8 +42,9 @@ def update(app: Sphinx, source_file: str) -> None:
app.env.breathe_file_state[source_file] = (new_mtime, docnames) # type: ignore
def _get_outdated(app: Sphinx, env: BuildEnvironment,
added: Set[str], changed: Set[str], removed: Set[str]) -> List[str]:
def _get_outdated(
app: Sphinx, env: BuildEnvironment, added: Set[str], changed: Set[str], removed: Set[str]
) -> List[str]:
if not hasattr(app.env, "breathe_file_state"):
return []

3
breathe/finder/__init__.py

@ -12,8 +12,7 @@ def stack(element, list_):
class ItemFinder:
def __init__(self, project_info: ProjectInfo, data_object,
item_finder_factory):
def __init__(self, project_info: ProjectInfo, data_object, item_finder_factory):
self.data_object = data_object
# DoxygenItemFinderFactory, but actually typing it would introduce an import cycle
self.item_finder_factory = item_finder_factory

2
breathe/finder/compound.py

@ -49,7 +49,7 @@ class MemberDefTypeSubItemFinder(ItemFinder):
if filter_.allow(node_stack):
matches.append(node_stack)
if data_object.kind == 'enum':
if data_object.kind == "enum":
for value in data_object.enumvalue:
value_stack = stack(value, node_stack)
if filter_.allow(value_stack):

3
breathe/finder/factory.py

@ -17,8 +17,7 @@ class _CreateCompoundTypeSubFinder:
def __call__(self, project_info: ProjectInfo, *args):
compound_parser = self.parser_factory.create_compound_parser(project_info)
return indexfinder.CompoundTypeSubItemFinder(self.app, compound_parser,
project_info, *args)
return indexfinder.CompoundTypeSubItemFinder(self.app, compound_parser, project_info, *args)
class DoxygenItemFinderFactory:

3
breathe/finder/index.py

@ -55,7 +55,8 @@ class CompoundTypeSubItemFinder(ItemFinder):
for member_stack in member_matches:
ref_filter = self.filter_factory.create_id_filter(
'memberdef', member_stack[0].refid)
"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

2
breathe/path_handler.py

@ -6,7 +6,7 @@ import os
def includes_directory(file_path: str):
# Check for backslash or forward slash as we don't know what platform we're on and sometimes
# the doxygen paths will have forward slash even on Windows.
return bool(file_path.count('\\')) or bool(file_path.count('/'))
return bool(file_path.count("\\")) or bool(file_path.count("/"))
def resolve_path(app: Sphinx, directory: str, filename: str):

26
breathe/process.py

@ -57,7 +57,8 @@ class AutoDoxygenProcessHandle:
contents = file_structure[1]
auto_project_info = self.project_info_factory.create_auto_project_info(
project_name, folder)
project_name, folder
)
project_files[project_name] = ProjectData(auto_project_info, contents)
@ -66,10 +67,8 @@ class AutoDoxygenProcessHandle:
for project_name, data in project_files.items():
project_path = self.process(
data.auto_project_info,
data.files,
doxygen_options,
doxygen_aliases)
data.auto_project_info, data.files, doxygen_options, doxygen_aliases
)
project_info = data.auto_project_info.create_project_info(project_path)
@ -83,27 +82,24 @@ class AutoDoxygenProcessHandle:
full_paths = map(lambda x: auto_project_info.abs_path_to_source_file(x), files)
options = "\n".join("%s=%s" % pair for pair in doxygen_options.items())
aliases = '\n'.join(
f'ALIASES += {name}="{value}"' for name, value in doxygen_aliases.items())
aliases = "\n".join(
f'ALIASES += {name}="{value}"' for name, value in doxygen_aliases.items()
)
cfg = AUTOCFG_TEMPLATE.format(
project_name=name,
output_dir=name,
input=" ".join(full_paths),
extra=f"{options}\n{aliases}"
)
extra=f"{options}\n{aliases}",