From: Martin Quinson Date: Sun, 10 Nov 2019 21:09:16 +0000 (+0100) Subject: Meld autodoxy into a single file for sake of import simplicity X-Git-Tag: v3.25~411 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/bd02d3682100837c80468bb5b24d06cafa64cd30 Meld autodoxy into a single file for sake of import simplicity --- diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b3f0665323..7c355ce85a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,7 @@ pages: - make -j4 - pip3 install --requirement docs/requirements.txt - cd docs - - LC_ALL=C.UTF-8 SPHINXOPTS=-vv PYTHONPATH=/builds/simgrid/simgrid/docs/source/_ext/autodoxy ./Build.sh + - LC_ALL=C.UTF-8 SPHINXOPTS=-vv ./Build.sh - mv build/html ../public # - The CSS contains a reference to a font or something, not something we gonna fix on our side # - The javasphinx output does not exist in the git, so the "edit on FramaGit" link is broken. diff --git a/docs/source/_ext/autodoxy/autodoxy/autodoxy.py b/docs/source/_ext/autodoxy.py similarity index 65% rename from docs/source/_ext/autodoxy/autodoxy/autodoxy.py rename to docs/source/_ext/autodoxy.py index 40ca007782..4d36e795d1 100644 --- a/docs/source/_ext/autodoxy/autodoxy/autodoxy.py +++ b/docs/source/_ext/autodoxy.py @@ -1,15 +1,181 @@ +""" +This is autodoxy, a sphinx extension providing autodoc-like directives +that are feed with Doxygen files. + +It is highly inspired from the autodoc_doxygen sphinx extension, but +adapted to my own needs in SimGrid. +https://github.com/rmcgibbo/sphinxcontrib-autodoc_doxygen + +Licence: MIT +Copyright (c) 2015 Robert T. McGibbon +Copyright (c) 2019 Martin Quinson +""" from __future__ import print_function, absolute_import, division +import os.path +import re +import sys + from six import itervalues from lxml import etree as ET from sphinx.ext.autodoc import Documenter, AutoDirective, members_option, ALL from sphinx.errors import ExtensionError from sphinx.util import logging -from . import get_doxygen_root -from .xmlutils import format_xml_paragraph -import sys +########################################################################## +# XML utils +########################################################################## +def format_xml_paragraph(xmlnode): + """Format an Doxygen XML segment (principally a detaileddescription) + as a paragraph for inclusion in the rst document + + Parameters + ---------- + xmlnode + + Returns + ------- + lines + A list of lines. + """ + return [l.rstrip() for l in _DoxygenXmlParagraphFormatter().generic_visit(xmlnode).lines] + + +class _DoxygenXmlParagraphFormatter(object): + # This class follows the model of the stdlib's ast.NodeVisitor for tree traversal + # where you dispatch on the element type to a different method for each node + # during the traverse. + + # It's supposed to handle paragraphs, references, preformatted text (code blocks), and lists. + + def __init__(self): + self.lines = [''] + self.continue_line = False + + def visit(self, node): + method = 'visit_' + node.tag + visitor = getattr(self, method, self.generic_visit) + return visitor(node) + + def generic_visit(self, node): + for child in node.getchildren(): + self.visit(child) + return self + + def visit_ref(self, node): + ref = get_doxygen_root().findall('.//*[@id="%s"]' % node.get('refid')) + if ref: + ref = ref[0] + if ref.tag == 'memberdef': + parent = ref.xpath('./ancestor::compounddef/compoundname')[0].text + name = ref.find('./name').text + real_name = parent + '::' + name + elif ref.tag in ('compounddef', 'enumvalue'): + name_node = ref.find('./name') + real_name = name_node.text if name_node is not None else '' + else: + raise NotImplementedError(ref.tag) + else: + real_name = None + + val = [':cpp:any:`', node.text] + if real_name: + val.extend((' <', real_name, '>`')) + else: + val.append('`') + if node.tail is not None: + val.append(node.tail) + + self.lines[-1] += ''.join(val) + + def visit_para(self, node): + if node.text is not None: + if self.continue_line: + self.lines[-1] += node.text + else: + self.lines.append(node.text) + self.generic_visit(node) + self.lines.append('') + self.continue_line = False + + def visit_verbatim(self, node): + if node.text is not None: + # remove the leading ' *' of any lines + lines = [re.sub('^\s*\*','', l) for l in node.text.split('\n')] + # Merge each paragraph together + text = re.sub("\n\n", "PaRaGrraphSplit", '\n'.join(lines)) + text = re.sub('\n', '', text) + lines = text.split('PaRaGrraphSplit') + + # merge content to the built doc + if self.continue_line: + self.lines[-1] += lines[0] + lines = lines[1:] + for l in lines: + self.lines.append('') + self.lines.append(l) + self.generic_visit(node) + self.lines.append('') + self.continue_line = False + + def visit_parametername(self, node): + if 'direction' in node.attrib: + direction = '[%s] ' % node.get('direction') + else: + direction = '' + + self.lines.append('**%s** -- %s' % ( + node.text, direction)) + self.continue_line = True + + def visit_parameterlist(self, node): + lines = [l for l in type(self)().generic_visit(node).lines if l is not ''] + self.lines.extend([':parameters:', ''] + ['* %s' % l for l in lines] + ['']) + + def visit_simplesect(self, node): + if node.get('kind') == 'return': + self.lines.append(':returns: ') + self.continue_line = True + self.generic_visit(node) + + def visit_listitem(self, node): + self.lines.append(' - ') + self.continue_line = True + self.generic_visit(node) + + def visit_preformatted(self, node): + segment = [node.text if node.text is not None else ''] + for n in node.getchildren(): + segment.append(n.text) + if n.tail is not None: + segment.append(n.tail) + + lines = ''.join(segment).split('\n') + self.lines.extend(('.. code-block:: C++', '')) + self.lines.extend([' ' + l for l in lines]) + + def visit_computeroutput(self, node): + c = node.find('preformatted') + if c is not None: + return self.visit_preformatted(c) + return self.visit_preformatted(node) + + def visit_xrefsect(self, node): + if node.find('xreftitle').text == 'Deprecated': + sublines = type(self)().generic_visit(node).lines + self.lines.extend(['.. admonition:: Deprecated'] + [' ' + s for s in sublines]) + else: + raise ValueError(node) + + def visit_subscript(self, node): + self.lines[-1] += '\ :sub:`%s` %s' % (node.text, node.tail) + + +########################################################################## +# Directives +########################################################################## + class DoxygenDocumenter(Documenter): # Variables to store the names of the object being documented. modname and fullname are redundant, @@ -368,3 +534,57 @@ class DoxygenVariableDocumenter(DoxygenDocumenter): def document_members(self, all_members=False): pass + +########################################################################## +# Setup the extension +########################################################################## +def set_doxygen_xml(app): + """Load all doxygen XML files from the app config variable + `app.config.doxygen_xml` which should be a path to a directory + containing doxygen xml output + """ + err = ExtensionError( + '[autodoxy] No doxygen xml output found in doxygen_xml="%s"' % app.config.doxygen_xml) + + if not os.path.isdir(app.config.doxygen_xml): + raise err + + files = [os.path.join(app.config.doxygen_xml, f) + for f in os.listdir(app.config.doxygen_xml) + if f.lower().endswith('.xml') and not f.startswith('._')] + if len(files) == 0: + raise err + + setup.DOXYGEN_ROOT = ET.ElementTree(ET.Element('root')).getroot() + for file in files: + root = ET.parse(file).getroot() + for node in root: + setup.DOXYGEN_ROOT.append(node) + + +def get_doxygen_root(): + """Get the root element of the doxygen XML document. + """ + if not hasattr(setup, 'DOXYGEN_ROOT'): + setup.DOXYGEN_ROOT = ET.Element("root") # dummy + return setup.DOXYGEN_ROOT + + +def setup(app): + import sphinx.ext.autosummary + + app.connect("builder-inited", set_doxygen_xml) +# app.connect("builder-inited", process_generate_options) + + app.setup_extension('sphinx.ext.autodoc') +# app.setup_extension('sphinx.ext.autosummary') + + app.add_autodocumenter(DoxygenClassDocumenter) + app.add_autodocumenter(DoxygenMethodDocumenter) + app.add_autodocumenter(DoxygenVariableDocumenter) + app.add_config_value("doxygen_xml", "", True) + +# app.add_directive('autodoxysummary', DoxygenAutosummary) +# app.add_directive('autodoxyenum', DoxygenAutoEnum) + + return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/docs/source/_ext/autodoxy/README b/docs/source/_ext/autodoxy/README deleted file mode 100644 index 6e4e936a2c..0000000000 --- a/docs/source/_ext/autodoxy/README +++ /dev/null @@ -1,31 +0,0 @@ -This is autodoxy, a sphinx extension providing autodoc-like directives -that are feed with Doxygen files. - -It is highly inspired from the autodoc_doxygen sphinx extension, but -adapted to my own needs in SimGrid. -https://github.com/rmcgibbo/sphinxcontrib-autodoc_doxygen - -The MIT License (MIT) - -Copyright (c) 2015 Robert T. McGibbon -Copytight (c) 2019 Martin Quinson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/docs/source/_ext/autodoxy/__init__.py b/docs/source/_ext/autodoxy/__init__.py deleted file mode 100644 index c113b0296a..0000000000 --- a/docs/source/_ext/autodoxy/__init__.py +++ /dev/null @@ -1,57 +0,0 @@ -import os.path -from lxml import etree as ET -from sphinx.errors import ExtensionError - -import sphinx.ext.autosummary -from autodoxy import DoxygenClassDocumenter, DoxygenMethodDocumenter, DoxygenTypeDocumenter -from autodoxy.autosummary import DoxygenAutosummary, DoxygenAutoEnum -from autodoxy.autosummary.generate import process_generate_options - -def set_doxygen_xml(app): - """Load all doxygen XML files from the app config variable - `app.config.doxygen_xml` which should be a path to a directory - containing doxygen xml output - """ - err = ExtensionError( - '[autodoxy] No doxygen xml output found in doxygen_xml="%s"' % app.config.doxygen_xml) - - if not os.path.isdir(app.config.doxygen_xml): - raise err - - files = [os.path.join(app.config.doxygen_xml, f) - for f in os.listdir(app.config.doxygen_xml) - if f.lower().endswith('.xml') and not f.startswith('._')] - if len(files) == 0: - raise err - - setup.DOXYGEN_ROOT = ET.ElementTree(ET.Element('root')).getroot() - for file in files: - root = ET.parse(file).getroot() - for node in root: - setup.DOXYGEN_ROOT.append(node) - -def get_doxygen_root(): - """Get the root element of the doxygen XML document. - """ - if not hasattr(setup, 'DOXYGEN_ROOT'): - setup.DOXYGEN_ROOT = ET.Element("root") # dummy - return setup.DOXYGEN_ROOT - -def setup(app): - - app.connect("builder-inited", set_doxygen_xml) - app.connect("builder-inited", process_generate_options) - - app.setup_extension('sphinx.ext.autodoc') - app.setup_extension('sphinx.ext.autosummary') - - app.add_autodocumenter(DoxygenClassDocumenter) - app.add_autodocumenter(DoxygenMethodDocumenter) - app.add_autodocumenter(DoxygenTypeDocumenter) - app.add_config_value("doxygen_xml", "", 'env') - app.add_config_value('autosummary_toctree', '', 'html') - - app.add_directive('autodoxysummary', DoxygenAutosummary) - app.add_directive('autodoxyenum', DoxygenAutoEnum) - - return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/docs/source/_ext/autodoxy/autodoxy/__init__.py b/docs/source/_ext/autodoxy/autodoxy/__init__.py deleted file mode 100644 index 232dfc91b4..0000000000 --- a/docs/source/_ext/autodoxy/autodoxy/__init__.py +++ /dev/null @@ -1,58 +0,0 @@ -import os.path -from lxml import etree as ET -from sphinx.errors import ExtensionError - - -def set_doxygen_xml(app): - """Load all doxygen XML files from the app config variable - `app.config.doxygen_xml` which should be a path to a directory - containing doxygen xml output - """ - err = ExtensionError( - '[autodoxy] No doxygen xml output found in doxygen_xml="%s"' % app.config.doxygen_xml) - - if not os.path.isdir(app.config.doxygen_xml): - raise err - - files = [os.path.join(app.config.doxygen_xml, f) - for f in os.listdir(app.config.doxygen_xml) - if f.lower().endswith('.xml') and not f.startswith('._')] - if len(files) == 0: - raise err - - setup.DOXYGEN_ROOT = ET.ElementTree(ET.Element('root')).getroot() - for file in files: - root = ET.parse(file).getroot() - for node in root: - setup.DOXYGEN_ROOT.append(node) - - -def get_doxygen_root(): - """Get the root element of the doxygen XML document. - """ - if not hasattr(setup, 'DOXYGEN_ROOT'): - setup.DOXYGEN_ROOT = ET.Element("root") # dummy - return setup.DOXYGEN_ROOT - - -def setup(app): - import sphinx.ext.autosummary - from autodoxy.autodoxy import DoxygenClassDocumenter, DoxygenMethodDocumenter, DoxygenVariableDocumenter - from autodoxy.autosummary import DoxygenAutosummary, DoxygenAutoEnum - from autodoxy.autosummary.generate import process_generate_options - - app.connect("builder-inited", set_doxygen_xml) - app.connect("builder-inited", process_generate_options) - - app.setup_extension('sphinx.ext.autodoc') - app.setup_extension('sphinx.ext.autosummary') - - app.add_autodocumenter(DoxygenClassDocumenter) - app.add_autodocumenter(DoxygenMethodDocumenter) - app.add_autodocumenter(DoxygenVariableDocumenter) - app.add_config_value("doxygen_xml", "", True) - - app.add_directive('autodoxysummary', DoxygenAutosummary) - app.add_directive('autodoxyenum', DoxygenAutoEnum) - - return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/docs/source/_ext/autodoxy/autodoxy/autosummary/__init__.py b/docs/source/_ext/autodoxy/autodoxy/autosummary/__init__.py deleted file mode 100644 index 0f2b423dc6..0000000000 --- a/docs/source/_ext/autodoxy/autodoxy/autosummary/__init__.py +++ /dev/null @@ -1,224 +0,0 @@ -from __future__ import print_function, absolute_import, division - -import re -import operator -from functools import reduce -from itertools import count, groupby - -from docutils import nodes -from docutils.statemachine import ViewList -from sphinx import addnodes -from sphinx.ext.autosummary import Autosummary, autosummary_table - -from autodoxy import get_doxygen_root -from autodoxy.autodoxy import DoxygenMethodDocumenter, DoxygenClassDocumenter -from autodoxy.xmlutils import format_xml_paragraph - - -def import_by_name(name, env=None, prefixes=None, i=0): - """Get xml documentation for a class/method with a given name. - If there are multiple classes or methods with that name, you - can use the `i` kwarg to pick which one. - """ - if prefixes is None: - prefixes = [None] - - if env is not None: - parent = env.ref_context.get('cpp:parent_symbol') - parent_symbols = [] - while parent is not None and parent.identifier is not None: - parent_symbols.insert(0, str(parent.identifier)) - parent = parent.parent - prefixes.append('::'.join(parent_symbols)) - - tried = [] - for prefix in prefixes: - try: - if prefix: - prefixed_name = '::'.join([prefix, name]) - else: - prefixed_name = name - return _import_by_name(prefixed_name, i=i) - except ImportError: - tried.append(prefixed_name) - raise ImportError('no module named %s' % ' or '.join(tried)) - - -def _import_by_name(name, i=0): - root = get_doxygen_root() - name = name.replace('.', '::') - - if '::' in name: - xpath_query = ( - './/compoundname[text()="%s"]/../' - 'sectiondef[@kind="public-func"]/memberdef[@kind="function"]/' - 'name[text()="%s"]/..') % tuple(name.rsplit('::', 1)) - m = root.xpath(xpath_query) - if len(m) > 0: - obj = m[i] - full_name = '.'.join(name.rsplit('::', 1)) - return full_name, obj, full_name, '' - - xpath_query = ( - './/compoundname[text()="%s"]/../' - 'sectiondef[@kind="public-type"]/memberdef[@kind="enum"]/' - 'name[text()="%s"]/..') % tuple(name.rsplit('::', 1)) - m = root.xpath(xpath_query) - if len(m) > 0: - obj = m[i] - full_name = '.'.join(name.rsplit('::', 1)) - return full_name, obj, full_name, '' - - xpath_query = ('.//compoundname[text()="%s"]/..' % name) - m = root.xpath(xpath_query) - if len(m) > 0: - obj = m[i] - return (name, obj, name, '') - - raise ImportError() - - -def get_documenter(obj, full_name): - if obj.tag == 'memberdef' and obj.get('kind') == 'function': - return DoxygenMethodDocumenter - elif obj.tag == 'compounddef': - return DoxygenClassDocumenter - - raise NotImplementedError(obj.tag) - - -class DoxygenAutosummary(Autosummary): - def get_items(self, names): - """Try to import the given names, and return a list of - ``[(name, signature, summary_string, real_name), ...]``. - """ - env = self.state.document.settings.env - items = [] - - names_and_counts = reduce(operator.add, - [tuple(zip(g, count())) for _, g in groupby(names)]) # type: List[(Str, Int)] - - for name, i in names_and_counts: - display_name = name - if name.startswith('~'): - name = name[1:] - display_name = name.split('::')[-1] - - try: - real_name, obj, parent, modname = import_by_name(name, env=env, i=i) - except ImportError: - self.warn('failed to import %s' % name) - items.append((name, '', '', name)) - continue - - self.result = ViewList() # initialize for each documenter - documenter = get_documenter(obj, parent)(self, real_name, id=obj.get('id')) - if not documenter.parse_name(): - self.warn('failed to parse name %s' % real_name) - items.append((display_name, '', '', real_name)) - continue - if not documenter.import_object(): - self.warn('failed to import object %s' % real_name) - items.append((display_name, '', '', real_name)) - continue - if documenter.options.members and not documenter.check_module(): - continue - # -- Grab the signature - sig = documenter.format_signature() - - # -- Grab the summary - documenter.add_content(None) - doc = list(documenter.process_doc([self.result.data])) - - while doc and not doc[0].strip(): - doc.pop(0) - - # If there's a blank line, then we can assume the first sentence / - # paragraph has ended, so anything after shouldn't be part of the - # summary - for i, piece in enumerate(doc): - if not piece.strip(): - doc = doc[:i] - break - - # Try to find the "first sentence", which may span multiple lines - m = re.search(r"^([A-Z].*?\.)(?:\s|$)", " ".join(doc).strip()) - if m: - summary = m.group(1).strip() - elif doc: - summary = doc[0].strip() - else: - summary = '' - - items.append((display_name, sig, summary, real_name)) - - return items - - def get_tablespec(self): - table_spec = addnodes.tabular_col_spec() - table_spec['spec'] = 'll' - - table = autosummary_table('') - real_table = nodes.table('', classes=['longtable']) - table.append(real_table) - group = nodes.tgroup('', cols=2) - real_table.append(group) - group.append(nodes.colspec('', colwidth=10)) - group.append(nodes.colspec('', colwidth=90)) - body = nodes.tbody('') - group.append(body) - - def append_row(*column_texts): - row = nodes.row('') - for text in column_texts: - node = nodes.paragraph('') - vl = ViewList() - vl.append(text, '') - self.state.nested_parse(vl, 0, node) - try: - if isinstance(node[0], nodes.paragraph): - node = node[0] - except IndexError: - pass - row.append(nodes.entry('', node)) - body.append(row) - return table, table_spec, append_row - - def get_table(self, items): - """Generate a proper list of table nodes for autosummary:: directive. - - *items* is a list produced by :meth:`get_items`. - """ - table, table_spec, append_row = self.get_tablespec() - for name, sig, summary, real_name in items: - qualifier = 'cpp:any' - # required for cpp autolink - full_name = real_name.replace('.', '::') - col1 = ':%s:`%s <%s>`' % (qualifier, name, full_name) - col2 = summary - append_row(col1, col2) - - self.result.append(' .. rubric: sdsf', 0) - return [table_spec, table] - - -class DoxygenAutoEnum(DoxygenAutosummary): - - def get_items(self, names): - env = self.state.document.settings.env - self.name = names[0] - - real_name, obj, parent, modname = import_by_name(self.name, env=env) - names = [n.text for n in obj.findall('./enumvalue/name')] - descriptions = [format_xml_paragraph(d) for d in obj.findall('./enumvalue/detaileddescription')] - return zip(names, descriptions) - - def get_table(self, items): - table, table_spec, append_row = self.get_tablespec() - for name, description in items: - col1 = ':strong:`' + name + '`' - while description and not description[0].strip(): - description.pop(0) - col2 = ' '.join(description) - append_row(col1, col2) - return [nodes.rubric('', 'Enum: %s' % self.name), table] diff --git a/docs/source/_ext/autodoxy/autodoxy/autosummary/generate.py b/docs/source/_ext/autodoxy/autodoxy/autosummary/generate.py deleted file mode 100644 index 0b8d66ac2d..0000000000 --- a/docs/source/_ext/autodoxy/autodoxy/autosummary/generate.py +++ /dev/null @@ -1,204 +0,0 @@ -from __future__ import print_function, absolute_import, division - -import codecs -import os -import re -import sys - -from jinja2 import FileSystemLoader -from jinja2.sandbox import SandboxedEnvironment -from sphinx.jinja2glue import BuiltinTemplateLoader -from sphinx.util.osutil import ensuredir - -from . import import_by_name - - -def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', - base_path=None, builder=None, template_dir=None): - - showed_sources = list(sorted(sources)) - if len(showed_sources) > 20: - showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:] - print('[autosummary] generating autosummary for: %s' % - ', '.join(showed_sources)) - - if output_dir: - print('[autosummary] writing to %s' % output_dir) - - if base_path is not None: - sources = [os.path.join(base_path, filename) for filename in sources] - - # create our own templating environment - template_dirs = [os.path.join(os.path.dirname(__file__), 'templates')] - - if builder is not None: - # allow the user to override the templates - template_loader = BuiltinTemplateLoader() - template_loader.init(builder, dirs=template_dirs) - else: - if template_dir: - template_dirs.insert(0, template_dir) - template_loader = FileSystemLoader(template_dirs) - template_env = SandboxedEnvironment(loader=template_loader) - - # read - items = find_autosummary_in_files(sources) - - # keep track of new files - new_files = [] - - for name, path, template_name in sorted(set(items), key=str): - if path is None: - # The corresponding autosummary:: directive did not have - # a :toctree: option - continue - - path = output_dir or os.path.abspath(path) - ensuredir(path) - - try: - name, obj, parent, mod_name = import_by_name(name) - except ImportError as e: - print('WARNING [autosummary] failed to import %r: %s' % (name, e), file=sys.stderr) - continue - - fn = os.path.join(path, name + suffix).replace('::', '.') - - # skip it if it exists - if os.path.isfile(fn): - continue - - new_files.append(fn) - - if template_name is None: - if obj.tag == 'compounddef' and obj.get('kind') == 'class': - template_name = 'doxyclass.rst.in' - else: - raise NotImplementedError('No template for %s' % obj) - - with open(fn, 'w') as f: - template = template_env.get_template(template_name) - ns = {} - if obj.tag == 'compounddef' and obj.get('kind') == 'class': - ns['methods'] = [e.text for e in obj.findall('.//sectiondef[@kind="public-func"]/memberdef[@kind="function"]/name')] - ns['enums'] = [e.text for e in obj.findall('.//sectiondef[@kind="public-type"]/memberdef[@kind="enum"]/name')] - ns['objtype'] = 'class' - else: - raise NotImplementedError(obj) - - parts = name.split('::') - mod_name, obj_name = '::'.join(parts[:-1]), parts[-1] - - ns['fullname'] = name - ns['module'] = mod_name - ns['objname'] = obj_name - ns['name'] = parts[-1] - ns['underline'] = len(name) * '=' - - rendered = template.render(**ns) - f.write(rendered) - - # descend recursively to new files - if new_files: - generate_autosummary_docs(new_files, output_dir=output_dir, - suffix=suffix, base_path=base_path, builder=builder, - template_dir=template_dir) - - -def find_autosummary_in_files(filenames): - """Find out what items are documented in source/*.rst. - - See `find_autosummary_in_lines`. - """ - documented = [] - for filename in filenames: - with codecs.open(filename, 'r', encoding='utf-8', - errors='ignore') as f: - lines = f.read().splitlines() - documented.extend(find_autosummary_in_lines(lines, - filename=filename)) - return documented - - -def find_autosummary_in_lines(lines, module=None, filename=None): - """Find out what items appear in autosummary:: directives in the - given lines. - - Returns a list of (name, toctree, template) where *name* is a name - of an object and *toctree* the :toctree: path of the corresponding - autosummary directive (relative to the root of the file name), and - *template* the value of the :template: option. *toctree* and - *template* ``None`` if the directive does not have the - corresponding options set. - """ - autosummary_re = re.compile(r'^(\s*)\.\.\s+autodoxysummary::\s*') - autosummary_item_re = re.compile(r'^\s+(~?[_a-zA-Z][a-zA-Z0-9_.:]*)\s*.*?') - toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$') - template_arg_re = re.compile(r'^\s+:template:\s*(.*?)\s*$') - - documented = [] - - toctree = None - template = None - in_autosummary = False - base_indent = "" - - for line in lines: - if in_autosummary: - m = toctree_arg_re.match(line) - if m: - toctree = m.group(1) - if filename: - toctree = os.path.join(os.path.dirname(filename), - toctree) - continue - - m = template_arg_re.match(line) - if m: - template = m.group(1).strip() - continue - - if line.strip().startswith(':'): - continue # skip options - - m = autosummary_item_re.match(line) - if m: - name = m.group(1).strip() - if name.startswith('~'): - name = name[1:] - documented.append((name, toctree, template)) - continue - - if not line.strip() or line.startswith(base_indent + " "): - continue - - in_autosummary = False - - m = autosummary_re.match(line) - if m: - in_autosummary = True - base_indent = m.group(1) - toctree = None - template = None - continue - - return documented - - -def process_generate_options(app): - genfiles = app.config.autosummary_generate - - if genfiles and not hasattr(genfiles, '__len__'): - env = app.builder.env - genfiles = [env.doc2path(x, base=None) for x in env.found_docs - if os.path.isfile(env.doc2path(x))] - - if not genfiles: - return - - ext = app.config.source_suffix[0] - genfiles = [genfile + (not genfile.endswith(ext) and ext or '') - for genfile in genfiles] - - generate_autosummary_docs(genfiles, builder=app.builder, - suffix=ext, base_path=app.srcdir) diff --git a/docs/source/_ext/autodoxy/autodoxy/autosummary/templates/doxyclass.rst.in b/docs/source/_ext/autodoxy/autodoxy/autosummary/templates/doxyclass.rst.in deleted file mode 100644 index 2559677eb3..0000000000 --- a/docs/source/_ext/autodoxy/autodoxy/autosummary/templates/doxyclass.rst.in +++ /dev/null @@ -1,20 +0,0 @@ -{{ name }} -{{ underline }} - -.. autodoxyclass:: {{ fullname }} - :members: - - {% if methods %} - .. rubric:: Methods - - .. autodoxysummary:: - {% for item in methods %} - ~{{ fullname }}::{{ item }} - {%- endfor %} - {% endif %} - - {% if enums %} - {% for enum in enums %} - .. autodoxyenum:: {{ enum }} - {% endfor %} - {% endif %} \ No newline at end of file diff --git a/docs/source/_ext/autodoxy/autodoxy/xmlutils.py b/docs/source/_ext/autodoxy/autodoxy/xmlutils.py deleted file mode 100644 index 582f0a47c7..0000000000 --- a/docs/source/_ext/autodoxy/autodoxy/xmlutils.py +++ /dev/null @@ -1,149 +0,0 @@ -from __future__ import print_function, absolute_import, division -from . import get_doxygen_root -import re - -def format_xml_paragraph(xmlnode): - """Format an Doxygen XML segment (principally a detaileddescription) - as a paragraph for inclusion in the rst document - - Parameters - ---------- - xmlnode - - Returns - ------- - lines - A list of lines. - """ - return [l.rstrip() for l in _DoxygenXmlParagraphFormatter().generic_visit(xmlnode).lines] - - -class _DoxygenXmlParagraphFormatter(object): - # This class follows the model of the stdlib's ast.NodeVisitor for tree traversal - # where you dispatch on the element type to a different method for each node - # during the traverse. - - # It's supposed to handle paragraphs, references, preformatted text (code blocks), and lists. - - def __init__(self): - self.lines = [''] - self.continue_line = False - - def visit(self, node): - method = 'visit_' + node.tag - visitor = getattr(self, method, self.generic_visit) - return visitor(node) - - def generic_visit(self, node): - for child in node.getchildren(): - self.visit(child) - return self - - def visit_ref(self, node): - ref = get_doxygen_root().findall('.//*[@id="%s"]' % node.get('refid')) - if ref: - ref = ref[0] - if ref.tag == 'memberdef': - parent = ref.xpath('./ancestor::compounddef/compoundname')[0].text - name = ref.find('./name').text - real_name = parent + '::' + name - elif ref.tag in ('compounddef', 'enumvalue'): - name_node = ref.find('./name') - real_name = name_node.text if name_node is not None else '' - else: - raise NotImplementedError(ref.tag) - else: - real_name = None - - val = [':cpp:any:`', node.text] - if real_name: - val.extend((' <', real_name, '>`')) - else: - val.append('`') - if node.tail is not None: - val.append(node.tail) - - self.lines[-1] += ''.join(val) - - def visit_para(self, node): - if node.text is not None: - if self.continue_line: - self.lines[-1] += node.text - else: - self.lines.append(node.text) - self.generic_visit(node) - self.lines.append('') - self.continue_line = False - - def visit_verbatim(self, node): - if node.text is not None: - # remove the leading ' *' of any lines - lines = [re.sub('^\s*\*','', l) for l in node.text.split('\n')] - # Merge each paragraph together - text = re.sub("\n\n", "PaRaGrraphSplit", '\n'.join(lines)) - text = re.sub('\n', '', text) - lines = text.split('PaRaGrraphSplit') - - # merge content to the built doc - if self.continue_line: - self.lines[-1] += lines[0] - lines = lines[1:] - for l in lines: - self.lines.append('') - self.lines.append(l) - self.generic_visit(node) - self.lines.append('') - self.continue_line = False - - def visit_parametername(self, node): - if 'direction' in node.attrib: - direction = '[%s] ' % node.get('direction') - else: - direction = '' - - self.lines.append('**%s** -- %s' % ( - node.text, direction)) - self.continue_line = True - - def visit_parameterlist(self, node): - lines = [l for l in type(self)().generic_visit(node).lines if l is not ''] - self.lines.extend([':parameters:', ''] + ['* %s' % l for l in lines] + ['']) - - def visit_simplesect(self, node): - if node.get('kind') == 'return': - self.lines.append(':returns: ') - self.continue_line = True - self.generic_visit(node) - - def visit_listitem(self, node): - self.lines.append(' - ') - self.continue_line = True - self.generic_visit(node) - - def visit_preformatted(self, node): - segment = [node.text if node.text is not None else ''] - for n in node.getchildren(): - segment.append(n.text) - if n.tail is not None: - segment.append(n.tail) - - lines = ''.join(segment).split('\n') - self.lines.extend(('.. code-block:: C++', '')) - self.lines.extend([' ' + l for l in lines]) - - def visit_computeroutput(self, node): - c = node.find('preformatted') - if c is not None: - return self.visit_preformatted(c) - return self.visit_preformatted(node) - - def visit_xrefsect(self, node): - if node.find('xreftitle').text == 'Deprecated': - sublines = type(self)().generic_visit(node).lines - self.lines.extend(['.. admonition:: Deprecated'] + [' ' + s for s in sublines]) - else: - raise ValueError(node) - - def visit_subscript(self, node): - self.lines[-1] += '\ :sub:`%s` %s' % (node.text, node.tail) - diff --git a/docs/source/_ext/autodoxy/setup.py b/docs/source/_ext/autodoxy/setup.py deleted file mode 100644 index 63f517109e..0000000000 --- a/docs/source/_ext/autodoxy/setup.py +++ /dev/null @@ -1,22 +0,0 @@ -from setuptools import setup, Extension - -with open("README", "r") as fh: - long_description = fh.read() - -setup( - name="autodoxy", - version="0.0.1", - author="Martin Quinson", -# author_email="author@example.com", - description="A bridge between the autodoc of Python and Doxygen of C/C++", - long_description=long_description, - long_description_content_type="text/plain", - url="https://framagit.org/simgrid/simgrid/docs/source/_ext/autodoxy", - packages=setuptools.find_packages(), - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - ], - python_requires='>=3.6', -)