def get_ref(self, node: nodes.Node) -> Optional[nodes.Node]: while node is not None: if not node.get('ids'): # In Sphinx domain descriptions, the ID is in the # first child node, the desc_signature. # We can take that, but to make the JS handling # the TOC sidebar work properly, we need it to # be in the hierarchy. So create an ID for the # desc node. if node[0].get('ids'): node['ids'] = [node[0].get('ids')[0] + '-tocentry'] if node.get('ids'): return node['ids'][0] node = node.parent
def _add_pending_back_reference(app: Sphinx, signode: Node, fullname: str) -> None: """ Updates the ``doc_links`` entry of the modules stored in ``_viewcode_c_modules`` so that they can later be added to the source code listings as links to the documentation locations. Args: app (Sphinx): The sphinx app currently doing the processing. signode (Node): The signature node to create the back reference to. fullname (str): The name of the construct, i.e. function name, variable name etc. """ module = signode.get("module") if module is None: return env = app.builder.env code_listing = env._viewcode_c_modules.get(module) # type: ignore if code_listing is None: return doc_links = code_listing.doc_links doc_links.setdefault(fullname, DocumentationReference(env.docname, module, fullname))
def visit_doctest_block(self, node: Node) -> None: pysrc = node[0].astext() if node.get('codeblock'): self.body.append(flatten(colorize_codeblock(pysrc))) else: self.body.append(flatten(colorize_doctest(pysrc))) raise SkipNode()
def is_translatable(node: Node) -> bool: if isinstance(node, addnodes.translatable): return True # image node marked as translatable or having alt text if isinstance(node, nodes.image) and (node.get('translatable') or node.get('alt')): return True if isinstance(node, nodes.Inline) and 'translatable' not in node: # type: ignore # inline node must not be translated if 'translatable' is not set return False if isinstance(node, nodes.TextElement): if not node.source: logger.debug('[i18n] SKIP %r because no node.source: %s', get_full_module_name(node), repr_domxml(node)) return False # built-in message if isinstance(node, IGNORED_NODES) and 'translatable' not in node: logger.debug( "[i18n] SKIP %r because node is in IGNORED_NODES " "and no node['translatable']: %s", get_full_module_name(node), repr_domxml(node)) return False if not node.get('translatable', True): # not(node['translatable'] == True or node['translatable'] is None) logger.debug("[i18n] SKIP %r because not node['translatable']: %s", get_full_module_name(node), repr_domxml(node)) return False # <field_name>orphan</field_name> # XXX ignore all metadata (== docinfo) if isinstance(node, nodes.field_name) and node.children[0] == 'orphan': logger.debug('[i18n] SKIP %r because orphan node: %s', get_full_module_name(node), repr_domxml(node)) return False return True if is_pending_meta(node) or isinstance(node, addnodes.meta): # docutils-0.17 or older return True elif isinstance(node, addnodes.docutils_meta): # docutils-0.18+ return True return False
def locate_in_toc(self, app: Sphinx, node: nodes.Node) -> Optional[nodes.Node]: toc = app.env.tocs[app.env.docname] ref = self.get_ref(node) for node in toc.traverse(nodes.reference): node_ref = node.get('anchorname') if not node_ref or node_ref[0] != "#": continue if node_ref[1:] == ref: return node.parent.parent
def resolve_any_xref( self, env: BuildEnvironment, from_doc_name: str, builder: Builder, target: str, node: nodes.Node, cont_node: nodes.Node) -> List[Tuple[str, nodes.Node]]: modname = node.get('lua:module') class_name = node.get('lua:class') results: List[Tuple[str, nodes.Node]] = [] # always search in "refspecific" mode with the :any: role matches = self.find_obj(env, modname, class_name, target, None, 1) for name, obj in matches: if obj[1] == 'module': results.append( ('lua:mod', self._make_module_refnode(builder, from_doc_name, name, cont_node))) else: results.append(('lua:' + self.role_for_objtype(obj[1]), make_refnode(builder, from_doc_name, obj[0], name, cont_node, name))) return results
def get_enumerable_node_type(self, node: Node) -> str: """Get type of enumerable nodes.""" def has_child(node: Element, cls: "Type") -> bool: return any(isinstance(child, cls) for child in node) if isinstance(node, nodes.section): return 'section' elif isinstance(node, nodes.container): if node.get('literal_block') and has_child(node, nodes.literal_block): return 'code-block' else: return None else: figtype, _ = self.enumerable_nodes.get(node.__class__, (None, None)) return figtype
def _add_pending_source_cross_reference(app: Sphinx, signode: Node, fullname: str) -> None: """ Adds a pending source cross reference to the signature in the doctree, `signode`. The viewcode and linkcode extensions walk the doctree once parsed and then add this node, however since sphinx_c_autodoc already has to add logic, the `module` option to the directives it seems more practical to just create the full pending cross reference here, and then viewcode is an extension which will populate this cross refernce. Args: app (Sphinx): The sphinx app currently doing the processing. signode (Node): The signature node to apply the source code cross reference to. fullname (str): The dotted fullname of the C construct. """ module = signode.get("module") if module is None: return source_page = _get_source_page_name(module) # Using the `viewcode-link` to be consistent with the python versions in # case someone else wants to walk the tree and do other links inline = nodes.inline("", "[source]", classes=["viewcode-link"]) # Limit this cross referencing only to html html_node = addnodes.only(expr="html") html_node += addnodes.pending_xref( "", inline, reftype=f"{C_DOMAIN_LINK_PREFIX}viewcode", refdomain="std", refexplicit=False, reftarget=source_page, refid=f"{C_DOMAIN_LINK_PREFIX}{fullname}", refdoc=app.builder.env.docname, module=module, fullname=fullname, ) signode += html_node
def handle_missing_xref(app: Sphinx, env, node: nodes.Node, contnode: nodes.Node) -> None: # Ignore missing reference warnings for the wheel_filename module if node.get("reftarget", '').startswith("docutils."): raise NoUri if node.get("reftarget", '').startswith("sphinx.ext.autodoc."): raise NoUri if node.get("reftarget", '').startswith("sphinx.ext.autosummary."): raise NoUri if node.get("reftarget", '').startswith("sphinx_toolbox._data_documenter."): # TODO: redirect raise NoUri if node.get("reftarget", '') in { "spam", "lobster", "foo", "typing_extensions", "bs4.BeautifulSoup", "pytest_regressions.file_regression.FileRegressionFixture", "sphinx_toolbox.patched_autosummary", "sphinx_toolbox.autodoc_augment_defaults", "sphinx_toolbox.autodoc_typehints", "sphinx_toolbox.autotypeddict", "sphinx_toolbox.autoprotocol", "sphinx_toolbox.utils._T", "sphinx_toolbox.testing.EventManager", # TODO "sphinx.registry.SphinxComponentRegistry", "sphinx.config.Config", "sphinx.config.Config.latex_elements", "sphinx.util.docfields.TypedField", "sphinx.writers.html.HTMLTranslator", "sphinx.writers.latex.LaTeXTranslator", "sphinx.domains.python.PyXRefRole", "sphinx.domains.std.GenericObject", "sphinx.domains.changeset.VersionChange", "sphinx.directives.code.CodeBlock", "sphinx.roles.Abbreviation", "autodoc.Documenter", # TODO: why not sphinx.ext.autodoc.Documenter? }: raise NoUri if node.get("reftarget", '').startswith("consolekit.terminal_colours.Fore."): raise NoUri
def dispatch_visit(self, node: Node) -> None: if isinstance(node, nodes.comment): raise nodes.SkipNode elif isinstance(node, nodes.raw): if 'html' in node.get('format', '').split(): # Some people might put content in raw HTML that should be searched, # so we just amateurishly strip HTML tags and index the remaining # content nodetext = re.sub(r'(?is)<style.*?</style>', '', node.astext()) nodetext = re.sub(r'(?is)<script.*?</script>', '', nodetext) nodetext = re.sub(r'<[^<]+?>', '', nodetext) self.found_words.extend(self.lang.split(nodetext)) raise nodes.SkipNode elif isinstance(node, nodes.Text): self.found_words.extend(self.lang.split(node.astext())) elif isinstance(node, nodes.title): self.found_title_words.extend(self.lang.split(node.astext())) elif isinstance(node, addnodes.meta) and self.is_meta_keywords(node): keywords = node['content'] keywords = [keyword.strip() for keyword in keywords.split(',')] self.found_words.extend(keywords)
def match(self, node: Node) -> bool: try: if self.classes and not isinstance(node, self.classes): return False if self.attrs: if not isinstance(node, nodes.Element): return False for key, value in self.attrs.items(): if key not in node: return False elif value is Any: continue elif node.get(key) != value: return False return True except Exception: # for non-Element nodes return False
def is_gettext_additional_targets(node: Node) -> bool: # This func judges if passed `node` is one of the following, which can be # tranlated by `gettext_addtional_targets` setting and is not supported by # this sphinx extension: # - toctree (with hidden attribute as True) # - literal-block # - raw # - image # hidden toc element if isinstance(node, toctree) and node.get("hidden", None) is True: return True # literal_block / raw / image nodes are not supported since they are not # supported due to implementation issue, e.g. compatibility with code-block # highlight HTML writing elif (isinstance(node, literal_block) or isinstance(node, raw) or isinstance(node, image)): return True else: return False
def get_refnodes(self, doctree: Node, result: List[Dict[str, Any]]) -> List[Dict[str, Any]]: # NOQA """Collect section titles, their depth in the toc and the refuri.""" # XXX: is there a better way than checking the attribute # toctree-l[1-8] on the parent node? if isinstance(doctree, nodes.reference) and doctree.get('refuri'): refuri = doctree['refuri'] if refuri.startswith('http://') or refuri.startswith('https://') \ or refuri.startswith('irc:') or refuri.startswith('mailto:'): return result classes = doctree.parent.attributes['classes'] for level in range(8, 0, -1): # or range(1, 8)? if (self.toctree_template % level) in classes: result.append({ 'level': level, 'refuri': html.escape(refuri), 'text': ssp(html.escape(doctree.astext())) }) break elif isinstance(doctree, nodes.Element): for elem in doctree: result = self.get_refnodes(elem, result) return result
def visit_container(self, node: nodes.Node): classes = "docutils container" if node.get("is_div", False): # we don't want the CSS for container for these nodes classes = "docutils" self.body.append(self.starttag(node, "div", CLASS=classes))
def match(self, node: nodes.Node) -> bool: uri = node.get('uri', '') return bool(url_to_file_id(uri))
def visit_togglereveal(self, node: nodes.Node) -> None: classes = " ".join(node.get("classes", [])) self.body.append(f'<div class="togglereveal {classes}">') self.body.append('<details class="admonition-body">') self.body.append("<summary></summary>")