Beispiel #1
0
class StandardDomain(Domain):
    """
    Domain for all objects that don't fit into another domain or are added
    via the application interface.
    """

    name = 'std'
    label = 'Default'

    object_types = {
        'term': ObjType(_('glossary term'), 'term', searchprio=-1),
        'token': ObjType(_('grammar token'), 'token', searchprio=-1),
        'label': ObjType(_('reference label'), 'ref', 'keyword',
                         searchprio=-1),
        'envvar': ObjType(_('environment variable'), 'envvar'),
        'cmdoption': ObjType(_('program option'), 'option'),
        'doc': ObjType(_('document'), 'doc', searchprio=-1)
    }  # type: Dict[str, ObjType]

    directives = {
        'program': Program,
        'cmdoption': Cmdoption,  # old name for backwards compatibility
        'option': Cmdoption,
        'envvar': EnvVar,
        'glossary': Glossary,
        'productionlist': ProductionList,
    }  # type: Dict[str, Type[Directive]]
    roles = {
        'option':
        OptionXRefRole(warn_dangling=True),
        'envvar':
        EnvVarXRefRole(),
        # links to tokens in grammar productions
        'token':
        TokenXRefRole(),
        # links to terms in glossary
        'term':
        XRefRole(innernodeclass=nodes.inline, warn_dangling=True),
        # links to headings or arbitrary labels
        'ref':
        XRefRole(lowercase=True,
                 innernodeclass=nodes.inline,
                 warn_dangling=True),
        # links to labels of numbered figures, tables and code-blocks
        'numref':
        XRefRole(lowercase=True, warn_dangling=True),
        # links to labels, without a different title
        'keyword':
        XRefRole(warn_dangling=True),
        # links to documents
        'doc':
        XRefRole(warn_dangling=True, innernodeclass=nodes.inline),
    }  # type: Dict[str, Union[RoleFunction, XRefRole]]

    initial_data = {
        'progoptions': {},      # (program, name) -> docname, labelid
        'objects': {},          # (type, name) -> docname, labelid
        'labels': {             # labelname -> docname, labelid, sectionname
            'genindex': ('genindex', '', _('Index')),
            'modindex': ('py-modindex', '', _('Module Index')),
            'search':   ('search', '', _('Search Page')),
        },
        'anonlabels': {         # labelname -> docname, labelid
            'genindex': ('genindex', ''),
            'modindex': ('py-modindex', ''),
            'search':   ('search', ''),
        },
    }

    dangling_warnings = {
        'term': 'term not in glossary: %(target)s',
        'ref': 'undefined label: %(target)s (if the link has no caption '
        'the label must precede a section header)',
        'numref': 'undefined label: %(target)s',
        'keyword': 'unknown keyword: %(target)s',
        'doc': 'unknown document: %(target)s',
        'option': 'unknown option: %(target)s',
    }

    enumerable_nodes = {  # node_class -> (figtype, title_getter)
        nodes.figure: ('figure', None),
        nodes.table: ('table', None),
        nodes.container: ('code-block', None),
    }  # type: Dict[Type[Node], Tuple[str, Callable]]

    def __init__(self, env: "BuildEnvironment") -> None:
        super().__init__(env)

        # set up enumerable nodes
        self.enumerable_nodes = copy(
            self.enumerable_nodes)  # create a copy for this instance
        for node, settings in env.app.registry.enumerable_nodes.items():
            self.enumerable_nodes[node] = settings

    def note_hyperlink_target(self,
                              name: str,
                              docname: str,
                              node_id: str,
                              title: str = '') -> None:
        """Add a hyperlink target for cross reference.

        .. warning::

           This is only for internal use.  Please don't use this from your extension.
           ``document.note_explicit_target()`` or ``note_implicit_target()`` are recommended to
           add a hyperlink target to the document.

           This only adds a hyperlink target to the StandardDomain.  And this does not add a
           node_id to node.  Therefore, it is very fragile to calling this without
           understanding hyperlink target framework in both docutils and Sphinx.

        .. versionadded:: 3.0
        """
        if name in self.anonlabels and self.anonlabels[name] != (docname,
                                                                 node_id):
            logger.warning(__('duplicate label %s, other instance in %s'),
                           name, self.env.doc2path(self.anonlabels[name][0]))

        self.anonlabels[name] = (docname, node_id)
        if title:
            self.labels[name] = (docname, node_id, title)

    @property
    def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
        return self.data.setdefault('objects',
                                    {})  # (objtype, name) -> docname, labelid

    def note_object(self,
                    objtype: str,
                    name: str,
                    labelid: str,
                    location: Any = None) -> None:
        """Note a generic object for cross reference.

        .. versionadded:: 3.0
        """
        if (objtype, name) in self.objects:
            docname = self.objects[objtype, name][0]
            logger.warning(
                __('duplicate %s description of %s, other instance in %s'),
                objtype,
                name,
                docname,
                location=location)
        self.objects[objtype, name] = (self.env.docname, labelid)

    def add_object(self, objtype: str, name: str, docname: str,
                   labelid: str) -> None:
        warnings.warn('StandardDomain.add_object() is deprecated.',
                      RemovedInSphinx50Warning)
        self.objects[objtype, name] = (docname, labelid)

    @property
    def progoptions(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
        return self.data.setdefault('progoptions',
                                    {})  # (program, name) -> docname, labelid

    @property
    def labels(self) -> Dict[str, Tuple[str, str, str]]:
        return self.data.setdefault(
            'labels', {})  # labelname -> docname, labelid, sectionname

    @property
    def anonlabels(self) -> Dict[str, Tuple[str, str]]:
        return self.data.setdefault('anonlabels',
                                    {})  # labelname -> docname, labelid

    def clear_doc(self, docname: str) -> None:
        key = None  # type: Any
        for key, (fn, _l) in list(self.progoptions.items()):
            if fn == docname:
                del self.progoptions[key]
        for key, (fn, _l) in list(self.objects.items()):
            if fn == docname:
                del self.objects[key]
        for key, (fn, _l, _l) in list(self.labels.items()):
            if fn == docname:
                del self.labels[key]
        for key, (fn, _l) in list(self.anonlabels.items()):
            if fn == docname:
                del self.anonlabels[key]

    def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
        # XXX duplicates?
        for key, data in otherdata['progoptions'].items():
            if data[0] in docnames:
                self.progoptions[key] = data
        for key, data in otherdata['objects'].items():
            if data[0] in docnames:
                self.objects[key] = data
        for key, data in otherdata['labels'].items():
            if data[0] in docnames:
                self.labels[key] = data
        for key, data in otherdata['anonlabels'].items():
            if data[0] in docnames:
                self.anonlabels[key] = data

    def process_doc(self, env: "BuildEnvironment", docname: str,
                    document: nodes.document) -> None:  # NOQA
        for name, explicit in document.nametypes.items():
            if not explicit:
                continue
            labelid = document.nameids[name]
            if labelid is None:
                continue
            node = document.ids[labelid]
            if isinstance(node, nodes.target) and 'refid' in node:
                # indirect hyperlink targets
                node = document.ids.get(node['refid'])
                labelid = node['names'][0]
            if (node.tagname == 'footnote' or 'refuri' in node
                    or node.tagname.startswith('desc_')):
                # ignore footnote labels, labels automatically generated from a
                # link and object descriptions
                continue
            if name in self.labels:
                logger.warning(__('duplicate label %s, other instance in %s'),
                               name,
                               env.doc2path(self.labels[name][0]),
                               location=node)
            self.anonlabels[name] = docname, labelid
            if node.tagname in ('section', 'rubric'):
                title = cast(nodes.title, node[0])
                sectname = clean_astext(title)
            elif self.is_enumerable_node(node):
                sectname = self.get_numfig_title(node)
                if not sectname:
                    continue
            else:
                toctree = next(iter(node.traverse(addnodes.toctree)), None)
                if toctree and toctree.get('caption'):
                    sectname = toctree.get('caption')
                else:
                    # anonymous-only labels
                    continue
            self.labels[name] = docname, labelid, sectname

    def add_program_option(self, program: str, name: str, docname: str,
                           labelid: str) -> None:
        self.progoptions[program, name] = (docname, labelid)

    def build_reference_node(self, fromdocname: str, builder: "Builder",
                             docname: str, labelid: str, sectname: str,
                             rolename: str, **options: Any) -> Element:
        nodeclass = options.pop('nodeclass', nodes.reference)
        newnode = nodeclass('', '', internal=True, **options)
        innernode = nodes.inline(sectname, sectname)
        if innernode.get('classes') is not None:
            innernode['classes'].append('std')
            innernode['classes'].append('std-' + rolename)
        if docname == fromdocname:
            newnode['refid'] = labelid
        else:
            # set more info in contnode; in case the
            # get_relative_uri call raises NoUri,
            # the builder will then have to resolve these
            contnode = pending_xref('')
            contnode['refdocname'] = docname
            contnode['refsectname'] = sectname
            newnode['refuri'] = builder.get_relative_uri(fromdocname, docname)
            if labelid:
                newnode['refuri'] += '#' + labelid
        newnode.append(innernode)
        return newnode

    def resolve_xref(self, env: "BuildEnvironment", fromdocname: str,
                     builder: "Builder", typ: str, target: str,
                     node: pending_xref, contnode: Element) -> Element:
        if typ == 'ref':
            resolver = self._resolve_ref_xref
        elif typ == 'numref':
            resolver = self._resolve_numref_xref
        elif typ == 'keyword':
            resolver = self._resolve_keyword_xref
        elif typ == 'doc':
            resolver = self._resolve_doc_xref
        elif typ == 'option':
            resolver = self._resolve_option_xref
        elif typ == 'citation':
            warnings.warn(
                'pending_xref(domain=std, type=citation) is deprecated: %r' %
                node, RemovedInSphinx40Warning)
            domain = env.get_domain('citation')
            return domain.resolve_xref(env, fromdocname, builder, typ, target,
                                       node, contnode)
        elif typ == 'term':
            resolver = self._resolve_term_xref
        else:
            resolver = self._resolve_obj_xref

        return resolver(env, fromdocname, builder, typ, target, node, contnode)

    def _resolve_ref_xref(self, env: "BuildEnvironment", fromdocname: str,
                          builder: "Builder", typ: str, target: str,
                          node: pending_xref, contnode: Element) -> Element:
        if node['refexplicit']:
            # reference to anonymous label; the reference uses
            # the supplied link caption
            docname, labelid = self.anonlabels.get(target, ('', ''))
            sectname = node.astext()
        else:
            # reference to named label; the final node will
            # contain the section name after the label
            docname, labelid, sectname = self.labels.get(target, ('', '', ''))
        if not docname:
            return None

        return self.build_reference_node(fromdocname, builder, docname,
                                         labelid, sectname, 'ref')

    def _resolve_numref_xref(self, env: "BuildEnvironment", fromdocname: str,
                             builder: "Builder", typ: str, target: str,
                             node: pending_xref, contnode: Element) -> Element:
        if target in self.labels:
            docname, labelid, figname = self.labels.get(target, ('', '', ''))
        else:
            docname, labelid = self.anonlabels.get(target, ('', ''))
            figname = None

        if not docname:
            return None

        target_node = env.get_doctree(docname).ids.get(labelid)
        figtype = self.get_enumerable_node_type(target_node)
        if figtype is None:
            return None

        if figtype != 'section' and env.config.numfig is False:
            logger.warning(__('numfig is disabled. :numref: is ignored.'),
                           location=node)
            return contnode

        try:
            fignumber = self.get_fignumber(env, builder, figtype, docname,
                                           target_node)
            if fignumber is None:
                return contnode
        except ValueError:
            logger.warning(__("no number is assigned for %s: %s"),
                           figtype,
                           labelid,
                           location=node)
            return contnode

        try:
            if node['refexplicit']:
                title = contnode.astext()
            else:
                title = env.config.numfig_format.get(figtype, '')

            if figname is None and '{name}' in title:
                logger.warning(__('the link has no caption: %s'),
                               title,
                               location=node)
                return contnode
            else:
                fignum = '.'.join(map(str, fignumber))
                if '{name}' in title or 'number' in title:
                    # new style format (cf. "Fig.{number}")
                    if figname:
                        newtitle = title.format(name=figname, number=fignum)
                    else:
                        newtitle = title.format(number=fignum)
                else:
                    # old style format (cf. "Fig.%s")
                    newtitle = title % fignum
        except KeyError as exc:
            logger.warning(__('invalid numfig_format: %s (%r)'),
                           title,
                           exc,
                           location=node)
            return contnode
        except TypeError:
            logger.warning(__('invalid numfig_format: %s'),
                           title,
                           location=node)
            return contnode

        return self.build_reference_node(fromdocname,
                                         builder,
                                         docname,
                                         labelid,
                                         newtitle,
                                         'numref',
                                         nodeclass=addnodes.number_reference,
                                         title=title)

    def _resolve_keyword_xref(self, env: "BuildEnvironment", fromdocname: str,
                              builder: "Builder", typ: str, target: str,
                              node: pending_xref,
                              contnode: Element) -> Element:
        # keywords are oddballs: they are referenced by named labels
        docname, labelid, _ = self.labels.get(target, ('', '', ''))
        if not docname:
            return None
        return make_refnode(builder, fromdocname, docname, labelid, contnode)

    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)

    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)

    def _resolve_term_xref(self, env: "BuildEnvironment", fromdocname: str,
                           builder: "Builder", typ: str, target: str,
                           node: pending_xref, contnode: Element) -> Element:
        result = self._resolve_obj_xref(env, fromdocname, builder, typ, target,
                                        node, contnode)
        if result:
            return result
        else:
            for objtype, term in self.objects:
                if objtype == 'term' and term.lower() == target.lower():
                    docname, labelid = self.objects[objtype, term]
                    logger.warning(__(
                        'term %s not found in case sensitive match.'
                        'made a reference to %s instead.'),
                                   target,
                                   term,
                                   location=node,
                                   type='ref',
                                   subtype='term')
                    break
            else:
                docname, labelid = '', ''
            if not docname:
                return None
            return make_refnode(builder, fromdocname, docname, labelid,
                                contnode)

    def _resolve_obj_xref(self, env: "BuildEnvironment", fromdocname: str,
                          builder: "Builder", typ: str, target: str,
                          node: pending_xref, contnode: Element) -> Element:
        objtypes = self.objtypes_for_role(typ) or []
        for objtype in objtypes:
            if (objtype, target) in self.objects:
                docname, labelid = self.objects[objtype, target]
                break
        else:
            docname, labelid = '', ''
        if not docname:
            return None
        return make_refnode(builder, fromdocname, docname, labelid, contnode)

    def resolve_any_xref(self, env: "BuildEnvironment", fromdocname: str,
                         builder: "Builder", target: str, node: pending_xref,
                         contnode: Element) -> List[Tuple[str, Element]]:
        results = []  # type: List[Tuple[str, Element]]
        ltarget = target.lower()  # :ref: lowercases its target automatically
        for role in ('ref', 'option'):  # do not try "keyword"
            res = self.resolve_xref(env, fromdocname, builder, role,
                                    ltarget if role == 'ref' else target, node,
                                    contnode)
            if res:
                results.append(('std:' + role, res))
        # all others
        for objtype in self.object_types:
            key = (objtype, target)
            if objtype == 'term':
                key = (objtype, ltarget)
            if key in self.objects:
                docname, labelid = self.objects[key]
                results.append(('std:' + self.role_for_objtype(objtype),
                                make_refnode(builder, fromdocname, docname,
                                             labelid, contnode)))
        return results

    def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
        # handle the special 'doc' reference here
        for doc in self.env.all_docs:
            yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1)
        for (prog, option), info in self.progoptions.items():
            if prog:
                fullname = ".".join([prog, option])
                yield (fullname, fullname, 'cmdoption', info[0], info[1], 1)
            else:
                yield (option, option, 'cmdoption', info[0], info[1], 1)
        for (type, name), info in self.objects.items():
            yield (name, name, type, info[0], info[1],
                   self.object_types[type].attrs['searchprio'])
        for name, (docname, labelid, sectionname) in self.labels.items():
            yield (name, sectionname, 'label', docname, labelid, -1)
        # add anonymous-only labels as well
        non_anon_labels = set(self.labels)
        for name, (docname, labelid) in self.anonlabels.items():
            if name not in non_anon_labels:
                yield (name, name, 'label', docname, labelid, -1)

    def get_type_name(self, type: ObjType, primary: bool = False) -> str:
        # never prepend "Default"
        return type.lname

    def is_enumerable_node(self, node: Node) -> bool:
        return node.__class__ in self.enumerable_nodes

    def get_numfig_title(self, node: Node) -> str:
        """Get the title of enumerable nodes to refer them using its title"""
        if self.is_enumerable_node(node):
            elem = cast(Element, node)
            _, title_getter = self.enumerable_nodes.get(
                elem.__class__, (None, None))
            if title_getter:
                return title_getter(elem)
            else:
                for subnode in elem:
                    if isinstance(subnode, (nodes.caption, nodes.title)):
                        return clean_astext(subnode)

        return None

    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) and 'literal_block' in node
              and has_child(node, nodes.literal_block)):
            # given node is a code-block having caption
            return 'code-block'
        else:
            figtype, _ = self.enumerable_nodes.get(node.__class__,
                                                   (None, None))
            return figtype

    def get_fignumber(self, env: "BuildEnvironment", builder: "Builder",
                      figtype: str, docname: str,
                      target_node: Element) -> Tuple[int, ...]:
        if figtype == 'section':
            if builder.name == 'latex':
                return tuple()
            elif docname not in env.toc_secnumbers:
                raise ValueError  # no number assigned
            else:
                anchorname = '#' + target_node['ids'][0]
                if anchorname not in env.toc_secnumbers[docname]:
                    # try first heading which has no anchor
                    return env.toc_secnumbers[docname].get('')
                else:
                    return env.toc_secnumbers[docname].get(anchorname)
        else:
            try:
                figure_id = target_node['ids'][0]
                return env.toc_fignumbers[docname][figtype][figure_id]
            except (KeyError, IndexError):
                # target_node is found, but fignumber is not assigned.
                # Maybe it is defined in orphaned document.
                raise ValueError

    def get_full_qualified_name(self, node: Element) -> str:
        if node.get('reftype') == 'option':
            progname = node.get('std:program')
            command = ws_re.split(node.get('reftarget'))
            if progname:
                command.insert(0, progname)
            option = command.pop()
            if command:
                return '.'.join(['-'.join(command), option])
            else:
                return None
        else:
            return None

    def note_citations(self, env: "BuildEnvironment", docname: str,
                       document: nodes.document) -> None:  # NOQA
        warnings.warn('StandardDomain.note_citations() is deprecated.',
                      RemovedInSphinx40Warning)

    def note_citation_refs(self, env: "BuildEnvironment", docname: str,
                           document: nodes.document) -> None:  # NOQA
        warnings.warn('StandardDomain.note_citation_refs() is deprecated.',
                      RemovedInSphinx40Warning)

    def note_labels(self, env: "BuildEnvironment", docname: str,
                    document: nodes.document) -> None:  # NOQA
        warnings.warn('StandardDomain.note_labels() is deprecated.',
                      RemovedInSphinx40Warning)
Beispiel #2
0
class MATLABDomain(Domain):
    """MATLAB language domain."""
    name = 'mat'
    label = 'MATLAB'
    object_types = {
        'function': ObjType(_('function'), 'func', 'obj'),
        'data': ObjType(_('data'), 'data', 'obj'),
        'class': ObjType(_('class'), 'class', 'obj'),
        'exception': ObjType(_('exception'), 'exc', 'obj'),
        'method': ObjType(_('method'), 'meth', 'obj'),
        'classmethod': ObjType(_('class method'), 'meth', 'obj'),
        'staticmethod': ObjType(_('static method'), 'meth', 'obj'),
        'attribute': ObjType(_('attribute'), 'attr', 'obj'),
        'module': ObjType(_('module'), 'mod', 'obj'),
        'script': ObjType(_('script'), 'scpt', 'obj'),
        'application': ObjType(_('application'), 'app', 'obj'),
    }

    directives = {
        'function': MatModulelevel,
        'data': MatModulelevel,
        'class': MatClasslike,
        'exception': MatClasslike,
        'method': MatClassmember,
        'classmethod': MatClassmember,
        'staticmethod': MatClassmember,
        'attribute': MatClassmember,
        'module': MatModule,
        'currentmodule': MatCurrentModule,
        'decorator': MatDecoratorFunction,
        'decoratormethod': MatDecoratorMethod,
        'script': MatModulelevel,
        'application': MatModulelevel,
    }
    roles = {
        'data': MatXRefRole(),
        'exc': MatXRefRole(),
        'func': MatXRefRole(fix_parens=True),
        'class': MatXRefRole(),
        'const': MatXRefRole(),
        'attr': MatXRefRole(),
        'meth': MatXRefRole(fix_parens=True),
        'mod': MatXRefRole(),
        'obj': MatXRefRole(),
        'scpt': MatXRefRole(),
        'app': MatXRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
        'modules': {},  # modname -> docname, synopsis, platform, deprecated
    }
    indices = [
        MATLABModuleIndex,
    ]

    def clear_doc(self, docname):
        for fullname, (fn,
                       _) in list(self.data['objects'].items()):  # noqa: 401
            if fn == docname:
                del self.data['objects'][fullname]
        for modname, (fn, _, _, _) in list(self.data['modules'].items()):
            if fn == docname:
                del self.data['modules'][modname]

    def find_obj(self, env, modname, classname, name, type, searchmode=0):
        """Find a MATLAB object for "name", perhaps using the given module
        and/or classname.  Returns a list of (name, object entry) tuples.
        """
        # skip parens
        if name[-2:] == '()':
            name = name[:-2]

        if not name:
            return []

        objects = self.data['objects']
        matches = []

        newname = None
        if searchmode == 1:
            objtypes = self.objtypes_for_role(type)
            if objtypes is not None:
                if modname and classname:
                    fullname = modname + '.' + classname + '.' + name
                    if fullname in objects and objects[fullname][1] in objtypes:
                        newname = fullname
                if not newname:
                    if modname and modname + '.' + name in objects and \
                       objects[modname + '.' + name][1] in objtypes:
                        newname = modname + '.' + name
                    elif name in objects and objects[name][1] in objtypes:
                        newname = name
                    else:
                        # "fuzzy" searching mode
                        searchname = '.' + name
                        matches = [(oname, objects[oname]) for oname in objects
                                   if oname.endswith(searchname)
                                   and objects[oname][1] in objtypes]
        else:
            # NOTE: searching for exact match, object type is not considered
            if name in objects:
                newname = name
            elif type == 'mod':
                # only exact matches allowed for modules
                return []
            elif classname and classname + '.' + name in objects:
                newname = classname + '.' + name
            elif modname and modname + '.' + name in objects:
                newname = modname + '.' + name
            elif modname and classname and \
                    modname + '.' + classname + '.' + name in objects:
                newname = modname + '.' + classname + '.' + name
            # special case: builtin exceptions have module "exceptions" set
            elif type == 'exc' and '.' not in name and \
                    'exceptions.' + name in objects:
                newname = 'exceptions.' + name
            # special case: object methods
            elif type in ('func', 'meth') and '.' not in name and \
                    'object.' + name in objects:
                newname = 'object.' + name
        if newname is not None:
            matches.append((newname, objects[newname]))
        return matches

    def resolve_xref(self, env, fromdocname, builder, type, target, node,
                     contnode):
        modname = node.get('mat:module')
        clsname = node.get('mat:class')
        searchmode = node.hasattr('refspecific') and 1 or 0
        matches = self.find_obj(env, modname, clsname, target, type,
                                searchmode)
        if not matches:
            return None
        elif len(matches) > 1:
            env.warn_node(
                'more than one target found for cross-reference '
                '%r: %s' % (target, ', '.join(match[0] for match in matches)),
                node)
        name, obj = matches[0]

        if obj[1] == 'module':
            # get additional info for modules
            docname, synopsis, platform, deprecated = self.data['modules'][
                name]
            assert docname == obj[0]
            title = name
            if synopsis:
                title += ': ' + synopsis
            if deprecated:
                title += _(' (deprecated)')
            if platform:
                title += ' (' + platform + ')'
            return make_refnode(builder, fromdocname, docname,
                                'module-' + name, contnode, title)
        else:
            return make_refnode(builder, fromdocname, obj[0], name, contnode,
                                name)

    def get_objects(self):
        for modname, info in self.data['modules'].items():
            yield (modname, modname, 'module', info[0], 'module-' + modname, 0)
        for refname, (docname, type) in self.data['objects'].items():
            yield (refname, refname, type, docname, refname, 1)
class PythonDomain(Domain):
    """Python language domain."""
    name = 'py'
    label = 'Python'
    object_types = {
        'function':     ObjType(_('function'),      'func', 'obj'),
        'data':         ObjType(_('data'),          'data', 'obj'),
        'class':        ObjType(_('class'),         'class', 'exc', 'obj'),
        'exception':    ObjType(_('exception'),     'exc', 'class', 'obj'),
        'method':       ObjType(_('method'),        'meth', 'obj'),
        'classmethod':  ObjType(_('class method'),  'meth', 'obj'),
        'staticmethod': ObjType(_('static method'), 'meth', 'obj'),
        'attribute':    ObjType(_('attribute'),     'attr', 'obj'),
        'module':       ObjType(_('module'),        'mod', 'obj'),
    }  # type: Dict[unicode, ObjType]

    directives = {
        'function':        PyModulelevel,
        'data':            PyModulelevel,
        'class':           PyClasslike,
        'exception':       PyClasslike,
        'method':          PyClassmember,
        'classmethod':     PyClassmember,
        'staticmethod':    PyClassmember,
        'attribute':       PyClassmember,
        'module':          PyModule,
        'currentmodule':   PyCurrentModule,
        'decorator':       PyDecoratorFunction,
        'decoratormethod': PyDecoratorMethod,
    }
    roles = {
        'data':  PyXRefRole(),
        'exc':   PyXRefRole(),
        'func':  PyXRefRole(fix_parens=True),
        'class': PyXRefRole(),
        'const': PyXRefRole(),
        'attr':  PyXRefRole(),
        'meth':  PyXRefRole(fix_parens=True),
        'mod':   PyXRefRole(),
        'obj':   PyXRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
        'modules': {},  # modname -> docname, synopsis, platform, deprecated
    }  # type: Dict[unicode, Dict[unicode, Tuple[Any]]]
    indices = [
        PythonModuleIndex,
    ]

    def clear_doc(self, docname):
        # type: (unicode) -> None
        for fullname, (fn, _l) in list(self.data['objects'].items()):
            if fn == docname:
                del self.data['objects'][fullname]
        for modname, (fn, _x, _x, _x) in list(self.data['modules'].items()):
            if fn == docname:
                del self.data['modules'][modname]

    def merge_domaindata(self, docnames, otherdata):
        # type: (List[unicode], Dict) -> None
        # XXX check duplicates?
        for fullname, (fn, objtype) in otherdata['objects'].items():
            if fn in docnames:
                self.data['objects'][fullname] = (fn, objtype)
        for modname, data in otherdata['modules'].items():
            if data[0] in docnames:
                self.data['modules'][modname] = data

    def find_obj(self, env, modname, classname, name, type, searchmode=0):
        # type: (BuildEnvironment, unicode, unicode, unicode, unicode, int) -> List[Tuple[unicode, Any]]  # NOQA
        """Find a Python object for "name", perhaps using the given module
        and/or classname.  Returns a list of (name, object entry) tuples.
        """
        # skip parens
        if name[-2:] == '()':
            name = name[:-2]

        if not name:
            return []

        objects = self.data['objects']
        matches = []  # type: List[Tuple[unicode, Any]]

        newname = None
        if searchmode == 1:
            if type is None:
                objtypes = list(self.object_types)
            else:
                objtypes = self.objtypes_for_role(type)
            if objtypes is not None:
                if modname and classname:
                    fullname = modname + '.' + classname + '.' + name
                    if fullname in objects and objects[fullname][1] in objtypes:
                        newname = fullname
                if not newname:
                    if modname and modname + '.' + name in objects and \
                       objects[modname + '.' + name][1] in objtypes:
                        newname = modname + '.' + name
                    elif name in objects and objects[name][1] in objtypes:
                        newname = name
                    else:
                        # "fuzzy" searching mode
                        searchname = '.' + name
                        matches = [(oname, objects[oname]) for oname in objects
                                   if oname.endswith(searchname) and
                                   objects[oname][1] in objtypes]
        else:
            # NOTE: searching for exact match, object type is not considered
            if name in objects:
                newname = name
            elif type == 'mod':
                # only exact matches allowed for modules
                return []
            elif classname and classname + '.' + name in objects:
                newname = classname + '.' + name
            elif modname and modname + '.' + name in objects:
                newname = modname + '.' + name
            elif modname and classname and \
                    modname + '.' + classname + '.' + name in objects:
                newname = modname + '.' + classname + '.' + name
            # special case: builtin exceptions have module "exceptions" set
            elif type == 'exc' and '.' not in name and \
                    'exceptions.' + name in objects:
                newname = 'exceptions.' + name
            # special case: object methods
            elif type in ('func', 'meth') and '.' not in name and \
                    'object.' + name in objects:
                newname = 'object.' + name
        if newname is not None:
            matches.append((newname, objects[newname]))
        return matches

    def resolve_xref(self, env, fromdocname, builder,
                     type, target, node, contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        modname = node.get('py:module')
        clsname = node.get('py:class')
        searchmode = node.hasattr('refspecific') and 1 or 0
        matches = self.find_obj(env, modname, clsname, target,
                                type, 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[1] == 'module':
            return self._make_module_refnode(builder, fromdocname, name,
                                             contnode)
        else:
            return make_refnode(builder, fromdocname, obj[0], name,
                                contnode, name)

    def resolve_any_xref(self, env, fromdocname, builder, target,
                         node, contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[Tuple[unicode, nodes.Node]]  # NOQA
        modname = node.get('py:module')
        clsname = node.get('py:class')
        results = []  # type: List[Tuple[unicode, nodes.Node]]

        # 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[1] == 'module':
                results.append(('py:mod',
                                self._make_module_refnode(builder, fromdocname,
                                                          name, contnode)))
            else:
                results.append(('py:' + self.role_for_objtype(obj[1]),
                                make_refnode(builder, fromdocname, obj[0], name,
                                             contnode, name)))
        return results

    def _make_module_refnode(self, builder, fromdocname, name, contnode):
        # type: (Builder, unicode, unicode, nodes.Node) -> nodes.Node
        # get additional info for modules
        docname, synopsis, platform, deprecated = self.data['modules'][name]
        title = name
        if synopsis:
            title += ': ' + synopsis
        if deprecated:
            title += _(' (deprecated)')
        if platform:
            title += ' (' + platform + ')'
        return make_refnode(builder, fromdocname, docname,
                            'module-' + name, contnode, title)

    def get_objects(self):
        # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]]
        for modname, info in iteritems(self.data['modules']):
            yield (modname, modname, 'module', info[0], 'module-' + modname, 0)
        for refname, (docname, type) in iteritems(self.data['objects']):
            if type != 'module':  # modules are already handled
                yield (refname, refname, type, docname, refname, 1)

    def get_full_qualified_name(self, node):
        # type: (nodes.Node) -> unicode
        modname = node.get('py:module')
        clsname = node.get('py:class')
        target = node.get('reftarget')
        if target is None:
            return None
        else:
            return '.'.join(filter(None, [modname, clsname, target]))
Beispiel #4
0
class HTTPDomain(Domain):
    """HTTP domain."""

    name = 'http'
    label = 'HTTP'

    object_types = {
        'options': ObjType('options', 'options', 'obj'),
        'head': ObjType('head', 'head', 'obj'),
        'post': ObjType('post', 'post', 'obj'),
        'get': ObjType('get', 'get', 'obj'),
        'put': ObjType('put', 'put', 'obj'),
        'patch': ObjType('patch', 'patch', 'obj'),
        'delete': ObjType('delete', 'delete', 'obj'),
        'trace': ObjType('trace', 'trace', 'obj')
    }

    directives = {
        'options': HTTPOptions,
        'head': HTTPHead,
        'post': HTTPPost,
        'get': HTTPGet,
        'put': HTTPPut,
        'patch': HTTPPatch,
        'delete': HTTPDelete,
        'trace': HTTPTrace
    }

    roles = {
        'options': HTTPXRefRole('options'),
        'head': HTTPXRefRole('head'),
        'post': HTTPXRefRole('post'),
        'get': HTTPXRefRole('get'),
        'put': HTTPXRefRole('put'),
        'patch': HTTPXRefRole('patch'),
        'delete': HTTPXRefRole('delete'),
        'trace': HTTPXRefRole('trace'),
        'statuscode': http_statuscode_role,
        'method': http_method_role
    }

    initial_data = {
        'options': {}, # path: (docname, synopsis)
        'head': {},
        'post': {},
        'get': {},
        'put': {},
        'patch': {},
        'delete': {},
        'trace': {}
    }

    indices = [HTTPIndex]

    @property
    def routes(self):
        return dict((key, self.data[key]) for key in self.object_types)

    def clear_doc(self, docname):
        for typ, routes in self.routes.iteritems():
            for path, info in routes.items():
                if info[0] == docname:
                    del routes[path]

    def resolve_xref(self, env, fromdocname, builder, typ, target,
                     node, contnode):
        try:
            info = self.data[str(typ)][target]
        except KeyError:
            return
        else:
            anchor = http_resource_anchor(typ, target)
            title = typ.upper() + ' ' + target
            return make_refnode(builder, fromdocname, info[0], anchor,
                                contnode, title)

    def get_objects(self):
        for method, routes in self.routes.iteritems():
            for path, info in routes.iteritems():
                anchor = http_resource_anchor(method, path)
                yield (path, path, method, info[0], anchor, 1)
Beispiel #5
0
Datei: std.py Projekt: th0/test2
class StandardDomain(Domain):
    """
    Domain for all objects that don't fit into another domain or are added
    via the application interface.
    """

    name = 'std'
    label = 'Default'

    object_types = {
        'term': ObjType(l_('glossary term'), 'term', searchprio=-1),
        'token': ObjType(l_('grammar token'), 'token', searchprio=-1),
        'label': ObjType(l_('reference label'), 'ref', 'keyword',
                         searchprio=-1),
        'envvar': ObjType(l_('environment variable'), 'envvar'),
        'cmdoption': ObjType(l_('program option'), 'option'),
    }

    directives = {
        'program': Program,
        'cmdoption': Cmdoption,  # old name for backwards compatibility
        'option': Cmdoption,
        'envvar': EnvVar,
        'glossary': Glossary,
        'productionlist': ProductionList,
    }
    roles = {
        'option':  OptionXRefRole(),
        'envvar':  EnvVarXRefRole(),
        # links to tokens in grammar productions
        'token':   XRefRole(),
        # links to terms in glossary
        'term':    XRefRole(lowercase=True, innernodeclass=nodes.inline,
                            warn_dangling=True),
        # links to headings or arbitrary labels
        'ref':     XRefRole(lowercase=True, innernodeclass=nodes.inline,
                            warn_dangling=True),
        # links to labels of numbered figures, tables and code-blocks
        'numref':  XRefRole(lowercase=True,
                            warn_dangling=True),
        # links to labels, without a different title
        'keyword': XRefRole(warn_dangling=True),
    }

    initial_data = {
        'progoptions': {},  # (program, name) -> docname, labelid
        'objects': {},      # (type, name) -> docname, labelid
        'labels': {         # labelname -> docname, labelid, sectionname
            'genindex': ('genindex', '', l_('Index')),
            'modindex': ('py-modindex', '', l_('Module Index')),
            'search':   ('search', '', l_('Search Page')),
        },
        'anonlabels': {     # labelname -> docname, labelid
            'genindex': ('genindex', ''),
            'modindex': ('py-modindex', ''),
            'search':   ('search', ''),
        },
    }

    dangling_warnings = {
        'term': 'term not in glossary: %(target)s',
        'ref':  'undefined label: %(target)s (if the link has no caption '
                'the label must precede a section header)',
        'numref':  'undefined label: %(target)s',
        'keyword': 'unknown keyword: %(target)s',
    }

    def clear_doc(self, docname):
        for key, (fn, _l) in list(self.data['progoptions'].items()):
            if fn == docname:
                del self.data['progoptions'][key]
        for key, (fn, _l) in list(self.data['objects'].items()):
            if fn == docname:
                del self.data['objects'][key]
        for key, (fn, _l, _l) in list(self.data['labels'].items()):
            if fn == docname:
                del self.data['labels'][key]
        for key, (fn, _l) in list(self.data['anonlabels'].items()):
            if fn == docname:
                del self.data['anonlabels'][key]

    def merge_domaindata(self, docnames, otherdata):
        # XXX duplicates?
        for key, data in otherdata['progoptions'].items():
            if data[0] in docnames:
                self.data['progoptions'][key] = data
        for key, data in otherdata['objects'].items():
            if data[0] in docnames:
                self.data['objects'][key] = data
        for key, data in otherdata['labels'].items():
            if data[0] in docnames:
                self.data['labels'][key] = data
        for key, data in otherdata['anonlabels'].items():
            if data[0] in docnames:
                self.data['anonlabels'][key] = data

    def process_doc(self, env, docname, document):
        labels, anonlabels = self.data['labels'], self.data['anonlabels']
        for name, explicit in iteritems(document.nametypes):
            if not explicit:
                continue
            labelid = document.nameids[name]
            if labelid is None:
                continue
            node = document.ids[labelid]
            if name.isdigit() or 'refuri' in node or \
               node.tagname.startswith('desc_'):
                # ignore footnote labels, labels automatically generated from a
                # link and object descriptions
                continue
            if name in labels:
                env.warn_node('duplicate label %s, ' % name + 'other instance '
                              'in ' + env.doc2path(labels[name][0]), node)
            anonlabels[name] = docname, labelid
            if node.tagname == 'section':
                sectname = clean_astext(node[0])  # node[0] == title node
            elif node.tagname == 'figure':
                for n in node:
                    if n.tagname == 'caption':
                        sectname = clean_astext(n)
                        break
                else:
                    continue
            elif node.tagname == 'image' and node.parent.tagname == 'figure':
                for n in node.parent:
                    if n.tagname == 'caption':
                        sectname = clean_astext(n)
                        break
                else:
                    continue
            elif node.tagname == 'table':
                for n in node:
                    if n.tagname == 'title':
                        sectname = clean_astext(n)
                        break
                else:
                    continue
            elif node.tagname == 'container' and node.get('literal_block'):
                for n in node:
                    if n.tagname == 'caption':
                        sectname = clean_astext(n)
                        break
                else:
                    continue
            elif node.traverse(addnodes.toctree):
                n = node.traverse(addnodes.toctree)[0]
                if n.get('caption'):
                    sectname = n['caption']
                else:
                    continue
            else:
                # anonymous-only labels
                continue
            labels[name] = docname, labelid, sectname

    def build_reference_node(self, fromdocname, builder,
                             docname, labelid, sectname,
                             **options):
        nodeclass = options.pop('nodeclass', nodes.reference)
        newnode = nodeclass('', '', internal=True, **options)
        innernode = nodes.inline(sectname, sectname)
        if docname == fromdocname:
            newnode['refid'] = labelid
        else:
            # set more info in contnode; in case the
            # get_relative_uri call raises NoUri,
            # the builder will then have to resolve these
            contnode = addnodes.pending_xref('')
            contnode['refdocname'] = docname
            contnode['refsectname'] = sectname
            newnode['refuri'] = builder.get_relative_uri(
                fromdocname, docname)
            if labelid:
                newnode['refuri'] += '#' + labelid
        newnode.append(innernode)
        return newnode

    def resolve_xref(self, env, fromdocname, builder,
                     typ, target, node, contnode):
        if typ == 'ref':
            if node['refexplicit']:
                # reference to anonymous label; the reference uses
                # the supplied link caption
                docname, labelid = self.data['anonlabels'].get(target, ('', ''))
                sectname = node.astext()
            else:
                # reference to named label; the final node will
                # contain the section name after the label
                docname, labelid, sectname = self.data['labels'].get(target,
                                                                     ('', '', ''))
            if not docname:
                return None

            return self.build_reference_node(fromdocname, builder,
                                             docname, labelid, sectname)
        elif typ == 'numref':
            docname, labelid = self.data['anonlabels'].get(target, ('', ''))
            if not docname:
                return None

            if env.config.numfig is False:
                env.warn(fromdocname, 'numfig is disabled. :numref: is ignored.')
                return contnode

            try:
                target_node = env.get_doctree(docname).ids[labelid]
                figtype = get_figtype(target_node)
                figure_id = target_node['ids'][0]
                fignumber = env.toc_fignumbers[docname][figtype][figure_id]
            except (KeyError, IndexError):
                return None

            title = contnode.astext()
            if target == fully_normalize_name(title):
                title = env.config.numfig_format.get(figtype, '')

            newtitle = title % '.'.join(map(str, fignumber))
            return self.build_reference_node(fromdocname, builder,
                                             docname, labelid, newtitle,
                                             nodeclass=addnodes.number_reference,
                                             title=title)
        elif typ == 'keyword':
            # keywords are oddballs: they are referenced by named labels
            docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
            if not docname:
                return None
            return make_refnode(builder, fromdocname, docname,
                                labelid, contnode)
        elif typ == 'option':
            target = target.strip()
            # most obvious thing: we are a flag option without program
            if target.startswith(('-', '/', '+')):
                progname = node.get('std:program')
            elif re.search(r'[-/+]', target):
                try:
                    progname, target = re.split(r' (?=-|--|/|\+)', target, 1)
                except ValueError:
                    return None
                progname = ws_re.sub('-', progname.strip())
            else:
                progname = None
            docname, labelid = self.data['progoptions'].get((progname, target),
                                                            ('', ''))
            if not docname:
                return None
            return make_refnode(builder, fromdocname, docname,
                                labelid, contnode)
        else:
            objtypes = self.objtypes_for_role(typ) or []
            for objtype in objtypes:
                if (objtype, target) in self.data['objects']:
                    docname, labelid = self.data['objects'][objtype, target]
                    break
            else:
                docname, labelid = '', ''
            if not docname:
                return None
            return make_refnode(builder, fromdocname, docname,
                                labelid, contnode)

    def resolve_any_xref(self, env, fromdocname, builder, target,
                         node, contnode):
        results = []
        ltarget = target.lower()  # :ref: lowercases its target automatically
        for role in ('ref', 'option'):  # do not try "keyword"
            res = self.resolve_xref(env, fromdocname, builder, role,
                                    ltarget if role == 'ref' else target,
                                    node, contnode)
            if res:
                results.append(('std:' + role, res))
        # all others
        for objtype in self.object_types:
            key = (objtype, target)
            if objtype == 'term':
                key = (objtype, ltarget)
            if key in self.data['objects']:
                docname, labelid = self.data['objects'][key]
                results.append(('std:' + self.role_for_objtype(objtype),
                                make_refnode(builder, fromdocname, docname,
                                             labelid, contnode)))
        return results

    def get_objects(self):
        for (prog, option), info in iteritems(self.data['progoptions']):
            yield (option, option, 'option', info[0], info[1], 1)
        for (type, name), info in iteritems(self.data['objects']):
            yield (name, name, type, info[0], info[1],
                   self.object_types[type].attrs['searchprio'])
        for name, info in iteritems(self.data['labels']):
            yield (name, info[2], 'label', info[0], info[1], -1)
        # add anonymous-only labels as well
        non_anon_labels = set(self.data['labels'])
        for name, info in iteritems(self.data['anonlabels']):
            if name not in non_anon_labels:
                yield (name, name, 'label', info[0], info[1], -1)

    def get_type_name(self, type, primary=False):
        # never prepend "Default"
        return type.lname
class ChapelDomain(Domain):
    """Chapel language domain."""

    name = 'chpl'
    labels = 'Chapel'

    object_types = {
        'data': ObjType(_('data'), 'data', 'const', 'var', 'param', 'type'),
        'type': ObjType(_('type'), 'type', 'data'),
        'function': ObjType(_('function'), 'func', 'proc'),
        'iterfunction': ObjType(_('iterfunction'), 'func', 'iter', 'proc'),
        'enum': ObjType(_('enum'), 'enum'),
        'class': ObjType(_('class'), 'class'),
        'record': ObjType(_('record'), 'record'),
        'method': ObjType(_('method'), 'meth', 'proc'),
        'itermethod': ObjType(_('itermethod'), 'meth', 'iter'),
        'attribute': ObjType(_('attribute'), 'attr'),
        'module': ObjType(_('module'), 'mod'),
    }

    directives = {
        'data': ChapelModuleLevel,
        'type': ChapelModuleLevel,
        'function': ChapelModuleLevel,
        'iterfunction': ChapelModuleLevel,

        # TODO: Consider making enums ChapelClassObject, then each constant
        #       becomes an attribute on the class. Then xrefs to each constant
        #       would be possible, plus it would scale to large numbers of
        #       constants. (thomasvandoren, 2015-03-12)
        'enum': ChapelModuleLevel,

        'class': ChapelClassObject,
        'record': ChapelClassObject,
        'method': ChapelClassMember,
        'itermethod': ChapelClassMember,
        'attribute': ChapelClassMember,
        'module': ChapelModule,
        'currentmodule': ChapelCurrentModule,
    }

    roles = {
        'data': ChapelXRefRole(),
        'const': ChapelXRefRole(),
        'var': ChapelXRefRole(),
        'param': ChapelXRefRole(),
        'type': ChapelXRefRole(),
        'func': ChapelXRefRole(),
        'proc': ChapelXRefRole(),
        'iter': ChapelXRefRole(),
        'class': ChapelXRefRole(),
        'record': ChapelXRefRole(),
        'enum': ChapelXRefRole(),
        'meth': ChapelXRefRole(),
        'attr': ChapelXRefRole(),
        'mod': ChapelXRefRole(),
        'chplref': ChapelXRefRole(),
    }

    initial_data = {
        'objects': {},   # fullname -> docname, objtype
        'modules': {},   # modname -> docname, synopsis, platform, deprecated
        'labels': {      # labelname -> docname, labelid, sectionname
            'chplmodindex': ('chpl-modindex', '', _('Chapel Module Index')),
        },
        'anonlabels': {  # labelname -> docname, labelid
            'chplmodindex': ('chpl-modindex', ''),
        },
    }

    indices = [
        ChapelModuleIndex,
    ]

    def clear_doc(self, docname):
        """Remove the data associated with this instance of the domain."""
        todel = []
        for fullname, (fn, x) in self.data['objects'].items():
            if fn == docname:
                todel.append(fullname)
        for fullname in todel:
            del self.data['objects'][fullname]

        todel = []
        for modname, (fn, x, x, x) in self.data['modules'].items():
            if fn == docname:
                todel.append(modname)
        for modname in todel:
            del self.data['modules'][modname]

        todel = []
        for labelname, (fn, x, x) in self.data['labels'].items():
            if fn == docname:
                todel.append(labelname)
        for labelname in todel:
            del self.data['labels'][labelname]

        todel = []
        for anonlabelname, (fn, x) in self.data['anonlabels'].items():
            if fn == docname:
                todel.append(anonlabelname)
        for anonlabelname in todel:
            del self.data['anonlabels'][anonlabelname]

    def find_obj(self, env, modname, classname, name, type_name, searchmode=0):
        """Find a Chapel object for "name", possibly with module or class/record
        name. Returns a list of (name, object entry) tuples.

        :arg int searchmode: If 1, search more specific names first. Otherwise,
            search built-ins first and then get more specific.
        """
        if name[-2:] == '()':
            name = name[:-2]

        if not name:
            return []

        objects = self.data['objects']
        matches = []

        newname = None
        if searchmode == 1:
            if type_name is None:
                objtypes = list(self.object_types)
            else:
                objtypes = self.objtypes_for_role(type_name)
            if objtypes is not None:
                if modname and classname:
                    fullname = modname + '.' + classname + '.' + name
                    if (fullname in objects and
                            objects[fullname][1] in objtypes):
                        newname = fullname
                if not newname:
                    if (modname and modname + '.' + name in objects and
                            objects[modname + '.' + name][1] in objtypes):
                        newname = modname + '.' + name
                    elif name in objects and objects[name][1] in objtypes:
                        newname = name
                    else:
                        # "Fuzzy" search mode.
                        searchname = '.' + name
                        matches = [(oname, objects[oname]) for oname in objects
                                   if oname.endswith(searchname) and
                                   objects[oname][1] in objtypes]
        else:
            # NOTE: Search for exact match, object type is not considered.
            if name in objects:
                newname = name
            elif type_name == 'mod':
                # Only exact matches allowed for modules.
                return []
            elif classname and classname + '.' + name in objects:
                newname = classname + '.' + name
            elif modname and modname + '.' + name in objects:
                newname = modname + '.' + name
            elif (modname and classname and
                    modname + '.' + classname + '.' + name in objects):
                newname = modname + '.' + classname + '.' + name

        if newname is not None:
            matches.append((newname, objects[newname]))
        return matches

    def resolve_xref(self, env, fromdocname, builder,
                     type_name, target, node, contnode):
        """Resolve the pending_xref *node* with give *type_name* and *target*. Returns
        None if xref node can not be resolved. If xref can be resolved, returns
        new node containing the *contnode*.
        """
        # Special case the :chpl:chplref:`chplmodindex` instances.
        if type_name == 'chplref':
            if node['refexplicit']:
                # Reference to anonymous label. The reference uses the supplied
                # link caption.
                docname, labelid = self.data['anonlabels'].get(
                    target, ('', ''))
                sectname = node.astext()
            else:
                # Reference to named label. The final node will contain the
                # section name after the label.
                docname, labelid, sectname = self.data['labels'].get(
                    target, ('', '', ''))

            if not docname:
                return None

            return self._make_refnode(
                fromdocname, builder, docname, labelid, sectname, contnode)

        modname = node.get('chpl:module')
        clsname = node.get('chpl:class')
        searchmode = 1 if node.hasattr('refspecific') else 0
        matches = self.find_obj(env, modname, clsname, target,
                                type_name, searchmode)

        if not matches:
            return None
        elif len(matches) > 1:
            env.warn_node(
                'more than one target found for cross-reference '
                '%r: %s' % (target, ', '.join(match[0] for match in matches)),
                node)
        name, obj = matches[0]

        if obj[1] == 'module':
            return self._make_module_refnode(
                builder, fromdocname, name, contnode)
        else:
            return make_refnode(builder, fromdocname, obj[0], name,
                                contnode, name)

    def resolve_any_xref(self, env, fromdocname, builder, target,
                         node, contnode):
        """Similar to :py:meth:`ChapelDomain.resolve_xref`, but applies to *any* or
        similar role where type is not known. This returns a list of tuples
        with ("domain:role", newnode).
        """
        modname = node.get('chpl:module')
        clsname = node.get('chpl:class')
        results = []

        # 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[1] == 'module':
                results.append(('chpl:mod',
                                self._make_module_refnode(builder, fromdocname,
                                                          name, contnode)))
            else:
                results.append(
                    ('chpl:' + self.role_for_objtype(obj[1]),
                     make_refnode(builder, fromdocname, obj[0], name,
                                  contnode, name)))

        return results

    def _make_refnode(self, fromdocname, builder, docname, labelid, sectname,
                      contnode, **kwargs):
        """Return reference node for something like ``:chpl:chplref:``."""
        nodeclass = kwargs.pop('nodeclass', nodes.reference)
        newnode = nodeclass('', '', internal=True, **kwargs)
        innernode = nodes.emphasis(sectname, sectname)
        if docname == fromdocname:
            newnode['refid'] = labelid
        else:
            # Set more info on contnode. In case the get_relative_uri call
            # raises NoUri, the builder will then have to resolve these.
            contnode = addnodes.pending_xref('')
            contnode['refdocname'] = docname
            contnode['refsectname'] = sectname
            newnode['refuri'] = builder.get_relative_uri(fromdocname, docname)
            if labelid:
                newnode['refuri'] += '#' + labelid
        newnode.append(innernode)
        return newnode

    def _make_module_refnode(self, builder, fromdocname, name, contnode):
        """Helper function to generate new xref node based on
        current environment.
        """
        # Get additional info for modules.
        docname, synopsis, platform, deprecated = self.data['modules'][name]
        title = name
        if synopsis:
            title += ': ' + synopsis
        if deprecated:
            title += _(' (deprecated)')
        if platform:
            title += ' (' + platform + ')'
        return make_refnode(builder, fromdocname, docname,
                            'module-' + name, contnode, title)

    def merge_domaindata(self, docnames, otherdata):
        """Merge in data regarding *docnames* from a different domaindata inventory
        (coming froma subprocess in a parallel build).
        """
        for fullname, (fn, objtype) in otherdata['objects'].items():
            if fn in docnames:
                self.data['objects'][fullname] = (fn, objtype)
        for modname, data in otherdata['modules'].items():
            if data[0] in docnames:
                self.data['modules'][modname] = data
        for labelname, data in otherdata['labels'].items():
            if data[0] in docnames:
                self.data['labels'][labelname] = data
        for anonlabelname, data in otherdata['anonlabels'].items():
            if data[0] in docnames:
                self.data['anonlabels'][anonlabelname] = data

    def get_objects(self):
        """Return iterable of "object descriptions", which are tuple with these items:

        * `name`
        * `dispname`
        * `type`
        * `docname`
        * `anchor`
        * `priority`

        For details on each item, see
        :py:meth:`~sphinx.domains.Domain.get_objects`.
        """
        for modname, info in self.data['modules'].items():
            yield (modname, modname, 'module', info[0], 'module-' + modname, 0)
        for refname, (docname, type_name) in self.data['objects'].items():
            if type_name != 'module':  # modules are already handled
                yield (refname, refname, type_name, docname, refname, 1)
Beispiel #7
0
class StandardDomain(Domain):
    """
    Domain for all objects that don't fit into another domain or are added
    via the application interface.
    """

    name = 'std'
    label = 'Default'

    object_types = {
        'term': ObjType(_('glossary term'), 'term', searchprio=-1),
        'token': ObjType(_('grammar token'), 'token', searchprio=-1),
        'label': ObjType(_('reference label'), 'ref', 'keyword',
                         searchprio=-1),
        'envvar': ObjType(_('environment variable'), 'envvar'),
        'cmdoption': ObjType(_('program option'), 'option'),
        'doc': ObjType(_('document'), 'doc', searchprio=-1)
    }  # type: Dict[unicode, ObjType]

    directives = {
        'program': Program,
        'cmdoption': Cmdoption,  # old name for backwards compatibility
        'option': Cmdoption,
        'envvar': EnvVar,
        'glossary': Glossary,
        'productionlist': ProductionList,
    }  # type: Dict[unicode, Type[Directive]]
    roles = {
        'option':
        OptionXRefRole(warn_dangling=True),
        'envvar':
        EnvVarXRefRole(),
        # links to tokens in grammar productions
        'token':
        XRefRole(),
        # links to terms in glossary
        'term':
        XRefRole(lowercase=True,
                 innernodeclass=nodes.inline,
                 warn_dangling=True),
        # links to headings or arbitrary labels
        'ref':
        XRefRole(lowercase=True,
                 innernodeclass=nodes.inline,
                 warn_dangling=True),
        # links to labels of numbered figures, tables and code-blocks
        'numref':
        XRefRole(lowercase=True, warn_dangling=True),
        # links to labels, without a different title
        'keyword':
        XRefRole(warn_dangling=True),
        # links to documents
        'doc':
        XRefRole(warn_dangling=True, innernodeclass=nodes.inline),
    }  # type: Dict[unicode, Union[RoleFunction, XRefRole]]

    initial_data = {
        'progoptions': {},      # (program, name) -> docname, labelid
        'objects': {},          # (type, name) -> docname, labelid
        'citations': {},        # citation_name -> docname, labelid, lineno
        'citation_refs': {},    # citation_name -> list of docnames
        'labels': {             # labelname -> docname, labelid, sectionname
            'genindex': ('genindex', '', _('Index')),
            'modindex': ('py-modindex', '', _('Module Index')),
            'search':   ('search', '', _('Search Page')),
        },
        'anonlabels': {         # labelname -> docname, labelid
            'genindex': ('genindex', ''),
            'modindex': ('py-modindex', ''),
            'search':   ('search', ''),
        },
    }

    dangling_warnings = {
        'term': 'term not in glossary: %(target)s',
        'ref': 'undefined label: %(target)s (if the link has no caption '
        'the label must precede a section header)',
        'numref': 'undefined label: %(target)s',
        'keyword': 'unknown keyword: %(target)s',
        'doc': 'unknown document: %(target)s',
        'option': 'unknown option: %(target)s',
        'citation': 'citation not found: %(target)s',
    }

    enumerable_nodes = {  # node_class -> (figtype, title_getter)
        nodes.figure: ('figure', None),
        nodes.table: ('table', None),
        nodes.container: ('code-block', None),
    }  # type: Dict[nodes.Node, Tuple[unicode, Callable]]

    def __init__(self, env):
        # type: (BuildEnvironment) -> None
        super(StandardDomain, self).__init__(env)

        # set up enumerable nodes
        self.enumerable_nodes = copy(
            self.enumerable_nodes)  # create a copy for this instance
        for node, settings in env.app.registry.enumerable_nodes.items():
            self.enumerable_nodes[node] = settings

    def clear_doc(self, docname):
        # type: (unicode) -> None
        for key, (fn, _l) in list(self.data['progoptions'].items()):
            if fn == docname:
                del self.data['progoptions'][key]
        for key, (fn, _l) in list(self.data['objects'].items()):
            if fn == docname:
                del self.data['objects'][key]
        for key, (fn, _l, lineno) in list(self.data['citations'].items()):
            if fn == docname:
                del self.data['citations'][key]
        for key, docnames in list(self.data['citation_refs'].items()):
            if docnames == [docname]:
                del self.data['citation_refs'][key]
            elif docname in docnames:
                docnames.remove(docname)
        for key, (fn, _l, _l) in list(self.data['labels'].items()):
            if fn == docname:
                del self.data['labels'][key]
        for key, (fn, _l) in list(self.data['anonlabels'].items()):
            if fn == docname:
                del self.data['anonlabels'][key]

    def merge_domaindata(self, docnames, otherdata):
        # type: (List[unicode], Dict) -> None
        # XXX duplicates?
        for key, data in otherdata['progoptions'].items():
            if data[0] in docnames:
                self.data['progoptions'][key] = data
        for key, data in otherdata['objects'].items():
            if data[0] in docnames:
                self.data['objects'][key] = data
        for key, data in otherdata['citations'].items():
            if data[0] in docnames:
                self.data['citations'][key] = data
        for key, data in otherdata['citation_refs'].items():
            citation_refs = self.data['citation_refs'].setdefault(key, [])
            for docname in data:
                if docname in docnames:
                    citation_refs.append(docname)
        for key, data in otherdata['labels'].items():
            if data[0] in docnames:
                self.data['labels'][key] = data
        for key, data in otherdata['anonlabels'].items():
            if data[0] in docnames:
                self.data['anonlabels'][key] = data

    def process_doc(self, env, docname, document):
        # type: (BuildEnvironment, unicode, nodes.Node) -> None
        self.note_citations(env, docname, document)
        self.note_citation_refs(env, docname, document)
        self.note_labels(env, docname, document)

    def note_citations(self, env, docname, document):
        # type: (BuildEnvironment, unicode, nodes.Node) -> None
        for node in document.traverse(nodes.citation):
            node['docname'] = docname
            label = node[0].astext()
            if label in self.data['citations']:
                path = env.doc2path(self.data['citations'][label][0])
                logger.warning(
                    __('duplicate citation %s, other instance in %s'),
                    label,
                    path,
                    location=node,
                    type='ref',
                    subtype='citation')
            self.data['citations'][label] = (docname, node['ids'][0],
                                             node.line)

    def note_citation_refs(self, env, docname, document):
        # type: (BuildEnvironment, unicode, nodes.Node) -> None
        for node in document.traverse(addnodes.pending_xref):
            if node['refdomain'] == 'std' and node['reftype'] == 'citation':
                label = node['reftarget']
                citation_refs = self.data['citation_refs'].setdefault(
                    label, [])
                citation_refs.append(docname)

    def note_labels(self, env, docname, document):
        # type: (BuildEnvironment, unicode, nodes.Node) -> None
        labels, anonlabels = self.data['labels'], self.data['anonlabels']
        for name, explicit in document.nametypes.items():
            if not explicit:
                continue
            labelid = document.nameids[name]
            if labelid is None:
                continue
            node = document.ids[labelid]
            if node.tagname == 'target' and 'refid' in node:  # indirect hyperlink targets
                node = document.ids.get(node['refid'])
                labelid = node['names'][0]
            if (node.tagname == 'footnote' or 'refuri' in node
                    or node.tagname.startswith('desc_')):
                # ignore footnote labels, labels automatically generated from a
                # link and object descriptions
                continue
            if name in labels:
                logger.warning(__('duplicate label %s, other instance in %s'),
                               name,
                               env.doc2path(labels[name][0]),
                               location=node)
            anonlabels[name] = docname, labelid
            if node.tagname in ('section', 'rubric'):
                sectname = clean_astext(node[0])  # node[0] == title node
            elif self.is_enumerable_node(node):
                sectname = self.get_numfig_title(node)
                if not sectname:
                    continue
            elif node.traverse(addnodes.toctree):
                n = node.traverse(addnodes.toctree)[0]
                if n.get('caption'):
                    sectname = n['caption']
                else:
                    continue
            else:
                # anonymous-only labels
                continue
            labels[name] = docname, labelid, sectname

    def check_consistency(self):
        # type: () -> None
        for name, (docname, labelid, lineno) in self.data['citations'].items():
            if name not in self.data['citation_refs']:
                logger.warning(__('Citation [%s] is not referenced.'),
                               name,
                               type='ref',
                               subtype='citation',
                               location=(docname, lineno))

    def build_reference_node(self, fromdocname, builder, docname, labelid,
                             sectname, rolename, **options):
        # type: (unicode, Builder, unicode, unicode, unicode, unicode, Any) -> nodes.Node
        nodeclass = options.pop('nodeclass', nodes.reference)
        newnode = nodeclass('', '', internal=True, **options)
        innernode = nodes.inline(sectname, sectname)
        if innernode.get('classes') is not None:
            innernode['classes'].append('std')
            innernode['classes'].append('std-' + rolename)
        if docname == fromdocname:
            newnode['refid'] = labelid
        else:
            # set more info in contnode; in case the
            # get_relative_uri call raises NoUri,
            # the builder will then have to resolve these
            contnode = addnodes.pending_xref('')
            contnode['refdocname'] = docname
            contnode['refsectname'] = sectname
            newnode['refuri'] = builder.get_relative_uri(fromdocname, docname)
            if labelid:
                newnode['refuri'] += '#' + labelid
        newnode.append(innernode)
        return newnode

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        if typ == 'ref':
            resolver = self._resolve_ref_xref
        elif typ == 'numref':
            resolver = self._resolve_numref_xref
        elif typ == 'keyword':
            resolver = self._resolve_keyword_xref
        elif typ == 'doc':
            resolver = self._resolve_doc_xref
        elif typ == 'option':
            resolver = self._resolve_option_xref
        elif typ == 'citation':
            resolver = self._resolve_citation_xref
        else:
            resolver = self._resolve_obj_xref

        return resolver(env, fromdocname, builder, typ, target, node, contnode)

    def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node,
                          contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        if node['refexplicit']:
            # reference to anonymous label; the reference uses
            # the supplied link caption
            docname, labelid = self.data['anonlabels'].get(target, ('', ''))
            sectname = node.astext()
        else:
            # reference to named label; the final node will
            # contain the section name after the label
            docname, labelid, sectname = self.data['labels'].get(
                target, ('', '', ''))
        if not docname:
            return None

        return self.build_reference_node(fromdocname, builder, docname,
                                         labelid, sectname, 'ref')

    def _resolve_numref_xref(self, env, fromdocname, builder, typ, target,
                             node, contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        if target in self.data['labels']:
            docname, labelid, figname = self.data['labels'].get(
                target, ('', '', ''))
        else:
            docname, labelid = self.data['anonlabels'].get(target, ('', ''))
            figname = None

        if not docname:
            return None

        target_node = env.get_doctree(docname).ids.get(labelid)
        figtype = self.get_enumerable_node_type(target_node)
        if figtype is None:
            return None

        if figtype != 'section' and env.config.numfig is False:
            logger.warning(__('numfig is disabled. :numref: is ignored.'),
                           location=node)
            return contnode

        try:
            fignumber = self.get_fignumber(env, builder, figtype, docname,
                                           target_node)
            if fignumber is None:
                return contnode
        except ValueError:
            logger.warning(__("no number is assigned for %s: %s"),
                           figtype,
                           labelid,
                           location=node)
            return contnode

        try:
            if node['refexplicit']:
                title = contnode.astext()
            else:
                title = env.config.numfig_format.get(figtype, '')

            if figname is None and '{name}' in title:
                logger.warning(__('the link has no caption: %s'),
                               title,
                               location=node)
                return contnode
            else:
                fignum = '.'.join(map(str, fignumber))
                if '{name}' in title or 'number' in title:
                    # new style format (cf. "Fig.{number}")
                    if figname:
                        newtitle = title.format(name=figname, number=fignum)
                    else:
                        newtitle = title.format(number=fignum)
                else:
                    # old style format (cf. "Fig.%s")
                    newtitle = title % fignum
        except KeyError as exc:
            logger.warning(__('invalid numfig_format: %s (%r)'),
                           title,
                           exc,
                           location=node)
            return contnode
        except TypeError:
            logger.warning(__('invalid numfig_format: %s'),
                           title,
                           location=node)
            return contnode

        return self.build_reference_node(fromdocname,
                                         builder,
                                         docname,
                                         labelid,
                                         newtitle,
                                         'numref',
                                         nodeclass=addnodes.number_reference,
                                         title=title)

    def _resolve_keyword_xref(self, env, fromdocname, builder, typ, target,
                              node, contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        # keywords are oddballs: they are referenced by named labels
        docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
        if not docname:
            return None
        return make_refnode(builder, fromdocname, docname, labelid, contnode)

    def _resolve_doc_xref(self, env, fromdocname, builder, typ, target, node,
                          contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        # 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)

    def _resolve_option_xref(self, env, fromdocname, builder, typ, target,
                             node, contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        progname = node.get('std:program')
        target = target.strip()
        docname, labelid = self.data['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.data['progoptions'].get(
                    (progname, target), ('', ''))
                if docname:
                    break
            else:
                return None

        return make_refnode(builder, fromdocname, docname, labelid, contnode)

    def _resolve_citation_xref(self, env, fromdocname, builder, typ, target,
                               node, contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        from sphinx.environment import NoUri

        docname, labelid, lineno = self.data['citations'].get(
            target, ('', '', 0))
        if not docname:
            if 'ids' in node:
                # remove ids attribute that annotated at
                # transforms.CitationReference.apply.
                del node['ids'][:]
            return None

        try:
            return make_refnode(builder, fromdocname, docname, labelid,
                                contnode)
        except NoUri:
            # remove the ids we added in the CitationReferences
            # transform since they can't be transfered to
            # the contnode (if it's a Text node)
            if not isinstance(contnode, nodes.Element):
                del node['ids'][:]
            raise

    def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node,
                          contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        objtypes = self.objtypes_for_role(typ) or []
        for objtype in objtypes:
            if (objtype, target) in self.data['objects']:
                docname, labelid = self.data['objects'][objtype, target]
                break
        else:
            docname, labelid = '', ''
        if not docname:
            return None
        return make_refnode(builder, fromdocname, docname, labelid, contnode)

    def resolve_any_xref(self, env, fromdocname, builder, target, node,
                         contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[Tuple[unicode, nodes.Node]]  # NOQA
        results = []  # type: List[Tuple[unicode, nodes.Node]]
        ltarget = target.lower()  # :ref: lowercases its target automatically
        for role in ('ref', 'option'):  # do not try "keyword"
            res = self.resolve_xref(env, fromdocname, builder, role,
                                    ltarget if role == 'ref' else target, node,
                                    contnode)
            if res:
                results.append(('std:' + role, res))
        # all others
        for objtype in self.object_types:
            key = (objtype, target)
            if objtype == 'term':
                key = (objtype, ltarget)
            if key in self.data['objects']:
                docname, labelid = self.data['objects'][key]
                results.append(('std:' + self.role_for_objtype(objtype),
                                make_refnode(builder, fromdocname, docname,
                                             labelid, contnode)))
        return results

    def get_objects(self):
        # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]]
        # handle the special 'doc' reference here
        for doc in self.env.all_docs:
            yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1)
        for (prog, option), info in self.data['progoptions'].items():
            if prog:
                fullname = ".".join([prog, option])
                yield (fullname, fullname, 'cmdoption', info[0], info[1], 1)
            else:
                yield (option, option, 'cmdoption', info[0], info[1], 1)
        for (type, name), info in self.data['objects'].items():
            yield (name, name, type, info[0], info[1],
                   self.object_types[type].attrs['searchprio'])
        for name, info in self.data['labels'].items():
            yield (name, info[2], 'label', info[0], info[1], -1)
        # add anonymous-only labels as well
        non_anon_labels = set(self.data['labels'])
        for name, info in self.data['anonlabels'].items():
            if name not in non_anon_labels:
                yield (name, name, 'label', info[0], info[1], -1)

    def get_type_name(self, type, primary=False):
        # type: (ObjType, bool) -> unicode
        # never prepend "Default"
        return type.lname

    def is_enumerable_node(self, node):
        # type: (nodes.Node) -> bool
        return node.__class__ in self.enumerable_nodes

    def get_numfig_title(self, node):
        # type: (nodes.Node) -> unicode
        """Get the title of enumerable nodes to refer them using its title"""
        if self.is_enumerable_node(node):
            _, title_getter = self.enumerable_nodes.get(
                node.__class__, (None, None))
            if title_getter:
                return title_getter(node)
            else:
                for subnode in node:
                    if subnode.tagname in ('caption', 'title'):
                        return clean_astext(subnode)

        return None

    def get_enumerable_node_type(self, node):
        # type: (nodes.Node) -> unicode
        """Get type of enumerable nodes."""
        def has_child(node, cls):
            # type: (nodes.Node, 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 get_figtype(self, node):
        # type: (nodes.Node) -> unicode
        """Get figure type of nodes.

        .. deprecated:: 1.8
        """
        warnings.warn(
            'StandardDomain.get_figtype() is deprecated. '
            'Please use get_enumerable_node_type() instead.',
            RemovedInSphinx30Warning)
        return self.get_enumerable_node_type(node)

    def get_fignumber(self, env, builder, figtype, docname, target_node):
        # type: (BuildEnvironment, Builder, unicode, unicode, nodes.Node) -> Tuple[int, ...]
        if figtype == 'section':
            if builder.name == 'latex':
                return tuple()
            elif docname not in env.toc_secnumbers:
                raise ValueError  # no number assigned
            else:
                anchorname = '#' + target_node['ids'][0]
                if anchorname not in env.toc_secnumbers[docname]:
                    # try first heading which has no anchor
                    return env.toc_secnumbers[docname].get('')
                else:
                    return env.toc_secnumbers[docname].get(anchorname)
        else:
            try:
                figure_id = target_node['ids'][0]
                return env.toc_fignumbers[docname][figtype][figure_id]
            except (KeyError, IndexError):
                # target_node is found, but fignumber is not assigned.
                # Maybe it is defined in orphaned document.
                raise ValueError

    def get_full_qualified_name(self, node):
        # type: (nodes.Node) -> unicode
        if node.get('reftype') == 'option':
            progname = node.get('std:program')
            command = ws_re.split(node.get('reftarget'))
            if progname:
                command.insert(0, progname)
            option = command.pop()
            if command:
                return '.'.join(['-'.join(command), option])
            else:
                return None
        else:
            return None
Beispiel #8
0
class CPPDomain(Domain):
    """C++ language domain."""
    name = 'cpp'
    label = 'C++'
    object_types = {
        'class':    ObjType(l_('class'),    'class'),
        'function': ObjType(l_('function'), 'func'),
        'member':   ObjType(l_('member'),   'member'),
        'type':     ObjType(l_('type'),     'type')
    }

    directives = {
        'class':        CPPClassObject,
        'function':     CPPFunctionObject,
        'member':       CPPMemberObject,
        'type':         CPPTypeObject,
        'namespace':    CPPCurrentNamespace
    }
    roles = {
        'class':  CPPXRefRole(),
        'func' :  CPPXRefRole(fix_parens=True),
        'member': CPPXRefRole(),
        'type':   CPPXRefRole()
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
    }

    def clear_doc(self, docname):
        for fullname, (fn, _, _) in self.data['objects'].items():
            if fn == docname:
                del self.data['objects'][fullname]

    def resolve_xref(self, env, fromdocname, builder,
                     typ, target, node, contnode):
        def _create_refnode(expr):
            name = unicode(expr)
            if name not in self.data['objects']:
                return None
            obj = self.data['objects'][name]
            if obj[1] not in self.objtypes_for_role(typ):
                return None
            return make_refnode(builder, fromdocname, obj[0], obj[2],
                                contnode, name)

        parser = DefinitionParser(target)
        try:
            expr = parser.parse_type().get_name()
            parser.skip_ws()
            if not parser.eof or expr is None:
                raise DefinitionError('')
        except DefinitionError:
            env.warn_node('unparseable C++ definition: %r' % target, node)
            return None

        parent = node.get('cpp:parent', None)

        rv = _create_refnode(expr)
        if rv is not None or parent is None:
            return rv
        parent = parent.get_name()

        rv = _create_refnode(expr.prefix(parent))
        if rv is not None:
            return rv

        parent, name = parent.split_owner()
        return _create_refnode(expr.prefix(parent))

    def get_objects(self):
        for refname, (docname, type, theid) in self.data['objects'].iteritems():
            yield (refname, refname, type, docname, refname, 1)
Beispiel #9
0
class CMakeDomain(Domain):
    """CMake domain."""

    name = "cmake"
    label = "CMake"
    object_types = {
        "command": ObjType("command", "command"),
        "generator": ObjType("generator", "generator"),
        "variable": ObjType("variable", "variable"),
        "module": ObjType("module", "module"),
        "policy": ObjType("policy", "policy"),
        "prop_cache": ObjType("prop_cache", "prop_cache"),
        "prop_dir": ObjType("prop_dir", "prop_dir"),
        "prop_gbl": ObjType("prop_gbl", "prop_gbl"),
        "prop_inst": ObjType("prop_inst", "prop_inst"),
        "prop_sf": ObjType("prop_sf", "prop_sf"),
        "prop_test": ObjType("prop_test", "prop_test"),
        "prop_tgt": ObjType("prop_tgt", "prop_tgt"),
        "manual": ObjType("manual", "manual"),
    }
    directives = {
        "command": CMakeObject,
        "variable": CMakeObject,
        # Other object types cannot be created except by the CMakeTransform
        # 'generator':  CMakeObject,
        # 'module':     CMakeObject,
        # 'policy':     CMakeObject,
        # 'prop_cache': CMakeObject,
        # 'prop_dir':   CMakeObject,
        # 'prop_gbl':   CMakeObject,
        # 'prop_inst':  CMakeObject,
        # 'prop_sf':    CMakeObject,
        # 'prop_test':  CMakeObject,
        # 'prop_tgt':   CMakeObject,
        # 'manual':     CMakeObject,
    }
    roles = {
        "command": CMakeXRefRole(fix_parens=True, lowercase=True),
        "generator": CMakeXRefRole(),
        "variable": CMakeXRefRole(),
        "module": CMakeXRefRole(),
        "policy": CMakeXRefRole(),
        "prop_cache": CMakeXRefRole(),
        "prop_dir": CMakeXRefRole(),
        "prop_gbl": CMakeXRefRole(),
        "prop_inst": CMakeXRefRole(),
        "prop_sf": CMakeXRefRole(),
        "prop_test": CMakeXRefRole(),
        "prop_tgt": CMakeXRefRole(),
        "manual": CMakeXRefRole(),
    }
    initial_data = {
        "objects": {},  # fullname -> docname, objtype
    }

    def clear_doc(self, docname):
        to_clear = set()
        for fullname, (fn, _) in self.data["objects"].items():
            if fn == docname:
                to_clear.add(fullname)
        for fullname in to_clear:
            del self.data["objects"][fullname]

    def resolve_xref(
        self, env, fromdocname, builder, typ, target, node, contnode
    ):
        targetid = "%s:%s" % (typ, target)
        obj = self.data["objects"].get(targetid)
        if obj is None:
            # TODO: warn somehow?
            return None
        return make_refnode(
            builder, fromdocname, obj[0], targetid, contnode, target
        )

    def get_objects(self):
        for refname, (docname, type) in self.data["objects"].items():
            yield (refname, refname, type, docname, refname, 1)
Beispiel #10
0
class MinIODomain(Domain):
    """MinIO language domain."""
    name = 'minio'
    label = 'MinIO'
    # if you add a new object type make sure to edit MinioObject.get_index_string
    object_types = {
        'data': ObjType(_('data'), 'data'),
        'kubeconf': ObjType(_('kubeconf'), 'kubeconf'),
        'userpolicy': ObjType(_('userpolicy'), 'userpolicy'),
        'command': ObjType(_('command'), 'command'),
        'subcommand': ObjType(_('subcommand'), 'subcommand'),
        'flag': ObjType(_('flag'), 'flag'),
        'mc': ObjType(_('mc'), 'mc'),
        'mc-cmd': ObjType(_('mc-cmd'), 'mc-cmd'),
        'mc-cmd-option': ObjType(_('mc-cmd-option'), 'mc-cmd-option'),
        'policy-action': ObjType(_('policy-action'), 'policy-action'),
    }
    directives = {
        'data': MinioObject,
        'kubeconf': MinioObject,
        'userpolicy': MinioObject,
        'command': MinioCommand,
        'subcommand': MinioCommand,
        'flag': MinioObject,
        'mc': MinioMCCommand,
        'mc-cmd': MinioMCObject,
        'policy-action': MinioObject
    }
    roles = {
        'data': MinioXRefRole(),
        'kubeconf': MinioXRefRole(),
        'userpolicy': MinioXRefRole(),
        'command': MinioXRefRole(),
        'subcommand': MinioXRefRole(),
        'flag': MinioXRefRole(),
        'mc': MinioXRefRole(),
        'mc-cmd': MinioXRefRole(),
        'mc-cmd-option': MinioCMDOptionXRefRole(),
        'policy-action': MinioXRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, node_id, objtype
        'modules': {},  # modname  -> docname, node_id
        'commands': {},
    }  # type: Dict[str, Dict[str, Tuple[str, str]]]

    @property
    def objects(self) -> Dict[str, Tuple[str, str, str]]:
        return self.data.setdefault(
            'objects', {})  # fullname -> docname, node_id, objtype

    def note_object(self,
                    fullname: str,
                    objtype: str,
                    node_id: str,
                    location: Any = None) -> None:
        if fullname in self.objects:
            docname = self.objects[fullname][0]
            logger.warning(
                __('duplicate %s description of %s, other %s in %s'),
                objtype,
                fullname,
                objtype,
                docname,
                location=location)
        self.objects[fullname] = (self.env.docname, node_id, objtype)

    @property
    def modules(self) -> Dict[str, Tuple[str, str]]:
        return self.data.setdefault('modules',
                                    {})  # modname -> docname, node_id

    def note_module(self, modname: str, node_id: str) -> None:
        self.modules[modname] = (self.env.docname, node_id)

    @property
    def command(self) -> Dict[str, Tuple[str, str]]:
        return self.data.setdefault('command',
                                    {})  # command -> commandname, node_id

    def note_command(self, commandname: str, node_id: str) -> None:
        self.command[commandname] = (self.env.docname, node_id)

    def clear_doc(self, docname: str) -> None:
        for fullname, (pkg_docname, node_id, _l) in list(self.objects.items()):
            if pkg_docname == docname:
                del self.objects[fullname]
        for modname, (pkg_docname, node_id) in list(self.modules.items()):
            if pkg_docname == docname:
                del self.modules[modname]

    def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
        # XXX check duplicates
        for fullname, (fn, node_id, objtype) in otherdata['objects'].items():
            if fn in docnames:
                self.objects[fullname] = (fn, node_id, objtype)
        for mod_name, (pkg_docname, node_id) in otherdata['modules'].items():
            if pkg_docname in docnames:
                self.modules[mod_name] = (pkg_docname, node_id)

    def find_obj(self,
                 env: BuildEnvironment,
                 mod_name: str,
                 prefix: str,
                 name: str,
                 typ: str,
                 searchorder: int = 0) -> Tuple[str, Tuple[str, str, str]]:
        if name[-2:] == '()':
            name = name[:-2]

        searches = []
        if mod_name and prefix:
            searches.append('.'.join([mod_name, prefix, name]))
        if mod_name:
            searches.append('.'.join([mod_name, name]))
        if prefix:
            searches.append('.'.join([prefix, name]))
        searches.append(name)

        if searchorder == 0:
            searches.reverse()

        newname = None
        for search_name in searches:
            if search_name in self.objects:
                newname = search_name

        return newname, self.objects.get(newname)

    def resolve_xref(self, env: BuildEnvironment, fromdocname: str,
                     builder: Builder, typ: str, target: str,
                     node: pending_xref, contnode: Element) -> Element:
        mod_name = node.get('minio:module')
        prefix = node.get('minio: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)

    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('minio:module')
        prefix = node.get('minio:object')
        name, obj = self.find_obj(env, mod_name, prefix, target, None, 1)
        if not obj:
            return []
        return [('minio:' + self.role_for_objtype(obj[2]),
                 make_refnode(builder, fromdocname, obj[0], obj[1], contnode,
                              name))]

    def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
        for refname, (docname, node_id, typ) in list(self.objects.items()):
            yield refname, refname, typ, docname, node_id, 1

    def get_full_qualified_name(self, node: Element) -> str:
        modname = node.get('minio:module')
        prefix = node.get('minio:object')
        target = node.get('reftarget')
        if target is None:
            return None
        else:
            return '.'.join(filter(None, [modname, prefix, target]))
class BBDomain(Domain):
    name = 'bb'
    label = 'Buildbot'

    object_types = {
        'cfg': ObjType('cfg', 'cfg'),
        'sched': ObjType('sched', 'sched'),
        'chsrc': ObjType('chsrc', 'chsrc'),
        'step': ObjType('step', 'step'),
        'reporter': ObjType('reporter', 'reporter'),
        'configurator': ObjType('configurator', 'configurator'),
        'worker': ObjType('worker', 'worker'),
        'cmdline': ObjType('cmdline', 'cmdline'),
        'msg': ObjType('msg', 'msg'),
        'event': ObjType('event', 'event'),
        'rtype': ObjType('rtype', 'rtype'),
        'rpath': ObjType('rpath', 'rpath'),
    }

    directives = {
        'cfg':
        make_ref_target_directive('cfg',
                                  indextemplates=[
                                      'single: Buildmaster Config; %s',
                                      'single: %s (Buildmaster Config)',
                                  ]),
        'sched':
        make_ref_target_directive('sched',
                                  indextemplates=[
                                      'single: Schedulers; %s',
                                      'single: %s Scheduler',
                                  ]),
        'chsrc':
        make_ref_target_directive('chsrc',
                                  indextemplates=[
                                      'single: Change Sources; %s',
                                      'single: %s Change Source',
                                  ]),
        'step':
        make_ref_target_directive('step',
                                  indextemplates=[
                                      'single: Build Steps; %s',
                                      'single: %s Build Step',
                                  ]),
        'reporter':
        make_ref_target_directive('reporter',
                                  indextemplates=[
                                      'single: Reporter Targets; %s',
                                      'single: %s Reporter Target',
                                  ]),
        'configurator':
        make_ref_target_directive('configurator',
                                  indextemplates=[
                                      'single: Configurators; %s',
                                      'single: %s Configurators',
                                  ]),
        'worker':
        make_ref_target_directive('worker',
                                  indextemplates=[
                                      'single: Build Workers; %s',
                                      'single: %s Build Worker',
                                  ]),
        'cmdline':
        make_ref_target_directive('cmdline',
                                  indextemplates=[
                                      'single: Command Line Subcommands; %s',
                                      'single: %s Command Line Subcommand',
                                  ]),
        'msg':
        make_ref_target_directive('msg',
                                  indextemplates=[
                                      'single: Message Schema; %s',
                                  ],
                                  has_content=True,
                                  name_annotation='routing key:',
                                  doc_field_types=[
                                      TypedField('key',
                                                 label='Keys',
                                                 names=('key', ),
                                                 typenames=('type', ),
                                                 can_collapse=True),
                                      Field('var',
                                            label='Variable',
                                            names=('var', )),
                                  ]),
        'event':
        make_ref_target_directive('event',
                                  indextemplates=[
                                      'single: event; %s',
                                  ],
                                  has_content=True,
                                  name_annotation='event:',
                                  doc_field_types=[]),
        'rtype':
        make_ref_target_directive('rtype',
                                  indextemplates=[
                                      'single: Resource Type; %s',
                                  ],
                                  has_content=True,
                                  name_annotation='resource type:',
                                  doc_field_types=[
                                      TypedField('attr',
                                                 label='Attributes',
                                                 names=('attr', ),
                                                 typenames=('type', ),
                                                 can_collapse=True),
                                  ]),
        'rpath':
        make_ref_target_directive('rpath',
                                  indextemplates=[
                                      'single: Resource Path; %s',
                                  ],
                                  name_annotation='path:',
                                  has_content=True,
                                  doc_field_types=[
                                      TypedField('pathkey',
                                                 label='Path Keys',
                                                 names=('pathkey', ),
                                                 typenames=('type', ),
                                                 can_collapse=True),
                                  ]),
        'raction':
        make_ref_target_directive('raction',
                                  indextemplates=[
                                      'single: Resource Action; %s',
                                  ],
                                  name_annotation='POST with method:',
                                  has_content=True,
                                  doc_field_types=[
                                      TypedField('body',
                                                 label='Body keys',
                                                 names=('body', ),
                                                 typenames=('type', ),
                                                 can_collapse=True),
                                  ]),
    }

    roles = {
        'cfg': XRefRole(),
        'sched': XRefRole(),
        'chsrc': XRefRole(),
        'step': XRefRole(),
        'reporter': XRefRole(),
        'configurator': XRefRole(),
        'worker': XRefRole(),
        'cmdline': XRefRole(),
        'msg': XRefRole(),
        'event': XRefRole(),
        'rtype': XRefRole(),
        'rpath': XRefRole(),
        'index': XRefRole()
    }

    initial_data = {
        'targets': {},  # type -> target -> (docname, targetname)
    }

    indices = [
        make_index("cfg", "Buildmaster Configuration Index"),
        make_index("sched", "Scheduler Index"),
        make_index("chsrc", "Change Source Index"),
        make_index("step", "Build Step Index"),
        make_index("reporter", "Reporter Target Index"),
        make_index("configurator", "Configurator Target Index"),
        make_index("worker", "Build Worker Index"),
        make_index("cmdline", "Command Line Index"),
        make_index("msg", "MQ Routing Key Index"),
        make_index("event", "Data API Event Index"),
        make_index("rtype", "REST/Data API Resource Type Index"),
        make_index("rpath", "REST/Data API Path Index"),
        make_index("raction", "REST/Data API Actions Index"),
    ]

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        if typ == 'index':
            for idx in self.indices:
                if idx.name == target:
                    break
            else:
                raise KeyError("no index named '%s'" % target)
            return idx.resolve_ref(self, env, fromdocname, builder, typ,
                                   target, node, contnode)
        elif typ in self.directives:
            dir = self.directives[typ]
            return dir.resolve_ref(self, env, fromdocname, builder, typ,
                                   target, node, contnode)
Beispiel #12
0
class CondaDomain(Domain):
    name = "conda"
    object_types = {'package': ObjType('package', 'package')}
    roles = {'package': XRefRole()}
Beispiel #13
0
class CabalDomain(Domain):
    '''
    Sphinx domain for cabal

    needs Domain.merge_doc for parallel building, just union all dicts
    '''
    name = 'cabal'
    label = 'Cabal'
    object_types = {
        'pkg-section': ObjType(l_('pkg-section'), 'pkg-section'),
        'pkg-field'  : ObjType(l_('pkg-field')  , 'pkg-field'  ),
        'cfg-section': ObjType(l_('cfg-section'), 'cfg-section'),
        'cfg-field'  : ObjType(l_('cfg-field')  , 'cfg-field' ),
    }
    directives = {
        'pkg-section': CabalPackageSection,
        'pkg-field'  : CabalPackageField,
        'cfg-section': CabalConfigSection,
        'cfg-field'  : ConfigField,
    }
    roles = {
        'pkg-section': XRefRole(warn_dangling=True),
        'pkg-field'  : CabalPackageFieldXRef(warn_dangling=True),
        'cfg-section': XRefRole(warn_dangling=True),
        'cfg-field'  : CabalConfigFieldXRef(warn_dangling=True),
        'cfg-flag'   : CabalConfigFieldXRef(warn_dangling=True),
    }
    initial_data = {
        'pkg-sections': {},
        'pkg-fields'  : {},
        'cfg-sections': {},
        'index-num'   : {}, #per document number of objects
                            # used to order references page
        'cfg-fields'  : {},
        'cfg-flags'   : {},
    }
    indices = [
        ConfigFieldIndex
    ]
    types = {
        'pkg-section': 'pkg-sections',
        'pkg-field'  : 'pkg-fields',
        'cfg-section': 'cfg-sections',
        'cfg-field'  : 'cfg-fields',
        'cfg-flag'   : 'cfg-flags',
    }
    def clear_doc(self, docname):
        for k in ['pkg-sections', 'pkg-fields', 'cfg-sections',
                  'cfg-fields', 'cfg-flags']:
            for name, (fn, _, _) in self.data[k].items():
                if fn == docname:
                    del self.data[k][comname]
        try:
            del self.data['index-num'][docname]
        except KeyError:
            pass

    def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode):
        objtypes = self.objtypes_for_role(type)
        for typ, key in ((typ, key)
                         for typ in objtypes
                         for key in make_data_keys(typ, target, node)):
            try:
                data = env.domaindata['cabal'][self.types[typ]][key]
            except KeyError:
                continue
            doc, ref, meta = data
            title = make_title(typ, key, meta)
            return make_refnode(builder, fromdocname, doc, ref, contnode, title)

    def get_objects(self):
        '''
        Used for search functionality
        '''
        for typ in ['pkg-section', 'pkg-field',
                    'cfg-section', 'cfg-field', 'cfg-flag']:
            key = self.types[typ]
            for name, (fn, target, meta) in self.data[key].items():
                title = make_title(typ, name, meta)
                yield title, title, typ, fn, target, 0
Beispiel #14
0
class RoseDomain(Domain):
    """Sphinx extension to add the ability to document Rose objects.

    Example:

        Click :guilabel:`source` to view source code.

        .. code-block:: rst

           .. rose:app: foo

              An app called ``foo``.

              .. rose:conf: bar

                 A setting called ``bar`` for the app ``foo``.

              .. rose:conf: baz

                 A config section called ``baz`` for the app ``foo``.

                 .. rose:conf: pub

                    A config setting called ``[baz]pub`` for the app ``foo``.
    """

    name = 'rose'
    """Prefix for Rose domain (used by sphinx)."""
    label = 'Rose'
    """Display label for the Rose domain (used by sphinx)."""

    object_types = {
        'app': ObjType('app', 'app', 'obj'),
        'file': ObjType('file', 'file', 'obj'),
        'conf': ObjType('conf', 'conf', 'obj')
    }
    """List of object types, this should mirror ``directives``."""

    directives = {
        'app': RoseAppDirective,
        'file': RoseFileDirective,
        'conf': RoseConfigDirective
    }
    """List of domains associated with prefixes (e.g. ``app`` becomes the
    ``rose:app`` domain."""

    roles = {
        'app': RoseXRefRole(),
        'file': RoseXRefRole(),
        'conf': RoseXRefRole()
    }
    """Sphinx text roles associated with the domain. Text roles are required
    for referencing objects. There should be one role for each item in
    ``object_types``"""

    initial_data = {
        'objects': {}  # path: (docname, synopsis)
    }
    """This sets ``self.data`` on initialisation."""
    def clear_doc(self, docname):
        """Removes documented items from  the Rose domain.

        Not sure why, but apparently necessary.
        """
        for fullname, (pkg_docname, _l) in list(self.data['objects'].items()):
            if pkg_docname == docname:
                del self.data['objects'][fullname]

    def get_objects(self):
        """Iterates through documented items in the Rose domain."""
        for refname, (docname, type_) in list(self.data['objects'].items()):
            yield refname, refname, type_, docname, refname, 1

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        """Associate a reference with a documented object.

        The important parameters are:
            typ (str): The object type - see ``RoseDomain.object_types``.
            target (str): The rest of the reference as written in the rst.

        This implementation simplifies things by storing objects under their
        namespace which is the same syntax used to reference the objects i.e:

        .. rose:app: Foo

        Creates the entry ``self.data['objects']['rose:app:foo']``.

        Which can be referenced in rst by:

        .. code-block:: rst

           :rose:app:`foo`
        """
        # If target has a trailing argument ignore it.
        target = OPT_ARG_REGEX.search(target).groups()[0]

        # Determine the namespace of the object being referenced.
        if typ in ['app', 'file']:
            # Object is a root rose config - path is absolute.
            namespace = 'rose:%s:%s' % (typ, target)
        elif typ == 'obj':
            # Object is an 'obj' e.g. an environment variable, 'obj's are not
            # referenceable (yet).
            return None
        elif typ == 'conf':
            relative_to_conf = False
            if target.startswith('['):
                # Target is relative to the context conf_file.
                relative_to_conf = True

            # Get the referenced namespace in tokenised form.
            reference_namespace = tokenise_namespace('rose:%s:%s' %
                                                     (typ, target))
            if reference_namespace[0][0] in ['rose:app', 'rose:file']:
                # Target is a root rose config - path is absolute.
                namespace = 'rose:%s:%s' % (typ, target)
            else:
                # Target is not a root config - path is relative.
                context_namespace = tokens_from_ref_context(
                    node['ref_context'])
                if not context_namespace:
                    LOGGER.warning(
                        'Relative reference requires local context ' +
                        '"%s".' % (target),
                        location=node)
                    return
                if relative_to_conf:
                    # Target is relative to the context conf_file.
                    namespace_tokens = (context_namespace[:1] +
                                        reference_namespace)
                else:
                    # Target is relative to the current namespace.
                    namespace_tokens = (context_namespace[:-1] +
                                        reference_namespace)
                # Convert the tokenised namespace into a string namespace.
                namespace = namespace_from_tokens(namespace_tokens)

        # Lookup the object from the namespace.
        try:
            data = self.data['objects'][namespace]
        except KeyError:
            # No reference exists for "object_name".
            LOGGER.warning('No Ref for "%s"' % namespace, location=node)
            return None

        # Create a link pointing at the object.
        return make_refnode(builder, fromdocname, data[0], namespace, contnode,
                            namespace)
 def get_type(cls):
     return ObjType(l_(cls.long_name), cls.short_name, cls.long_name, 'obj')
Beispiel #16
0
class ReSTDomain(Domain):
    """ReStructuredText domain."""
    name = 'rst'
    label = 'reStructuredText'

    object_types = {
        'directive': ObjType(_('directive'), 'dir'),
        'role': ObjType(_('role'), 'role'),
    }
    directives = {
        'directive': ReSTDirective,
        'role': ReSTRole,
    }
    roles = {
        'dir': XRefRole(),
        'role': XRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
    }  # type: Dict[unicode, Dict[unicode, Tuple[unicode, ObjType]]]

    def clear_doc(self, docname):
        # type: (unicode) -> None
        for (typ, name), doc in list(self.data['objects'].items()):
            if doc == docname:
                del self.data['objects'][typ, name]

    def merge_domaindata(self, docnames, otherdata):
        # type: (List[unicode], Dict) -> None
        # XXX check duplicates
        for (typ, name), doc in otherdata['objects'].items():
            if doc in docnames:
                self.data['objects'][typ, name] = doc

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, addnodes.pending_xref, nodes.Element) -> nodes.Element  # NOQA
        objects = self.data['objects']
        objtypes = self.objtypes_for_role(typ)
        for objtype in objtypes:
            if (objtype, target) in objects:
                return make_refnode(builder, fromdocname, objects[objtype,
                                                                  target],
                                    objtype + '-' + target, contnode,
                                    target + ' ' + objtype)
        return None

    def resolve_any_xref(self, env, fromdocname, builder, target, node,
                         contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, addnodes.pending_xref, nodes.Element) -> List[Tuple[unicode, nodes.Element]]  # NOQA
        objects = self.data['objects']
        results = []  # type: List[Tuple[unicode, nodes.Element]]
        for objtype in self.object_types:
            if (objtype, target) in self.data['objects']:
                results.append(
                    ('rst:' + self.role_for_objtype(objtype),
                     make_refnode(builder, fromdocname, objects[objtype,
                                                                target],
                                  objtype + '-' + target, contnode,
                                  target + ' ' + objtype)))
        return results

    def get_objects(self):
        # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]]
        for (typ, name), docname in self.data['objects'].items():
            yield name, name, typ, docname, typ + '-' + name, 1
Beispiel #17
0
class PerconaServerDomain(Domain):
    """Percona Server domain."""
    name = 'psdom'
    label = 'Percona Server'
    object_types = {
        'db': ObjType(l_('db'), 'db'),
        'table': ObjType(l_('table'), 'table'),
        'column': ObjType(l_('column'), 'column'),
        'option': ObjType(l_('option'), 'option'),
        'variable': ObjType(l_('variable'), 'data'),
    }

    directives = {
        'db': PSDatabase,
        'table': PSTable,
        'column': PSColumn,
        'option': PSVariable,
        'variable': PSVariable,
        'rn': PSReleaseNotes
    }
    roles = {
        'db': PSXRefRole(),
        'table': PSXRefRole(),
        'column': PSXRefRole(),
        'option': PSXRefRole(),
        'variable': PSXRefRole(),
        'rn': PSXRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
    }

    def clear_doc(self, docname):
        for fullname, (fn, _) in self.data['objects'].iteritems():
            if fn == docname:
                del self.data['objects'][fullname]

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        # strip pointer asterisk
        target = target.rstrip(' *')
        if target not in self.data['objects']:
            return None
        obj = self.data['objects'][target]
        return make_refnode(builder, fromdocname, obj[0], target, contnode,
                            target)

    def get_objects(self):
        for refname, (docname, type) in self.data['objects'].items():
            yield (refname, refname, type, docname, refname, 1)

    def find_obj(self, env, obj, name, typ, searchorder=0):
        if name[-2:] == '()':
            name = name[:-2]
        objects = self.data['objects']
        newname = None
        if searchorder == 1:
            if obj and obj + '.' + name in objects:
                newname = obj + '.' + name
            else:
                newname = name
        else:
            if name in objects:
                newname = name
            elif obj and obj + '.' + name in objects:
                newname = obj + '.' + name
        return newname, objects.get(newname)
Beispiel #18
0
class StandardDomain(Domain):
    """
    Domain for all objects that don't fit into another domain or are added
    via the application interface.
    """

    name = 'std'
    label = 'Default'

    object_types = {
        'term': ObjType(l_('glossary term'), 'term', searchprio=-1),
        'token': ObjType(l_('grammar token'), 'token', searchprio=-1),
        'label': ObjType(l_('reference label'),
                         'ref',
                         'keyword',
                         searchprio=-1),
        'envvar': ObjType(l_('environment variable'), 'envvar'),
        'cmdoption': ObjType(l_('program option'), 'option'),
    }

    directives = {
        'program': Program,
        'cmdoption': Cmdoption,  # old name for backwards compatibility
        'option': Cmdoption,
        'envvar': EnvVar,
        'glossary': Glossary,
        'productionlist': ProductionList,
    }
    roles = {
        'option':
        OptionXRefRole(innernodeclass=addnodes.literal_emphasis),
        'envvar':
        EnvVarXRefRole(),
        # links to tokens in grammar productions
        'token':
        XRefRole(),
        # links to terms in glossary
        'term':
        XRefRole(lowercase=True,
                 innernodeclass=nodes.emphasis,
                 warn_dangling=True),
        # links to headings or arbitrary labels
        'ref':
        XRefRole(lowercase=True,
                 innernodeclass=nodes.emphasis,
                 warn_dangling=True),
        # links to labels, without a different title
        'keyword':
        XRefRole(warn_dangling=True),
    }

    initial_data = {
        'progoptions': {},  # (program, name) -> docname, labelid
        'objects': {},      # (type, name) -> docname, labelid
        'labels': {         # labelname -> docname, labelid, sectionname
            'genindex': ('genindex', '', l_('Index')),
            'modindex': ('py-modindex', '', l_('Module Index')),
            'search':   ('search', '', l_('Search Page')),
        },
        'anonlabels': {     # labelname -> docname, labelid
            'genindex': ('genindex', ''),
            'modindex': ('py-modindex', ''),
            'search':   ('search', ''),
        },
    }

    dangling_warnings = {
        'term': 'term not in glossary: %(target)s',
        'ref': 'undefined label: %(target)s (if the link has no caption '
        'the label must precede a section header)',
        'keyword': 'unknown keyword: %(target)s',
    }

    def clear_doc(self, docname):
        for key, (fn, _) in self.data['progoptions'].items():
            if fn == docname:
                del self.data['progoptions'][key]
        for key, (fn, _) in self.data['objects'].items():
            if fn == docname:
                del self.data['objects'][key]
        for key, (fn, _, _) in self.data['labels'].items():
            if fn == docname:
                del self.data['labels'][key]
        for key, (fn, _) in self.data['anonlabels'].items():
            if fn == docname:
                del self.data['anonlabels'][key]

    def process_doc(self, env, docname, document):
        labels, anonlabels = self.data['labels'], self.data['anonlabels']
        for name, explicit in document.nametypes.iteritems():
            if not explicit:
                continue
            labelid = document.nameids[name]
            if labelid is None:
                continue
            node = document.ids[labelid]
            if name.isdigit() or node.has_key('refuri') or \
                   node.tagname.startswith('desc_'):
                # ignore footnote labels, labels automatically generated from a
                # link and object descriptions
                continue
            if name in labels:
                env.warn_node(
                    'duplicate label %s, ' % name + 'other instance '
                    'in ' + env.doc2path(labels[name][0]), node)
            anonlabels[name] = docname, labelid
            if node.tagname == 'section':
                sectname = clean_astext(node[0])  # node[0] == title node
            elif node.tagname == 'figure':
                for n in node:
                    if n.tagname == 'caption':
                        sectname = clean_astext(n)
                        break
                else:
                    continue
            elif node.tagname == 'table':
                for n in node:
                    if n.tagname == 'title':
                        sectname = clean_astext(n)
                        break
                else:
                    continue
            else:
                # anonymous-only labels
                continue
            labels[name] = docname, labelid, sectname

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        if typ == 'ref':
            if node['refexplicit']:
                # reference to anonymous label; the reference uses
                # the supplied link caption
                docname, labelid = self.data['anonlabels'].get(
                    target, ('', ''))
                sectname = node.astext()
            else:
                # reference to named label; the final node will
                # contain the section name after the label
                docname, labelid, sectname = self.data['labels'].get(
                    target, ('', '', ''))
            if not docname:
                return None
            newnode = nodes.reference('', '', internal=True)
            innernode = nodes.emphasis(sectname, sectname)
            if docname == fromdocname:
                newnode['refid'] = labelid
            else:
                # set more info in contnode; in case the
                # get_relative_uri call raises NoUri,
                # the builder will then have to resolve these
                contnode = addnodes.pending_xref('')
                contnode['refdocname'] = docname
                contnode['refsectname'] = sectname
                newnode['refuri'] = builder.get_relative_uri(
                    fromdocname, docname)
                if labelid:
                    newnode['refuri'] += '#' + labelid
            newnode.append(innernode)
            return newnode
        elif typ == 'keyword':
            # keywords are oddballs: they are referenced by named labels
            docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
            if not docname:
                return None
            return make_refnode(builder, fromdocname, docname, labelid,
                                contnode)
        elif typ == 'option':
            progname = node['refprogram']
            docname, labelid = self.data['progoptions'].get((progname, target),
                                                            ('', ''))
            if not docname:
                return None
            return make_refnode(builder, fromdocname, docname, labelid,
                                contnode)
        else:
            objtypes = self.objtypes_for_role(typ) or []
            for objtype in objtypes:
                if (objtype, target) in self.data['objects']:
                    docname, labelid = self.data['objects'][objtype, target]
                    break
            else:
                docname, labelid = '', ''
            if not docname:
                return None
            return make_refnode(builder, fromdocname, docname, labelid,
                                contnode)

    def get_objects(self):
        for (prog, option), info in self.data['progoptions'].iteritems():
            yield (option, option, 'option', info[0], info[1], 1)
        for (type, name), info in self.data['objects'].iteritems():
            yield (name, name, type, info[0], info[1],
                   self.object_types[type].attrs['searchprio'])
        for name, info in self.data['labels'].iteritems():
            yield (name, info[2], 'label', info[0], info[1], -1)

    def get_type_name(self, type, primary=False):
        # never prepend "Default"
        return type.lname
Beispiel #19
0
class CitationDomain(Domain):
    name = "cite"
    label = "citation"

    object_types = {
        'citation': ObjType(l_('citation'), *ROLES, searchprio=-1),
    }

    directives = {
        'conf': CitationConfDirective,
        'refs': CitationReferencesDirective
    }
    roles = dict([(r, CitationXRefRole()) for r in ROLES])

    initial_data = {
        'keys': OrderedSet(),  # Holds cite-keys in order of reference
        'conf': DEFAULT_CONF,
        'refdocs': {}
    }

    def __init__(self, env):
        super(CitationDomain, self).__init__(env)

        # Update conf
        env.domaindata['cite']['conf'].update(env.config.natbib)

        # TODO: warn if citations can't parse bibtex file
        self.citations = Citations(env)

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):

        refdoc = env.domaindata['cite'].get('refdoc')
        if not refdoc:
            env.warn(
                fromdocname,
                'no `refs` directive found; citations will have dead links',
                node.line)
            refuri = ''
        else:
            refuri = builder.get_relative_uri(fromdocname, refdoc)

        for nd in node.children:
            if isinstance(nd, nodes.pending):
                nd.details['refs'] = []

                if builder.name == 'latex':
                    cite_keys = nd.details['keys']
                    cite_keys = ','.join(cite_keys)
                    cite_node = nodes.citation_reference(cite_keys, cite_keys)
                    return cite_node

                for key in nd.details.pop('keys'):
                    ref = self.citations.get(key)
                    if ref is None:
                        continue
                    nd.details['refs'].append(ref)

                transform = nd.transform(**nd.details)
                node = transform.cite(
                    typ, refuri, global_keys=env.domaindata['cite']['keys'])

        return node
Beispiel #20
0
class CMakeDomain(Domain):
    """CMake domain."""
    name = 'cmake'
    label = 'CMake'
    object_types = {
        'command':    ObjType('command',    'command'),
        'generator':  ObjType('generator',  'generator'),
        'variable':   ObjType('variable',   'variable'),
        'module':     ObjType('module',     'module'),
        'policy':     ObjType('policy',     'policy'),
        'prop_cache': ObjType('prop_cache', 'prop_cache'),
        'prop_dir':   ObjType('prop_dir',   'prop_dir'),
        'prop_gbl':   ObjType('prop_gbl',   'prop_gbl'),
        'prop_inst':  ObjType('prop_inst',  'prop_inst'),
        'prop_sf':    ObjType('prop_sf',    'prop_sf'),
        'prop_test':  ObjType('prop_test',  'prop_test'),
        'prop_tgt':   ObjType('prop_tgt',   'prop_tgt'),
        'manual':     ObjType('manual',     'manual'),
    }
    directives = {
        'command':    CMakeObject,
        'variable':   CMakeObject,
        # Other object types cannot be created except by the CMakeTransform
        # 'generator':  CMakeObject,
        # 'module':     CMakeObject,
        # 'policy':     CMakeObject,
        # 'prop_cache': CMakeObject,
        # 'prop_dir':   CMakeObject,
        # 'prop_gbl':   CMakeObject,
        # 'prop_inst':  CMakeObject,
        # 'prop_sf':    CMakeObject,
        # 'prop_test':  CMakeObject,
        # 'prop_tgt':   CMakeObject,
        # 'manual':     CMakeObject,
    }
    roles = {
        'command':    CMakeXRefRole(fix_parens=True, lowercase=True),
        'generator':  CMakeXRefRole(),
        'variable':   CMakeXRefRole(),
        'module':     CMakeXRefRole(),
        'policy':     CMakeXRefRole(),
        'prop_cache': CMakeXRefRole(),
        'prop_dir':   CMakeXRefRole(),
        'prop_gbl':   CMakeXRefRole(),
        'prop_inst':  CMakeXRefRole(),
        'prop_sf':    CMakeXRefRole(),
        'prop_test':  CMakeXRefRole(),
        'prop_tgt':   CMakeXRefRole(),
        'manual':     CMakeXRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
    }

    def clear_doc(self, docname):
        to_clear = set()
        for fullname, (fn, _) in self.data['objects'].items():
            if fn == docname:
                to_clear.add(fullname)
        for fullname in to_clear:
            del self.data['objects'][fullname]

    def resolve_xref(self, env, fromdocname, builder,
                     typ, target, node, contnode):
        targetid = '%s:%s' % (typ, target)
        obj = self.data['objects'].get(targetid)
        if obj is None:
            # TODO: warn somehow?
            return None
        return make_refnode(builder, fromdocname, obj[0], targetid,
                            contnode, target)

    def get_objects(self):
        for refname, (docname, type) in self.data['objects'].items():
            yield (refname, refname, type, docname, refname, 1)
Beispiel #21
0
class BBDomain(Domain):
    name = 'bb'
    label = 'Buildbot'

    object_types = {
        'cfg': ObjType('cfg', 'cfg'),
        'sched': ObjType('sched', 'sched'),
        'chsrc': ObjType('chsrc', 'chsrc'),
        'step': ObjType('step', 'step'),
        'status': ObjType('status', 'status'),
        'cmdline': ObjType('cmdline', 'cmdline'),
    }

    directives = {
        'cfg': make_ref_target_directive('cfg',
                                         indextemplates=[
                                             'single: Buildmaster Config; %s',
                                             'single: %s (Buildmaster Config)',
                                         ]),
        'sched': make_ref_target_directive('sched',
                                           indextemplates=[
                                               'single: Schedulers; %s',
                                               'single: %s Scheduler',
                                           ]),
        'chsrc': make_ref_target_directive('chsrc',
                                           indextemplates=[
                                               'single: Change Sources; %s',
                                               'single: %s Change Source',
                                           ]),
        'step': make_ref_target_directive('step',
                                          indextemplates=[
                                              'single: Build Steps; %s',
                                              'single: %s Build Step',
                                          ]),
        'status': make_ref_target_directive('status',
                                            indextemplates=[
                                                'single: Status Targets; %s',
                                                'single: %s Status Target',
                                            ]),
        'cmdline': make_ref_target_directive('cmdline',
                                             indextemplates=[
                                                 'single: Command Line Subcommands; %s',
                                                 'single: %s Command Line Subcommand',
                                             ]),
    }

    roles = {
        'cfg': XRefRole(),
        'sched': XRefRole(),
        'chsrc': XRefRole(),
        'step': XRefRole(),
        'status': XRefRole(),
        'cmdline': XRefRole(),

        'index': XRefRole(),

        'bug': BugRole(),
        'src': SrcRole(),
        'pull': PullRole(),
    }

    initial_data = {
        'targets': {},  # type -> target -> (docname, targetname)
    }

    indices = [
        make_index("cfg", "Buildmaster Configuration Index"),
        make_index("sched", "Scheduler Index"),
        make_index("chsrc", "Change Source Index"),
        make_index("step", "Build Step Index"),
        make_index("status", "Status Target Index"),
        make_index("cmdline", "Command Line Index"),
    ]

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        if typ == 'index':
            for idx in self.indices:
                if idx.name == target:
                    break
            else:
                raise KeyError("no index named '%s'" % target)
            return idx.resolve_ref(self, env, fromdocname, builder, typ,
                                   target, node, contnode)
        elif typ in self.directives:
            dir = self.directives[typ]
            return dir.resolve_ref(self, env, fromdocname, builder, typ,
                                   target, node, contnode)
Beispiel #22
0
class PhpDomain(Domain):
    """PHP language domain."""
    name = 'php'
    label = 'PHP'
    object_types = {
        'function': ObjType(l_('function'), 'func', 'obj'),
        'global': ObjType(l_('global variable'), 'global', 'obj'),
        'const': ObjType(l_('const'), 'const', 'obj'),
        'method': ObjType(l_('method'), 'meth', 'obj'),
        'class': ObjType(l_('class'), 'class', 'obj'),
        'attr': ObjType(l_('attribute'), 'attr', 'obj'),
        'exception': ObjType(l_('exception'), 'exc', 'obj'),
        'namespace': ObjType(l_('namespace'), 'ns', 'obj'),
        'interface': ObjType(l_('interface'), 'interface', 'obj'),
        'trait': ObjType(l_('trait'), 'trait', 'obj'),
    }

    directives = {
        'function': PhpNamespacelevel,
        'global': PhpGloballevel,
        'const': PhpNamespacelevel,
        'class': PhpClasslike,
        'method': PhpClassmember,
        'staticmethod': PhpClassmember,
        'attr': PhpClassmember,
        'exception': PhpClasslike,
        'interface': PhpClasslike,
        'trait': PhpClasslike,
        'namespace': PhpNamespace,
    }

    roles = {
        'func': PhpXRefRole(fix_parens=False),
        'global': PhpXRefRole(),
        'class': PhpXRefRole(),
        'exc': PhpXRefRole(),
        'meth': PhpXRefRole(fix_parens=False),
        'attr': PhpXRefRole(),
        'const': PhpXRefRole(),
        'ns': PhpXRefRole(),
        'obj': PhpXRefRole(),
        'interface': PhpXRefRole(),
        'trait': PhpXRefRole(),
    }

    initial_data = {
        'objects': {},  # fullname -> docname, objtype
        'namespaces': {},  # namespace -> docname, synopsis
    }
    indices = [
        PhpNamespaceIndex,
    ]

    def clear_doc(self, docname):
        for fullname, (fn, _) in self.data['objects'].items():
            if fn == docname:
                del self.data['objects'][fullname]
        for ns, (fn, _, _) in self.data['namespaces'].items():
            if fn == docname:
                del self.data['namespaces'][ns]

    def resolve_xref(self, env, fromdocname, builder,
                     typ, target, node, contnode):
        if (typ == 'ns' or
            typ == 'obj' and target in self.data['namespaces']):
            docname, synopsis, deprecated = \
                self.data['namespaces'].get(target, ('','','', ''))
            if not docname:
                return None
            else:
                title = '%s%s' % (synopsis,
                                    (deprecated and ' (deprecated)' or ''))
                return make_refnode(builder, fromdocname, docname,
                                    'namespace-' + target, contnode, title)
        else:
            modname = node.get('php:namespace')
            clsname = node.get('php:class')
            searchorder = node.hasattr('refspecific') and 1 or 0
            name, obj = self.find_obj(env, modname, clsname,
                                      target, typ, searchorder)
            if not obj:
                return None
            else:
                return make_refnode(builder, fromdocname, obj[0], name,
                                    contnode, name)

    def find_obj(self, env, modname, classname, name, type, searchorder=0):
        """
        Find a PHP object for "name", perhaps using the given namespace and/or
        classname.
        """
        # skip parens
        if name[-2:] == '()':
            name = name[:-2]

        if not name:
            return None, None

        objects = self.data['objects']

        newname = None
        if searchorder == 1:
            if modname and classname and \
                     modname + NS + classname + '::' + name in objects:
                newname = modname + NS + classname + '::' + name
            elif modname and modname + NS + name in objects:
                newname = modname + NS + name
            elif modname and modname + NS + name in objects:
                newname = modname + NS + name
            elif classname and classname + '::' + name in objects:
                newname = classname + '.' + name
            elif classname and classname + '::$' + name in objects:
                newname = classname + '::$' + name
            elif name in objects:
                newname = name
        else:
            if name in objects:
                newname = name
            elif classname and classname + '::' + name in objects:
                newname = classname + '::' + name
            elif classname and classname + '::$' + name in objects:
                newname = classname + '::$' + name
            elif modname and modname + NS + name in objects:
                newname = modname + NS + name
            elif modname and classname and \
                     modname + NS + classname + '::' + name in objects:
                newname = modname + NS + classname + '::' + name
            elif modname and classname and \
                     modname + NS + classname + '::$' + name in objects:
                newname = modname + NS + classname + '::$' + name
            # special case: object methods
            elif type in ('func', 'meth') and '::' not in name and \
                 'object::' + name in objects:
                newname = 'object::' + name
        if newname is None:
            return None, None
        return newname, objects[newname]

    def get_objects(self):
        for ns, info in self.data['namespaces'].iteritems():
            yield (ns, ns, 'namespace', info[0], 'namespace-' + ns, 0)
        for refname, (docname, type) in self.data['objects'].iteritems():
            yield (refname, refname, type, docname, refname, 1)
Beispiel #23
0
class AdaDomain(Domain):
    """Ada language domain."""
    name = 'ada'
    label = 'Ada'
    object_types = {
        'function': ObjType(l_('function'), 'func'),
        'procedure': ObjType(l_('procedure'), 'proc'),
        'type': ObjType(l_('type'), 'type'),
        'module': ObjType(l_('module'), 'mod'),
    }

    directives = {
        'function': AdaObject,
        'procedure': AdaObject,
        'type': AdaObject,
        'module': AdaModule,
        'currentmodule': AdaCurrentModule,
    }
    roles = {
        'func': AdaXRefRole(),
        'proc': AdaXRefRole(),
        'type': AdaXRefRole(),
        'mod': AdaXRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
        'functions': {},  # fullname -> arity -> (targetname, docname)
        'procedures': {},  # fullname -> arity -> (targetname, docname)
        'modules': {},  # modname -> docname, synopsis, platform, deprecated
    }
    indices = [
        AdaModuleIndex,
    ]

    def clear_doc(self, docname):
        # Python 3's "items" is a view, not a copy, and modifying the dict
        # while iterating over the view is unsafe, so enforce copying by making
        # lists from the views.
        for fullname, (fn, _) in list(self.data['objects'].items()):
            if fn == docname:
                del self.data['objects'][fullname]
        for modname, (fn, _, _, _) in list(self.data['modules'].items()):
            if fn == docname:
                del self.data['modules'][modname]
        for fullname, funcs in list(self.data['functions'].items()):
            for arity, (fn, _) in list(funcs.items()):
                if fn == docname:
                    del self.data['functions'][fullname][arity]
            if not self.data['functions'][fullname]:
                del self.data['functions'][fullname]
        for fullname, funcs in list(self.data['procedures'].items()):
            for arity, (fn, _) in list(funcs.items()):
                if fn == docname:
                    del self.data['procedures'][fullname][arity]
            if not self.data['procedures'][fullname]:
                del self.data['procedures'][fullname]

    def _find_obj(self, env, modname, name, objtype, searchorder=0):
        """
        Find a Ada object for "name", perhaps using the given module and/or
        classname.
        """
        if not name:
            return None, None
        if ":" not in name:
            name = "%s:%s" % (modname, name)

        if name in self.data['objects']:
            return name, self.data['objects'][name][0]

        if '/' in name:
            fname, arity = name.split('/')
            arity = int(arity)
        else:
            fname = name
            arity = -1
        if fname in self.data['functions']:
            arities = self.data['functions'][fname]
        elif fname in self.data['procedures']:
            arities = self.data['procedures'][fname]
        else:
            return None, None

        if arity == -1:
            arity = min(arities)
        if arity in arities:
            docname, targetname = arities[arity]
            return targetname, docname
        return None, None

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        if typ == 'mod' and target in self.data['modules']:
            docname, synopsis, platform, deprecated = \
                self.data['modules'].get(target, ('','','', ''))
            if not docname:
                return None
            else:
                title = '%s%s%s' % (
                    (platform and '(%s) ' % platform), synopsis,
                    (deprecated and ' (deprecated)' or ''))
                return make_refnode(builder, fromdocname, docname,
                                    'module-' + target, contnode, title)
        else:
            modname = node.get('ada:module')
            searchorder = node.hasattr('refspecific') and 1 or 0
            name, obj = self._find_obj(env, modname, target, typ, searchorder)
            if not obj:
                return None
            else:
                return make_refnode(builder, fromdocname, obj, name, contnode,
                                    name)

    def get_objects(self):
        # Python 3 has no iteritems, so use items.
        for refname, (docname, type) in self.data['objects'].items():
            yield (refname, refname, type, docname, refname, 1)
Beispiel #24
0
class JavaScriptDomain(Domain):
    """JavaScript language domain."""
    name = 'js'
    label = 'JavaScript'
    # if you add a new object type make sure to edit JSObject.get_index_string
    object_types = {
        'function': ObjType(l_('function'), 'func'),
        'class': ObjType(l_('class'), 'class'),
        'data': ObjType(l_('data'), 'data'),
        'attribute': ObjType(l_('attribute'), 'attr'),
    }
    directives = {
        'function': JSCallable,
        'class': JSConstructor,
        'data': JSObject,
        'attribute': JSObject,
    }
    roles = {
        'func': JSXRefRole(fix_parens=True),
        'class': JSXRefRole(fix_parens=True),
        'data': JSXRefRole(),
        'attr': JSXRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
    }

    def clear_doc(self, docname):
        for fullname, (fn, _l) in list(self.data['objects'].items()):
            if fn == docname:
                del self.data['objects'][fullname]

    def merge_domaindata(self, docnames, otherdata):
        # XXX check duplicates
        for fullname, (fn, objtype) in otherdata['objects'].items():
            if fn in docnames:
                self.data['objects'][fullname] = (fn, objtype)

    def find_obj(self, env, obj, name, typ, searchorder=0):
        if name[-2:] == '()':
            name = name[:-2]
        objects = self.data['objects']
        newname = None
        if searchorder == 1:
            if obj and obj + '.' + name in objects:
                newname = obj + '.' + name
            else:
                newname = name
        else:
            if name in objects:
                newname = name
            elif obj and obj + '.' + name in objects:
                newname = obj + '.' + name
        return newname, objects.get(newname)

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        objectname = node.get('js:object')
        searchorder = node.hasattr('refspecific') and 1 or 0
        name, obj = self.find_obj(env, objectname, target, typ, searchorder)
        if not obj:
            return None
        return make_refnode(builder, fromdocname, obj[0],
                            name.replace('$', '_S_'), contnode, name)

    def resolve_any_xref(self, env, fromdocname, builder, target, node,
                         contnode):
        objectname = node.get('js:object')
        name, obj = self.find_obj(env, objectname, target, None, 1)
        if not obj:
            return []
        return [('js:' + self.role_for_objtype(obj[1]),
                 make_refnode(builder, fromdocname, obj[0],
                              name.replace('$', '_S_'), contnode, name))]

    def get_objects(self):
        for refname, (docname, type) in list(self.data['objects'].items()):
            yield refname, refname, type, docname, \
                refname.replace('$', '_S_'), 1
Beispiel #25
0
class CoqDomain(Domain):
    """A domain to document Coq code.

    Sphinx has a notion of “domains”, used to tailor it to a specific language.
    Domains mostly consist in descriptions of the objects that we wish to
    describe (for Coq, this includes tactics, tactic notations, options,
    exceptions, etc.), as well as domain-specific roles and directives.

    Each domain is responsible for tracking its objects, and resolving
    references to them. In the case of Coq, this leads us to define Coq
    “subdomains”, which classify objects into categories in which names must be
    unique. For example, a tactic and a theorem may share a name, but two
    tactics cannot be named the same.
    """

    name = 'coq'
    label = 'Coq'

    object_types = {
        # ObjType (= directive type) → (Local name, *xref-roles)
        'cmd': ObjType('cmd', 'cmd'),
        'cmdv': ObjType('cmdv', 'cmd'),
        'tacn': ObjType('tacn', 'tacn'),
        'tacv': ObjType('tacv', 'tacn'),
        'opt': ObjType('opt', 'opt'),
        'thm': ObjType('thm', 'thm'),
        'prodn': ObjType('prodn', 'prodn'),
        'exn': ObjType('exn', 'exn'),
        'warn': ObjType('warn', 'exn'),
        'index': ObjType('index', 'index', searchprio=-1)
    }

    directives = {
        # Note that some directives live in the same semantic subdomain; ie
        # there's one directive per object type, but some object types map to
        # the same role.
        'cmd': VernacObject,
        'cmdv': VernacVariantObject,
        'tacn': TacticNotationObject,
        'tacv': TacticNotationVariantObject,
        'opt': OptionObject,
        'thm': GallinaObject,
        'prodn': ProductionObject,
        'exn': ExceptionObject,
        'warn': WarningObject,
    }

    roles = {
        # Each of these roles lives in a different semantic “subdomain”
        'cmd': XRefRole(warn_dangling=True),
        'tacn': XRefRole(warn_dangling=True),
        'opt': XRefRole(warn_dangling=True),
        'thm': XRefRole(warn_dangling=True),
        'prodn': XRefRole(warn_dangling=True),
        'exn': XRefRole(warn_dangling=True),
        'warn': XRefRole(warn_dangling=True),
        # This one is special
        'index': IndexXRefRole(),
        # These are used for highlighting
        'n': NotationRole,
        'g': CoqCodeRole
    }

    indices = [
        CoqVernacIndex, CoqTacticIndex, CoqOptionIndex, CoqGallinaIndex,
        CoqProductionIndex, CoqExceptionIndex
    ]

    data_version = 1
    initial_data = {
        # Collect everything under a key that we control, since Sphinx adds
        # others, such as “version”
        'objects' : { # subdomain → name → docname, objtype, targetid
            'cmd': {},
            'tacn': {},
            'opt': {},
            'thm': {},
            'prodn' : {},
            'exn': {},
            'warn': {},
        }
    }

    @staticmethod
    def find_index_by_name(targetid):
        for index in CoqDomain.indices:
            if index.name == targetid:
                return index

    def get_objects(self):
        # Used for searching and object inventories (intersphinx)
        for _, objects in self.data['objects'].items():
            for name, (docname, objtype, targetid) in objects.items():
                yield (name, name, objtype, docname, targetid,
                       self.object_types[objtype].attrs['searchprio'])
        for index in self.indices:
            yield (index.name, index.localname, 'index', "coq-" + index.name,
                   '', -1)

    def merge_domaindata(self, docnames, otherdata):
        DUP = "Duplicate declaration: '{}' also defined in '{}'.\n"
        for subdomain, their_objects in otherdata['objects'].items():
            our_objects = self.data['objects'][subdomain]
            for name, (docname, objtype, targetid) in their_objects.items():
                if docname in docnames:
                    if name in our_objects:
                        self.env.warn(docname,
                                      DUP.format(name, our_objects[name][0]))
                    our_objects[name] = (docname, objtype, targetid)

    def resolve_xref(self, env, fromdocname, builder, role, targetname, node,
                     contnode):
        # ‘target’ is the name that was written in the document
        # ‘role’ is where this xref comes from; it's exactly one of our subdomains
        if role == 'index':
            index = CoqDomain.find_index_by_name(targetname)
            if index:
                return make_refnode(builder, fromdocname, "coq-" + index.name,
                                    '', contnode, index.localname)
        else:
            resolved = self.data['objects'][role].get(targetname)
            if resolved:
                (todocname, _, targetid) = resolved
                return make_refnode(builder, fromdocname, todocname, targetid,
                                    contnode, targetname)

    def clear_doc(self, docname_to_clear):
        for subdomain_objects in self.data['objects'].values():
            for name, (docname, _, _) in list(subdomain_objects.items()):
                if docname == docname_to_clear:
                    del subdomain_objects[name]
Beispiel #26
0
class JavaScriptDomain(Domain):
    """JavaScript language domain."""
    name = 'js'
    label = 'JavaScript'
    # if you add a new object type make sure to edit JSObject.get_index_string
    object_types = {
        'function': ObjType(l_('function'), 'func'),
        'method': ObjType(l_('method'), 'meth'),
        'class': ObjType(l_('class'), 'class'),
        'data': ObjType(l_('data'), 'data'),
        'attribute': ObjType(l_('attribute'), 'attr'),
        'module': ObjType(l_('module'), 'mod'),
    }
    directives = {
        'function': JSCallable,
        'method': JSCallable,
        'class': JSConstructor,
        'data': JSObject,
        'attribute': JSObject,
        'module': JSModule,
    }
    roles = {
        'func': JSXRefRole(fix_parens=True),
        'meth': JSXRefRole(fix_parens=True),
        'class': JSXRefRole(fix_parens=True),
        'data': JSXRefRole(),
        'attr': JSXRefRole(),
        'mod': JSXRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
        'modules': {},  # mod_name -> docname
    }  # type: Dict[unicode, Dict[unicode, Tuple[unicode, unicode]]]

    def clear_doc(self, docname):
        # type: (unicode) -> None
        for fullname, (pkg_docname, _l) in list(self.data['objects'].items()):
            if pkg_docname == docname:
                del self.data['objects'][fullname]
        for mod_name, pkg_docname in list(self.data['modules'].items()):
            if pkg_docname == docname:
                del self.data['modules'][mod_name]

    def merge_domaindata(self, docnames, otherdata):
        # type: (List[unicode], Dict) -> None
        # XXX check duplicates
        for fullname, (fn, objtype) in otherdata['objects'].items():
            if fn in docnames:
                self.data['objects'][fullname] = (fn, objtype)
        for mod_name, pkg_docname in otherdata['modules'].items():
            if pkg_docname in docnames:
                self.data['modules'][mod_name] = pkg_docname

    def find_obj(self, env, mod_name, prefix, name, typ, searchorder=0):
        # type: (BuildEnvironment, unicode, unicode, unicode, unicode, int) -> Tuple[unicode, Tuple[unicode, unicode]]  # NOQA
        if name[-2:] == '()':
            name = name[:-2]
        objects = self.data['objects']

        searches = []
        if mod_name and prefix:
            searches.append('.'.join([mod_name, prefix, name]))
        if mod_name:
            searches.append('.'.join([mod_name, name]))
        if prefix:
            searches.append('.'.join([prefix, name]))
        searches.append(name)

        if searchorder == 0:
            searches.reverse()

        newname = None
        for search_name in searches:
            if search_name in objects:
                newname = search_name

        return newname, objects.get(newname)

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        mod_name = node.get('js:module')
        prefix = node.get('js:object')
        searchorder = node.hasattr('refspecific') and 1 or 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],
                            name.replace('$', '_S_'), contnode, name)

    def resolve_any_xref(self, env, fromdocname, builder, target, node,
                         contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[Tuple[unicode, nodes.Node]]  # NOQA
        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[1]),
                 make_refnode(builder, fromdocname, obj[0],
                              name.replace('$', '_S_'), contnode, name))]

    def get_objects(self):
        # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]]
        for refname, (docname, type) in list(self.data['objects'].items()):
            yield refname, refname, type, docname, \
                refname.replace('$', '_S_'), 1

    def get_full_qualified_name(self, node):
        # type: (nodes.Node) -> unicode
        modname = node.get('js:module')
        prefix = node.get('js:object')
        target = node.get('reftarget')
        if target is None:
            return None
        else:
            return '.'.join(filter(None, [modname, prefix, target]))
Beispiel #27
0
class CondaDomain(Domain):
    """Domain for Conda Packages"""
    name = "conda"
    label = "Conda"

    object_types = {
        # ObjType(name, *roles, **attrs)
        'recipe': ObjType('recipe', 'recipe'),
        'package': ObjType('package', 'package', 'depends'),
    }
    directives = {
        'recipe': CondaRecipe,
        'package': CondaPackage,
    }
    roles = {
        'recipe': XRefRole(),
        'package': XRefRole(),
    }
    initial_data = {
        'objects': {},  #: (type, name) -> docname, labelid
        'backrefs': {}  #: package_name -> docname, package_name
    }
    indices = [PackageIndex]

    def clear_doc(self, docname: str):
        """Remove traces of a document in the domain-specific inventories."""
        if 'objects' not in self.data:
            return
        to_remove = [
            key for (key, (stored_docname, _)) in self.data['objects'].items()
            if docname == stored_docname
        ]
        for key in to_remove:
            del self.data['objects'][key]

    def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str,
                         builder, target, node, contnode):
        """Resolve references from "any" role."""
        res = self.resolve_xref(env, fromdocname, builder, 'package', target,
                                node, contnode)
        if res:
            return [('conda:package', res)]
        else:
            return []

    def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder,
                     role, target, node, contnode):
        """Resolve the ``pending_xref`` **node** with the given **role** and **target**."""
        for objtype in self.objtypes_for_role(role) or []:
            if (objtype, target) in self.data['objects']:
                node = make_refnode(builder, fromdocname,
                                    self.data['objects'][objtype, target][0],
                                    self.data['objects'][objtype, target][1],
                                    contnode, target + ' ' + objtype)
                node.set_class('conda-package')
                return node

            if objtype == "package":
                for channel, urlformat in env.app.config.bioconda_other_channels.items(
                ):
                    if RepoData().get_package_data(channels=channel,
                                                   name=target):
                        uri = urlformat.format(target)
                        node = nodes.reference('',
                                               '',
                                               internal=False,
                                               refuri=uri,
                                               classes=[channel])
                        node += contnode
                        return node

        return None  # triggers missing-reference

    def get_objects(self):
        """Yields "object description" 5-tuples

        ``name``:     fully qualified name
        ``dispname``: name to display when searching/linking
        ``type``:     object type, a key in ``self.object_types``
        ``docname``:  the document where it is to be found
        ``anchor``:   the anchor name for the object
        ``priority``: search priority

          - 1: default priority (placed before full-text matches)
          - 0: object is important (placed before default-priority objects)
          - 2: object is unimportant (placed after full-text matches)
          - -1: object should not show up in search at all
        """
        for (typ, name), (docname, ref) in self.data['objects'].items():
            dispname = "Recipe '{}'".format(name)
            yield name, dispname, typ, docname, ref, 1

    def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
        """Merge in data regarding *docnames* from a different domaindata
        inventory (coming from a subprocess in parallel builds).
        """
        for (typ, name), (docname, ref) in otherdata['objects'].items():
            if docname in docnames:
                self.data['objects'][typ, name] = (docname, ref)
Beispiel #28
0
class CDomain(Domain):
    """C language domain."""
    name = 'c'
    label = 'C'
    object_types = {
        'function': ObjType(_('function'), 'func'),
        'member':   ObjType(_('member'),   'member'),
        'macro':    ObjType(_('macro'),    'macro'),
        'type':     ObjType(_('type'),     'type'),
        'var':      ObjType(_('variable'), 'data'),
    }

    directives = {
        'function': CObject,
        'member':   CObject,
        'macro':    CObject,
        'type':     CObject,
        'var':      CObject,
    }
    roles = {
        'func':   CXRefRole(fix_parens=True),
        'member': CXRefRole(),
        'macro':  CXRefRole(),
        'data':   CXRefRole(),
        'type':   CXRefRole(),
    }
    initial_data = {
        'objects': {},  # fullname -> docname, objtype
    }  # type: Dict[unicode, Dict[unicode, Tuple[unicode, Any]]]

    def clear_doc(self, docname):
        # type: (unicode) -> None
        for fullname, (fn, _l) in list(self.data['objects'].items()):
            if fn == docname:
                del self.data['objects'][fullname]

    def merge_domaindata(self, docnames, otherdata):
        # type: (List[unicode], Dict) -> None
        # XXX check duplicates
        for fullname, (fn, objtype) in otherdata['objects'].items():
            if fn in docnames:
                self.data['objects'][fullname] = (fn, objtype)

    def resolve_xref(self, env, fromdocname, builder,
                     typ, target, node, contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA
        # strip pointer asterisk
        target = target.rstrip(' *')
        # becase TypedField can generate xrefs
        if target in CObject.stopwords:
            return contnode
        if target not in self.data['objects']:
            return None
        obj = self.data['objects'][target]
        return make_refnode(builder, fromdocname, obj[0], 'c.' + target,
                            contnode, target)

    def resolve_any_xref(self, env, fromdocname, builder, target,
                         node, contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[Tuple[unicode, nodes.Node]]  # NOQA
        # strip pointer asterisk
        target = target.rstrip(' *')
        if target not in self.data['objects']:
            return []
        obj = self.data['objects'][target]
        return [('c:' + self.role_for_objtype(obj[1]),
                 make_refnode(builder, fromdocname, obj[0], 'c.' + target,
                              contnode, target))]

    def get_objects(self):
        # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]]
        for refname, (docname, type) in list(self.data['objects'].items()):
            yield (refname, refname, type, docname, 'c.' + refname, 1)
Beispiel #29
0
class DBusDomain(Domain):
    """
    Implementation of the D-Bus domain.
    """

    name = "dbus"
    label = "D-Bus"
    object_types: Dict[str, ObjType] = {
        "interface": ObjType(_("interface"), "iface", "obj"),
        "method": ObjType(_("method"), "meth", "obj"),
        "signal": ObjType(_("signal"), "sig", "obj"),
        "property": ObjType(_("property"), "attr", "_prop", "obj"),
    }
    directives = {
        "interface": DBusInterface,
        "method": DBusMethod,
        "signal": DBusSignal,
        "property": DBusProperty,
    }
    roles = {
        "iface": DBusXRef(),
        "meth": DBusXRef(),
        "sig": DBusXRef(),
        "prop": DBusXRef(),
    }
    initial_data: Dict[str, Dict[str, Tuple[Any]]] = {
        "objects": {},  # fullname -> ObjectEntry
    }
    indices = [
        DBusIndex,
    ]

    @property
    def objects(self) -> Dict[str, ObjectEntry]:
        return self.data.setdefault("objects", {})  # fullname -> ObjectEntry

    def note_object(
        self, name: str, objtype: str, node_id: str, location: Any = None
    ) -> None:
        self.objects[name] = ObjectEntry(self.env.docname, node_id, objtype)

    def clear_doc(self, docname: str) -> None:
        for fullname, obj in list(self.objects.items()):
            if obj.docname == docname:
                del self.objects[fullname]

    def find_obj(self, typ: str, name: str) -> Optional[Tuple[str, ObjectEntry]]:
        # skip parens
        if name[-2:] == "()":
            name = name[:-2]
        if typ in ("meth", "sig", "prop"):
            try:
                ifacename, name = name.rsplit(".", 1)
            except ValueError:
                pass
        return self.objects.get(name)

    def resolve_xref(
        self,
        env: "BuildEnvironment",
        fromdocname: str,
        builder: "Builder",
        typ: str,
        target: str,
        node: pending_xref,
        contnode: Element,
    ) -> Optional[Element]:
        """Resolve the pending_xref *node* with the given *typ* and *target*."""
        objdef = self.find_obj(typ, target)
        if objdef:
            return node_utils.make_refnode(
                builder, fromdocname, objdef.docname, objdef.node_id, contnode
            )

    def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
        for refname, obj in self.objects.items():
            yield (refname, refname, obj.objtype, obj.docname, obj.node_id, 1)
Beispiel #30
0
class ComObjectDomain(Domain):
    name = 'com-object'
    label = 'ComObject'
    object_types = {
        'method': ObjType(_('method'), 'meth'),
    }

    directives = {'method': ComObjectClassmember}
    roles = {
        'meth': ComObjectXRefRole(fix_parens=True),
    }
    initial_data = {'objects': {}}
    indices = [
        ComObjectIndex,
    ]

    def clear_doc(self, docname):
        for fullname, (fn, _l) in list(self.data['objects'].items()):
            if fn == docname:
                del self.data['objects'][fullname]

    def find_obj(self, name, type, searchmode=0):
        if name[-2:] == '()':
            name = name[:-2]

        if not name:
            return []

        objects = self.data['objects']
        matches = []

        if searchmode == 1:
            objtypes = list(self.object_types
                            ) if type is None else self.objtypes_for_role(type)
            if objtypes is not None:
                searchname = '.' + name
                matches = [(oname, objects[oname]) for oname in objects
                           if oname.endswith(searchname)
                           and objects[oname][1] in objtypes]
        else:
            if name in objects:
                matches.append((name, objects[name]))
        return matches

    def resolve_xref(self, env, fromdocname, builder, type, target, node,
                     contnode):
        searchmode = node.hasattr('refspecific') and 1 or 0
        matches = self.find_obj(target, type, searchmode)
        if not matches:
            return None
        elif len(matches) > 1:
            match_list = ', '.join(match[0] for match in matches)
            warning = 'more than one target found for cross-reference {}: {}'.format(
                target.repr(), match_list)
            logger.warning(__(warning),
                           type='ref',
                           subtype='com-object',
                           location=node)
        name, obj = matches[0]

        return make_refnode(builder, fromdocname, obj[0], name, contnode, name)

    def get_objects(self):
        for refname, (docname, type) in iteritems(self.data['objects']):
            yield (refname, refname, type, docname, refname, 1)

    def get_full_qualified_name(self, node):
        target = node.get('reftarget')
        return None if target is None else '.'.join(
            filter(None, [None, target]))