Esempio n. 1
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)
Esempio n. 2
0
 def find_pending_xref_condition(self, node: pending_xref, conditions: Sequence[str]
                                 ) -> Optional[List[Node]]:
     for condition in conditions:
         matched = find_pending_xref_condition(node, condition)
         if matched:
             return matched.children
     else:
         return None
Esempio n. 3
0
    def run(self, **kwargs: Any) -> None:
        for node in self.document.traverse(addnodes.pending_xref):
            contnode = cast(nodes.TextElement, node[0].deepcopy())
            newnode = None

            typ = node['reftype']
            target = node['reftarget']
            refdoc = node.get('refdoc', self.env.docname)
            domain = None

            try:
                if 'refdomain' in node and node['refdomain']:
                    # let the domain try to resolve the reference
                    try:
                        domain = self.env.domains[node['refdomain']]
                    except KeyError as exc:
                        raise NoUri(target, typ) from exc
                    newnode = domain.resolve_xref(self.env, refdoc,
                                                  self.app.builder, typ,
                                                  target, node, contnode)
                # really hardwired reference types
                elif typ == 'any':
                    newnode = self.resolve_anyref(refdoc, node, contnode)
                # no new node found? try the missing-reference event
                if newnode is None:
                    newnode = self.app.emit_firstresult(
                        'missing-reference',
                        self.env,
                        node,
                        contnode,
                        allowed_exceptions=(NoUri, ))
                    # still not found? warn if node wishes to be warned about or
                    # we are in nit-picky mode
                    if newnode is None:
                        self.warn_missing_reference(refdoc, typ, target, node,
                                                    domain)
            except NoUri:
                newnode = None

            if newnode:
                newnodes = [newnode]  # type: List[Node]
            else:
                newnodes = [contnode]
                if newnode is None and isinstance(
                        node[0], addnodes.pending_xref_condition):
                    matched = find_pending_xref_condition(node, "*")
                    if matched:
                        newnodes = matched.children
                    else:
                        logger.warning(__(
                            'Could not determine the fallback text for the '
                            'cross-reference. Might be a bug.'),
                                       location=node)

            node.replace_self(newnodes)
Esempio n. 4
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