Пример #1
0
def _create_element_from_result(domain: Domain, inv_name: Optional[str],
                                data: InventoryItem, node: pending_xref,
                                contnode: TextElement) -> Element:
    proj, version, uri, dispname = data
    if '://' not in uri and node.get('refdoc'):
        # get correct path in case of subdirectories
        uri = path.join(relative_path(node['refdoc'], '.'), uri)
    if version:
        reftitle = _('(in %s v%s)') % (proj, version)
    else:
        reftitle = _('(in %s)') % (proj, )
    newnode = nodes.reference('',
                              '',
                              internal=False,
                              refuri=uri,
                              reftitle=reftitle)
    if node.get('refexplicit'):
        # use whatever title was given
        newnode.append(contnode)
    elif dispname == '-' or \
            (domain.name == 'std' and node['reftype'] == 'keyword'):
        # use whatever title was given, but strip prefix
        title = contnode.astext()
        if inv_name is not None and title.startswith(inv_name + ':'):
            newnode.append(
                contnode.__class__(title[len(inv_name) + 1:],
                                   title[len(inv_name) + 1:]))
        else:
            newnode.append(contnode)
    else:
        # else use the given display name (used for :ref:)
        newnode.append(contnode.__class__(dispname, dispname))
    return newnode
Пример #2
0
    def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
                     type: str, target: str, node: pending_xref, contnode: Element
                     ) -> Element:
        modname = node.get('py:module')
        clsname = node.get('py:class')
        searchmode = 1 if node.hasattr('refspecific') else 0
        matches = self.find_obj(env, modname, clsname, target,
                                type, searchmode)

        if not matches and type == 'attr':
            # fallback to meth (for property)
            matches = self.find_obj(env, modname, clsname, target, 'meth', searchmode)

        if not matches:
            return None
        elif len(matches) > 1:
            logger.warning(__('more than one target found for cross-reference %r: %s'),
                           target, ', '.join(match[0] for match in matches),
                           type='ref', subtype='python', location=node)
        name, obj = matches[0]

        if obj[2] == 'module':
            return self._make_module_refnode(builder, fromdocname, name, contnode)
        else:
            return make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name)
Пример #3
0
    def warn_missing_reference(self, refdoc: str, typ: str, target: str,
                               node: pending_xref, domain: Optional[Domain]) -> None:
        warn = node.get('refwarn')
        if self.config.nitpicky:
            warn = True
            if self.config.nitpick_ignore:
                dtype = '%s:%s' % (domain.name, typ) if domain else typ
                if (dtype, target) in self.config.nitpick_ignore:
                    warn = False
                # for "std" types also try without domain name
                if (not domain or domain.name == 'std') and \
                   (typ, target) in self.config.nitpick_ignore:
                    warn = False
        if not warn:
            return

        if self.app.emit_firstresult('warn-missing-reference', domain, node):
            return
        elif domain and typ in domain.dangling_warnings:
            msg = domain.dangling_warnings[typ]
        elif node.get('refdomain', 'std') not in ('', 'std'):
            msg = (__('%s:%s reference target not found: %%(target)s') %
                   (node['refdomain'], typ))
        else:
            msg = __('%r reference target not found: %%(target)s') % typ
        logger.warning(msg % {'target': target},
                       location=node, type='ref', subtype=typ)
def missing_reference(
    app: Sphinx, env: BuildEnvironment, node: pending_xref, contnode: Element
) -> Element:
    """
    Remove or resolve references to third party packages.

    - The ``kubernetes_asyncio`` package doesn't provide any reference
      documentsion for its API. To allow nitpicking on missing references we
      take the approach to exclude all ``kubernetes_asyncio`` references.

    - The ``aiopg`` package uses top-level imports (e.g. ``from aiopg import
        Connection``) and writes the documentation as such. But the actual
        classes and functions are defined in e.g. ``aiopg.conection`` or
        ``aiopg.cursor``. We rewrite the references accordingly.
    """
    reftarget = node.get("reftarget", "")
    if node.get("refdomain") == "py":
        if reftarget.startswith("kubernetes_asyncio."):
            raise NoUri()
        elif reftarget.startswith("aiohttp.client_reqrep."):
            node.attributes["reftarget"] = "aiohttp." + reftarget[22:]
        elif reftarget.startswith("aiopg.connection."):
            node.attributes["reftarget"] = "aiopg." + reftarget[17:]
        elif reftarget.startswith("aiopg.cursor."):
            node.attributes["reftarget"] = "aiopg." + reftarget[13:]
Пример #5
0
 def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
                      target: str, node: pending_xref, contnode: Element
                      ) -> List[Tuple[str, Element]]:
     mod_name = node.get('js:module')
     prefix = node.get('js:object')
     name, obj = self.find_obj(env, mod_name, prefix, target, None, 1)
     if not obj:
         return []
     return [('js:' + self.role_for_objtype(obj[2]),
              make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name))]
Пример #6
0
 def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
                  typ: str, target: str, node: pending_xref, contnode: Element
                  ) -> Element:
     mod_name = node.get('js:module')
     prefix = node.get('js:object')
     searchorder = 1 if node.hasattr('refspecific') else 0
     name, obj = self.find_obj(env, mod_name, prefix, target, typ, searchorder)
     if not obj:
         return None
     return make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name)
Пример #7
0
    def _resolve_doc_nested(self, node: pending_xref,
                            fromdocname: str) -> Optional[Element]:
        """This is the same as ``sphinx.domains.std._resolve_doc_xref``,
        but allows for nested syntax, rather than converting the inner node to raw text.

        It also allows for extensions on document names.
        """
        # directly reference to document by source name; can be absolute or relative
        refdoc = node.get("refdoc", fromdocname)
        docname = docname_join(refdoc, node["reftarget"])

        if docname not in self.env.all_docs:
            # try stripping known extensions from doc name
            if os.path.splitext(docname)[1] in self.env.config.source_suffix:
                docname = os.path.splitext(docname)[0]
            if docname not in self.env.all_docs:
                return None

        if node["refexplicit"]:
            # reference with explicit title
            caption = node.astext()
            innernode = nodes.inline(caption, "", classes=["doc"])
            innernode.extend(node[0].children)
        else:
            # TODO do we want nested syntax for titles?
            caption = clean_astext(self.env.titles[docname])
            innernode = nodes.inline(caption, caption, classes=["doc"])

        return make_refnode(self.app.builder, fromdocname, docname, "",
                            innernode)
Пример #8
0
    def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
                     type: str, target: str, node: pending_xref, contnode: Element
                     ) -> Optional[Element]:
        
        if "." in target:
            parts = target.split(".")
            clsname = parts[0]
            target = parts[1]
        else:
            clsname = node.get('dml:class')
        
        matches = self.find_obj(env, clsname, target, type, 1)

        if not matches:
            return None
        elif len(matches) > 1:
            logger.warning(__('more than one target found for cross-reference %r: %s'),
                               target, ', '.join(match[0] for match in matches),
                               type='ref', subtype='python', location=node)
        name, obj = matches[0]

        # determine the content of the reference by conditions
        content = find_pending_xref_condition(node, 'resolved')
        if content:
            children = content.children
        else:
            # if not found, use contnode
            children = [contnode]

        return make_refnode(builder, fromdocname, obj[0], obj[1], children, name)
Пример #9
0
 def _resolve_doc_xref(
     self,
     env: BuildEnvironment,
     fromdocname: str,
     builder: Builder,
     typ: str,
     target: str,
     node: pending_xref,
     contnode: Element,
 ) -> Element:
     """XXX copied from sphinx/sphinx/domains/std.py XXX"""
     # directly reference to document by source name
     # can be absolute or relative
     refdoc = node.get("refdoc", fromdocname)
     docname = docname_join(refdoc, node["reftarget"])
     if docname not in env.all_docs:
         return None
     else:
         if node["refexplicit"]:
             # reference with explicit title
             caption = node.astext()
         else:
             caption = clean_astext(env.titles[docname])
         innernode = inline(caption, caption, classes=["doc"])
         return make_refnode(builder, fromdocname, docname, None, innernode)
Пример #10
0
    def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
                         target: str, node: pending_xref, contnode: Element
                         ) -> List[Tuple[str, Element]]:
        modname = node.get('py:module')
        clsname = node.get('py:class')
        results = []  # type: List[Tuple[str, Element]]

        # always search in "refspecific" mode with the :any: role
        matches = self.find_obj(env, modname, clsname, target, None, 1)
        for name, obj in matches:
            if obj[2] == 'module':
                results.append(('py:mod',
                                self._make_module_refnode(builder, fromdocname,
                                                          name, contnode)))
            else:
                results.append(('py:' + self.role_for_objtype(obj[2]),
                                make_refnode(builder, fromdocname, obj[0], obj[1],
                                             contnode, name)))
        return results
Пример #11
0
 def _resolve_anchor(self, node: pending_xref,
                     fromdocname: str) -> Optional[Element]:
     """Resolve doc with anchor."""
     target = node["reftarget"]  # type: str
     if not ("#" in target and hasattr(self.env, "myst_anchors")):
         return None
     # the link may be a heading anchor; we need to first get the relative path
     rel_path, anchor = target.rsplit("#", 1)
     rel_path = os.path.normpath(rel_path)
     if rel_path == ".":
         # anchor in the same doc as the node
         doc_path = self.env.doc2path(node.get("refdoc", fromdocname),
                                      base=False)
     else:
         # anchor in a different doc from the node
         doc_path = os.path.normpath(
             os.path.join(node.get("refdoc", fromdocname), "..", rel_path))
     return self._resolve_ref_nested(node, fromdocname,
                                     doc_path + "#" + anchor)
Пример #12
0
    def warn_missing_reference(self, refdoc: str, typ: str, target: str,
                               node: pending_xref,
                               domain: Optional[Domain]) -> None:
        warn = node.get('refwarn')
        if self.config.nitpicky:
            warn = True
            dtype = '%s:%s' % (domain.name, typ) if domain else typ
            if self.config.nitpick_ignore:
                if (dtype, target) in self.config.nitpick_ignore:
                    warn = False
                # for "std" types also try without domain name
                if (not domain or domain.name == 'std') and \
                   (typ, target) in self.config.nitpick_ignore:
                    warn = False
            if self.config.nitpick_ignore_regex:

                def matches_ignore(entry_type: str, entry_target: str) -> bool:
                    for ignore_type, ignore_target in self.config.nitpick_ignore_regex:
                        if re.fullmatch(ignore_type, entry_type) and \
                           re.fullmatch(ignore_target, entry_target):
                            return True
                    return False

                if matches_ignore(dtype, target):
                    warn = False
                # for "std" types also try without domain name
                if (not domain or domain.name == 'std') and \
                   matches_ignore(typ, target):
                    warn = False
        if not warn:
            return

        if self.app.emit_firstresult('warn-missing-reference', domain, node):
            return
        elif domain and typ in domain.dangling_warnings:
            msg = domain.dangling_warnings[typ] % {'target': target}
        elif node.get('refdomain', 'std') not in ('', 'std'):
            msg = (__('%s:%s reference target not found: %s') %
                   (node['refdomain'], typ, target))
        else:
            msg = __('%r reference target not found: %s') % (typ, target)
        logger.warning(msg, location=node, type='ref', subtype=typ)
Пример #13
0
 def _resolve_anchor(self, node: pending_xref,
                     fromdocname: str) -> Optional[Element]:
     """Resolve doc with anchor."""
     if self.env.config.myst_heading_anchors is None:
         # no target anchors will have been created, so we don't look for them
         return None
     target = node["reftarget"]  # type: str
     if "#" not in target:
         return None
     # the link may be a heading anchor; we need to first get the relative path
     rel_path, anchor = target.rsplit("#", 1)
     rel_path = os.path.normpath(rel_path)
     if rel_path == ".":
         # anchor in the same doc as the node
         doc_path = self.env.doc2path(node.get("refdoc", fromdocname),
                                      base=False)
     else:
         # anchor in a different doc from the node
         doc_path = os.path.normpath(
             os.path.join(node.get("refdoc", fromdocname), "..", rel_path))
     return self._resolve_ref_nested(node, fromdocname,
                                     doc_path + "#" + anchor)
Пример #14
0
def builtin_resolver(app: Sphinx, env: BuildEnvironment,
                     node: pending_xref, contnode: Element) -> Element:
    """Do not emit nitpicky warnings for built-in types."""
    def istyping(s: str) -> bool:
        if s.startswith('typing.'):
            s = s.split('.', 1)[1]

        return s in typing.__all__  # type: ignore

    if node.get('refdomain') != 'py':
        return None
    elif node.get('reftype') == 'obj' and node.get('reftarget') == 'None':
        return contnode
    elif node.get('reftype') in ('class', 'exc'):
        reftarget = node.get('reftarget')
        if inspect.isclass(getattr(builtins, reftarget, None)):
            # built-in class
            return contnode
        elif istyping(reftarget):
            # typing class
            return contnode

    return None
Пример #15
0
def term_resolver(app: SphinxApplication, env: BuildEnvironment,
                  orphan: addnodes.pending_xref, textnode: nodes.inline):
    """Triggered when a xref cannot be resolved. For resolving
       missing :term:`glossary-term` references.

       * Create a new referene node with the class "term-missing"
       * Add a MissingTerm object lexicon domain data

       Params
       ------
       * app (sphinx.application.Sphinx): application object
       * env (app.builder.env): the build environment
       * orphan (nodes.pending_xref): node to be resolved
       * textnode (nodes.inline): the text node porition of orphan ref, used to
                                  create a new refnode if resolved

       Returns
       -------
       * if refdomain is "std" and reftype is "term":
           a new reference node that contains textnode
           with class "term-missing" and no href if not found
       * otherwise:
           None
    """

    if orphan.get("reftype") != "term" or orphan.get("refdomain") != "std":
        return

    domain = env.domains.get("lexicon")
    term = Term(orphan.astext())
    listing = domain.find_term(term)

    if not listing:
        domain.add_missing(term, env.docname, orphan.line)

    return domain.mkref(app.builder, term, listing, textnode)
Пример #16
0
 def _resolve_doc_xref(self, env: "BuildEnvironment", fromdocname: str,
                       builder: "Builder", typ: str, target: str,
                       node: pending_xref, contnode: Element) -> Element:
     # directly reference to document by source name; can be absolute or relative
     refdoc = node.get('refdoc', fromdocname)
     docname = docname_join(refdoc, node['reftarget'])
     if docname not in env.all_docs:
         return None
     else:
         if node['refexplicit']:
             # reference with explicit title
             caption = node.astext()
         else:
             caption = clean_astext(env.titles[docname])
         innernode = nodes.inline(caption, caption, classes=['doc'])
         return make_refnode(builder, fromdocname, docname, None, innernode)
Пример #17
0
    def _resolve_option_xref(self, env: "BuildEnvironment", fromdocname: str,
                             builder: "Builder", typ: str, target: str,
                             node: pending_xref, contnode: Element) -> Element:
        progname = node.get('std:program')
        target = target.strip()
        docname, labelid = self.progoptions.get((progname, target), ('', ''))
        if not docname:
            commands = []
            while ws_re.search(target):
                subcommand, target = ws_re.split(target, 1)
                commands.append(subcommand)
                progname = "-".join(commands)

                docname, labelid = self.progoptions.get((progname, target),
                                                        ('', ''))
                if docname:
                    break
            else:
                return None

        return make_refnode(builder, fromdocname, docname, labelid, contnode)
Пример #18
0
def _resolve_reference(env: BuildEnvironment, inv_name: Optional[str], inventory: Inventory,
                       honor_disabled_refs: bool,
                       node: pending_xref, contnode: TextElement) -> Optional[Element]:
    # disabling should only be done if no inventory is given
    honor_disabled_refs = honor_disabled_refs and inv_name is None

    if honor_disabled_refs and '*' in env.config.intersphinx_disabled_reftypes:
        return None

    typ = node['reftype']
    if typ == 'any':
        for domain_name, domain in env.domains.items():
            if honor_disabled_refs \
                    and (domain_name + ":*") in env.config.intersphinx_disabled_reftypes:
                continue
            objtypes = list(domain.object_types)
            res = _resolve_reference_in_domain(env, inv_name, inventory,
                                               honor_disabled_refs,
                                               domain, objtypes,
                                               node, contnode)
            if res is not None:
                return res
        return None
    else:
        domain_name = node.get('refdomain')
        if not domain_name:
            # only objects in domains are in the inventory
            return None
        if honor_disabled_refs \
                and (domain_name + ":*") in env.config.intersphinx_disabled_reftypes:
            return None
        domain = env.get_domain(domain_name)
        objtypes = domain.objtypes_for_role(typ)
        if not objtypes:
            return None
        return _resolve_reference_in_domain(env, inv_name, inventory,
                                            honor_disabled_refs,
                                            domain, objtypes,
                                            node, contnode)
Пример #19
0
def missing_reference(app: Sphinx, env: BuildEnvironment, node: pending_xref,
                      contnode: TextElement) -> nodes.reference:
    """Attempt to resolve a missing reference via intersphinx references."""
    target = node['reftarget']
    inventories = InventoryAdapter(env)
    objtypes: List[str] = None
    if node['reftype'] == 'any':
        # we search anything!
        objtypes = [
            '%s:%s' % (domain.name, objtype)
            for domain in env.domains.values()
            for objtype in domain.object_types
        ]
        domain = None
    else:
        domain = node.get('refdomain')
        if not domain:
            # only objects in domains are in the inventory
            return None
        objtypes = env.get_domain(domain).objtypes_for_role(node['reftype'])
        if not objtypes:
            return None
        objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes]
    if 'std:cmdoption' in objtypes:
        # until Sphinx-1.6, cmdoptions are stored as std:option
        objtypes.append('std:option')
    if 'py:attribute' in objtypes:
        # Since Sphinx-2.1, properties are stored as py:method
        objtypes.append('py:method')

    to_try = [(inventories.main_inventory, target)]
    if domain:
        full_qualified_name = env.get_domain(domain).get_full_qualified_name(
            node)
        if full_qualified_name:
            to_try.append((inventories.main_inventory, full_qualified_name))
    in_set = None
    if ':' in target:
        # first part may be the foreign doc set name
        setname, newtarget = target.split(':', 1)
        if setname in inventories.named_inventory:
            in_set = setname
            to_try.append((inventories.named_inventory[setname], newtarget))
            if domain:
                node['reftarget'] = newtarget
                full_qualified_name = env.get_domain(
                    domain).get_full_qualified_name(node)
                if full_qualified_name:
                    to_try.append((inventories.named_inventory[setname],
                                   full_qualified_name))
    for inventory, target in to_try:
        for objtype in objtypes:
            if objtype not in inventory:
                # Continue if there's nothing of this kind in the inventory
                continue
            if target in inventory[objtype]:
                # Case sensitive match, use it
                proj, version, uri, dispname = inventory[objtype][target]
            elif objtype == 'std:term':
                # Check for potential case insensitive matches for terms only
                target_lower = target.lower()
                insensitive_matches = list(
                    filter(lambda k: k.lower() == target_lower,
                           inventory[objtype].keys()))
                if insensitive_matches:
                    proj, version, uri, dispname = inventory[objtype][
                        insensitive_matches[0]]
                else:
                    # No case insensitive match either, continue to the next candidate
                    continue
            else:
                # Could reach here if we're not a term but have a case insensitive match.
                # This is a fix for terms specifically, but potentially should apply to
                # other types.
                continue

            if '://' not in uri and node.get('refdoc'):
                # get correct path in case of subdirectories
                uri = path.join(relative_path(node['refdoc'], '.'), uri)
            if version:
                reftitle = _('(in %s v%s)') % (proj, version)
            else:
                reftitle = _('(in %s)') % (proj, )
            newnode = nodes.reference('',
                                      '',
                                      internal=False,
                                      refuri=uri,
                                      reftitle=reftitle)
            if node.get('refexplicit'):
                # use whatever title was given
                newnode.append(contnode)
            elif dispname == '-' or \
                    (domain == 'std' and node['reftype'] == 'keyword'):
                # use whatever title was given, but strip prefix
                title = contnode.astext()
                if in_set and title.startswith(in_set + ':'):
                    newnode.append(
                        contnode.__class__(title[len(in_set) + 1:],
                                           title[len(in_set) + 1:]))
                else:
                    newnode.append(contnode)
            else:
                # else use the given display name (used for :ref:)
                newnode.append(contnode.__class__(dispname, dispname))
            return newnode
    # at least get rid of the ':' in the target if no explicit title given
    if in_set is not None and not node.get('refexplicit', True):
        if len(contnode) and isinstance(contnode[0], nodes.Text):
            contnode[0] = nodes.Text(newtarget, contnode[0].rawsource)

    return None
Пример #20
0
def missing_reference(app: Sphinx, env: BuildEnvironment, node: pending_xref,
                      contnode: TextElement) -> nodes.reference:
    """Attempt to resolve a missing reference via intersphinx references."""
    target = node['reftarget']
    inventories = InventoryAdapter(env)
    objtypes: List[str] = None
    if node['reftype'] == 'any':
        # we search anything!
        objtypes = [
            '%s:%s' % (domain.name, objtype)
            for domain in env.domains.values()
            for objtype in domain.object_types
        ]
        domain = None
    else:
        domain = node.get('refdomain')
        if not domain:
            # only objects in domains are in the inventory
            return None
        objtypes = env.get_domain(domain).objtypes_for_role(node['reftype'])
        if not objtypes:
            return None
        objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes]
    if 'std:cmdoption' in objtypes:
        # until Sphinx-1.6, cmdoptions are stored as std:option
        objtypes.append('std:option')
    if 'py:attribute' in objtypes:
        # Since Sphinx-2.1, properties are stored as py:method
        objtypes.append('py:method')

    # determine the contnode by pending_xref_condition
    content = find_pending_xref_condition(node, 'resolved')
    if content:
        # resolved condition found.
        contnodes = content.children
        contnode = content.children[0]  # type: ignore
    else:
        # not resolved. Use the given contnode
        contnodes = [contnode]

    to_try = [(inventories.main_inventory, target)]
    if domain:
        full_qualified_name = env.get_domain(domain).get_full_qualified_name(
            node)
        if full_qualified_name:
            to_try.append((inventories.main_inventory, full_qualified_name))
    in_set = None
    if ':' in target:
        # first part may be the foreign doc set name
        setname, newtarget = target.split(':', 1)
        if setname in inventories.named_inventory:
            in_set = setname
            to_try.append((inventories.named_inventory[setname], newtarget))
            if domain:
                node['reftarget'] = newtarget
                full_qualified_name = env.get_domain(
                    domain).get_full_qualified_name(node)
                if full_qualified_name:
                    to_try.append((inventories.named_inventory[setname],
                                   full_qualified_name))
    for inventory, target in to_try:
        for objtype in objtypes:
            if objtype not in inventory or target not in inventory[objtype]:
                continue
            proj, version, uri, dispname = inventory[objtype][target]
            if '://' not in uri and node.get('refdoc'):
                # get correct path in case of subdirectories
                uri = path.join(relative_path(node['refdoc'], '.'), uri)
            if version:
                reftitle = _('(in %s v%s)') % (proj, version)
            else:
                reftitle = _('(in %s)') % (proj, )
            newnode = nodes.reference('',
                                      '',
                                      internal=False,
                                      refuri=uri,
                                      reftitle=reftitle)
            if node.get('refexplicit'):
                # use whatever title was given
                newnode.extend(contnodes)
            elif dispname == '-' or \
                    (domain == 'std' and node['reftype'] == 'keyword'):
                # use whatever title was given, but strip prefix
                title = contnode.astext()
                if in_set and title.startswith(in_set + ':'):
                    newnode.append(
                        contnode.__class__(title[len(in_set) + 1:],
                                           title[len(in_set) + 1:]))
                else:
                    newnode.extend(contnodes)
            else:
                # else use the given display name (used for :ref:)
                newnode.append(contnode.__class__(dispname, dispname))
            return newnode
    # at least get rid of the ':' in the target if no explicit title given
    if in_set is not None and not node.get('refexplicit', True):
        if len(contnode) and isinstance(contnode[0], nodes.Text):
            contnode[0] = nodes.Text(newtarget, contnode[0].rawsource)

    return None