예제 #1
0
    def __call__(self, *args, **kwargs):
        nodes, messages = XRefRole.__call__(self, *args, **kwargs)
        for node in nodes:
            attrs = node.attributes
            target = attrs['reftarget']
            parens = ''
            if target.endswith('()'):
                # Function call, :symbol:`mongoc_init()`
                target = target[:-2]
                parens = '()'

            if ':' in target:
                # E.g., 'bson:bson_t' has domain 'bson', target 'bson_t'
                attrs['domain'], name = target.split(':', 1)
                attrs['reftarget'] = name

                old = node.children[0].children[0]
                assert isinstance(old, Text)
                new = Text(name + parens, name + parens)
                # Ensure setup_child is called.
                node.children[0].replace(old, new)

            else:
                attrs['reftarget'] = target

            attrs['reftype'] = 'doc'
            attrs['classes'].append('symbol')

            if sphinx_version_info >= (1, 6):
                # https://github.com/sphinx-doc/sphinx/issues/3698
                attrs['refdomain'] = 'std'

        return nodes, messages
예제 #2
0
    def __call__(self, *args, **kwargs):
        nodes, messages = XRefRole.__call__(self, *args, **kwargs)
        for node in nodes:
            attrs = node.attributes
            target = attrs['reftarget']
            parens = ''
            if target.endswith('()'):
                # Function call, :symbol:`mongoc_init()`
                target = target[:-2]
                parens = '()'

            if ':' in target:
                # E.g., 'bson:bson_t' has domain 'bson', target 'bson_t'
                attrs['domain'], name = target.split(':', 1)
                attrs['reftarget'] = name

                assert isinstance(node.children[0].children[0], Text)
                node.children[0].children[0] = Text(name + parens,
                                                    name + parens)

            else:
                attrs['reftarget'] = target

            attrs['reftype'] = 'doc'
            attrs['classes'].append('symbol')
        return nodes, messages
예제 #3
0
    def __call__(self, typ, rawtext, text, lineno, inliner,
                 options={}, content=[]):

        typ = 'std:ref'
        self._reporter = inliner.document.reporter
        self._lineno = lineno
        return XRefRole.__call__(self, typ, rawtext, text, lineno,
                                 inliner, options, content)
예제 #4
0
 def __call__(self, typ, rawtext, text, *args, **keys):
     # CMake cross-reference targets may contain '<' so escape
     # any explicit `<target>` with '<' not preceded by whitespace.
     while True:
         m = ECMXRefRole._re.match(text)
         if m and len(m.group(2)) == 0:
             text = '%s\x00<%s>' % (m.group(1), m.group(3))
         else:
             break
     return XRefRole.__call__(self, typ, rawtext, text, *args, **keys)
예제 #5
0
파일: cmake.py 프로젝트: dbcfd/CMake
 def __call__(self, typ, rawtext, text, *args, **keys):
     # Translate CMake command cross-references of the form:
     #  `command_name(SUB_COMMAND)`
     # to have an explicit target:
     #  `command_name(SUB_COMMAND) <command_name>`
     if typ == 'cmake:command':
         m = CMakeXRefRole._re_sub.match(text)
         if m:
             text = '%s <%s>' % (text, m.group(1))
     # CMake cross-reference targets frequently contain '<' so escape
     # any explicit `<target>` with '<' not preceded by whitespace.
     while True:
         m = CMakeXRefRole._re.match(text)
         if m and len(m.group(2)) == 0:
             text = '%s\x00<%s>' % (m.group(1), m.group(3))
         else:
             break
     return XRefRole.__call__(self, typ, rawtext, text, *args, **keys)
예제 #6
0
파일: coqdomain.py 프로젝트: kaylangan/coq
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'),
        'flag': ObjType('flag', 'flag'),
        'table': ObjType('table', 'table'),
        '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,
        'flag': FlagObject,
        'table': TableObject,
        '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),
        'flag': XRefRole(warn_dangling=True),
        'table': 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,
        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': {},
            'flag': {},
            'table': {},
            '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]
예제 #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[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,
                      stacklevel=2)
        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 == '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) as exc:
                # target_node is found, but fignumber is not assigned.
                # Maybe it is defined in orphaned document.
                raise ValueError from exc

    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
예제 #8
0
class EmacsLispDomain(Domain):
    """A domain to document Emacs Lisp code."""

    name = 'el'
    label = 'Emacs Lisp'

    object_types = {
        # TODO: Set search prio for object types
        # Types for user-facing options and commands
        'minor-mode': ObjType('minor-mode', 'function', 'mode',
                              cell='function'),
        'define-key': ObjType('key binding', cell='interactive'),
        'defcustom': ObjType('defcustom', 'defcustom', cell='variable'),
        'defface': ObjType('defface', 'defface', cell='face'),
        # Object types for code
        'defun': ObjType('defun', 'defun', cell='function'),
        'defmacro': ObjType('defmacro', 'defmacro', cell='function'),
        'defvar': ObjType('defvar', 'defvar', cell='variable'),
        'defconst': ObjType('defconst', 'defconst', cell='variable')
    }
    directives = {
        'minor-mode': EmacsLispMinorMode,
        'define-key': EmacsLispKey,
        'defcustom': EmacsLispSymbol,
        'defvar': EmacsLispSymbol,
        'defconst': EmacsLispSymbol,
        'defface': EmacsLispSymbol,
        'defun': EmacsLispFunction,
        'defmacro': EmacsLispFunction
    }
    roles = {
        'mode': XRefModeRole(),
        'defvar': XRefRole(),
        'defconst': XRefRole(),
        'defcustom': XRefRole(),
        'defface': XRefRole(),
        'defun': XRefRole(),
        'defmacro': XRefRole()
    }

    data_version = 1
    initial_data = {
        # Our domain data attempts to somewhat mirror the semantics of Emacs
        # Lisp, so we have an obarray which holds symbols which in turn have
        # function, variable, face, etc. cells, and a keymap which holds the
        # documentation for key bindings.
        'obarray': {},
        'keymap': {}
    }

    def clear_doc(self, docname):
        """Clear all cells documented ``docname``."""
        for symbol in self.data['obarray'].values():
            for cell in list(symbol.keys()):
                if docname == symbol[cell].docname:
                    del symbol[cell]
        for binding in list(self.data['keymap']):
            if self.data['keymap'][binding] == docname:
                del self.data['keymap'][binding]

    def resolve_xref(self, env, fromdocname, builder,
                     objtype, target, node, contnode):
        """Resolve a cross reference to ``target``."""
        if objtype == 'key':
            todocname = self.data['keymap'].get(target)
            if not todocname:
                return None
            reftarget = make_target('key', target)
        else:
            cell = self.object_types[objtype].attrs['cell']
            symbol = self.data['obarray'].get(target, {})
            if cell not in symbol:
                return None
            reftarget = make_target(cell, target)
            todocname = symbol[cell].docname

        return make_refnode(builder, fromdocname, todocname,
                            reftarget, contnode, target)

    def resolve_any_xref(self, env, fromdocname, builder,
                         target, node, contnode):
        """Return all possible cross references for ``target``."""
        nodes = ((objtype, self.resolve_xref(env, fromdocname, builder,
                                             objtype, target, node, contnode))
                 for objtype in ['key', 'defun', 'defvar', 'defface'])
        return [('el:{}'.format(objtype), node) for (objtype, node) in nodes
                if node is not None]

    @staticmethod
    def merge_warn_duplicate(objname, our_docname, their_docname):
        MERGE_DUP_MSG = "Duplicate declaration: '{}' also defined in '{}'.\n"
        msg = MERGE_DUP_MSG.format(objname, our_docname)
        self.env.warn(their_docname, msg)

    @staticmethod
    def merge_keymapdata(docnames, our_keymap, their_keymap):
        for key, docname in their_keymap.items():
            if docname in docnames:
                if key in our_keymap:
                    our_docname = our_keymap[key]
                    self.merge_warn_duplicate(our_docname, objname, docname)
                else:
                    our_keymap[key] = docname

    @staticmethod
    def merge_obarraydata(docnames, our_obarray, their_obarray):
        for objname, their_cells in their_obarray.items():
            our_cells = our_obarray.setdefault(objname, dict())
            for cellname, their_cell in their_cells.items():
                if their_cell.docname in docnames:
                    our_cell = our_cells.get(cellname)
                    if our_cell:
                        self.merge_warn_duplicate(docname, objname,
                                                  their_cell.docname)
                    else:
                        our_cells[cellname] = their_cell

    def merge_domaindata(self, docnames, otherdata):
        self.merge_keymapdata(docnames, self.data['keymap'],
                              otherdata['keymap'])
        self.merge_obarraydata(docnames, self.data['obarray'],
                               otherdata['obarray'])

    def get_objects(self):
        """Get all documented symbols for use in the search index."""
        for name, symbol in self.data['obarray'].items():
            for cellname, cell in symbol.items():
                yield (name, name, cell.objtype, cell.docname,
                       make_target(cellname, name),
                       self.object_types[cell.objtype].attrs['searchprio'])
예제 #9
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(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),
    }

    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',
        '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),
    }

    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 self.is_enumerable_node(node):
                sectname = self.get_numfig_title(node)
                if sectname is None:
                    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, rolename, **options):
        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):
        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, 'ref')
        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.',
                         lineno=node.line)
                return contnode

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

            try:
                figure_id = target_node['ids'][0]
                fignumber = 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.
                env.warn(fromdocname,
                         "no number is assigned for %s: %s" %
                         (figtype, labelid),
                         lineno=node.line)
                return contnode

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

            try:
                newtitle = title % '.'.join(map(str, fignumber))
            except TypeError:
                env.warn(fromdocname,
                         'invalid numfig_format: %s' % title,
                         lineno=node.line)
                return None

            return self.build_reference_node(
                fromdocname,
                builder,
                docname,
                labelid,
                newtitle,
                'numref',
                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':
            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)
        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):
        # 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 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

    def is_enumerable_node(self, node):
        return node.__class__ in self.enumerable_nodes

    def get_numfig_title(self, node):
        """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_figtype(self, node):
        """Get figure type of nodes."""
        def has_child(node, cls):
            return any(isinstance(child, cls) for child in node)

        if 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
예제 #10
0
 def __init__(self, method, **kwargs):
     XRefRole.__init__(self, **kwargs)
     self.method = method
예제 #11
0
class SpeedCrunchDomain(Domain):
    """Domain for documenting SpeedCrunch functions."""

    name = 'sc'
    label = 'SpeedCrunch'
    data_version = 1

    object_types = {
        # l10n: Label for built-in SpeedCrunch functions
        'function': ObjType(l_('function'), 'func'),
        # l10n: Label for built-in SpeedCrunch constants
        'constant': ObjType(l_('constant'), 'const'),
    }

    directives = {
        'function': SpeedCrunchFunction,
        'constant': SpeedCrunchConstant,
    }

    indices = [FunctionIndex]

    roles = {
        'func': XRefRole(fix_parens=True),
        'const': XRefRole(),
    }

    initial_data = {
        'objects': {},
    }

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

    def clear_doc(self, docname):
        for name, (i_docname, objtype) in list(self.data['objects'].items()):
            if i_docname == docname:
                del self.data['objects'][name]

    def merge_domaindata(self, docnames, otherdata):
        for name, (docname, objtype) in otherdata['objects'].items():
            if docname in docnames:
                self.data['objects'][name] = (docname, objtype)

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        try:
            docname, objtype = self.data['objects'][target]
        except KeyError:
            return None
        return make_refnode(builder, fromdocname, docname, 'sc.' + target,
                            contnode, target)

    def resolve_any_xref(self, env, fromdocname, builder, target, node,
                         contnode):
        try:
            docname, objtype = self.data['objects'][target]
        except KeyError:
            return []
        return [('sc:' + self.role_for_objtype(objtype),
                 make_refnode(builder, fromdocname, docname, 'sc.' + target,
                              contnode, target))]

    def get_objects(self):
        for name, (docname, objtype) in self.data['objects'].items():
            yield (name, name, objtype, docname, 'sc.' + name, 1)
예제 #12
0
def brianobj_role(role,
                  rawtext,
                  text,
                  lineno,
                  inliner,
                  options={},
                  content=[]):
    '''
    A Sphinx role, used as a wrapper for the default `py:obj` role, allowing
    us to use the simple backtick syntax for brian classes/functions without
    having to qualify the package for classes/functions that are available after
    a `from brian2 import *`, e.g `NeuronGroup`.
    Also allows to directly link to preference names using the same syntax.
    '''
    if text in prefs:
        linktext = text.replace('_', '-').replace('.', '-')
        text = '%s <brian-pref-%s>' % (text, linktext)
        # Use sphinx's cross-reference role
        xref = XRefRole(warn_dangling=True)
        return xref('std:ref', rawtext, text, lineno, inliner, options,
                    content)
    else:
        if text and (not '~' in text):
            try:
                # A simple class or function name
                if '.' not in text:
                    module = __import__('brian2', fromlist=[str(text)])
                    imported = getattr(module, str(text), None)
                    if getattr(imported, '__module__', None):
                        text = '~' + imported.__module__ + '.' + text
                        if inspect.isfunction(imported):
                            text += '()'
                # Possibly a method/classmethod/attribute name
                elif len(text.split('.')) == 2:
                    classname, attrname = text.split('.')
                    # Remove trailing parentheses (will be readded for display)
                    if attrname.endswith('()'):
                        attrname = attrname[:-2]
                    module = __import__('brian2', fromlist=[str(classname)])
                    imported = getattr(module, str(classname), None)
                    if hasattr(imported, '__module__'):
                        # Add trailing parentheses only for methods not for
                        # attributes
                        if inspect.ismethod(
                                getattr(imported, str(attrname), None)):
                            parentheses = '()'
                        else:
                            parentheses = ''

                        text = ('{classname}.{attrname}{parentheses} '
                                '<{modname}.{classname}.{attrname}>').format(
                                    classname=classname,
                                    attrname=attrname,
                                    modname=imported.__module__,
                                    parentheses=parentheses)

            except ImportError:
                pass
        role = 'py:obj'
        py_role = PyXRefRole()
        return py_role(role, rawtext, text, lineno, inliner, options, content)
예제 #13
0
def setup(app):
    app.add_role_to_domain('el', 'flyc-checker', XRefRole())
    app.add_directive_to_domain('el', 'flyc-checker', FlycheckChecker)
    app.add_transform(FlycheckSubstitutions)
    app.connect('doctree-read', count_languages)
    app.connect('doctree-resolved', substitute_flycheck_info)
예제 #14
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'),
    }
    directives = {
        'recipe': CondaRecipe,
        'package': CondaPackage,
    }
    roles = {
        'recipe': XRefRole(),
        'package': XRefRole(),
    }
    initial_data = {
        'objects': {},  #: (type, name) -> docname, labelid
        'backrefs': {}  #: package_name -> docname, package_name
    }
    indices = [RecipeIndex]

    def clear_doc(self, docname: str):
        # docs copied from Domain class
        """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_xref(self, env: BuildEnvironment, fromdocname: str, builder,
                     typ, target, node, contnode):
        # docs copied from Domain class
        """Resolve the pending_xref *node* with the given *typ* and *target*.

        This method should return a new node, to replace the xref node,
        containing the *contnode* which is the markup content of the
        cross-reference.

        If no resolution can be found, None can be returned; the xref node will
        then given to the :event:`missing-reference` event, and if that yields no
        resolution, replaced by *contnode*.

        The method can also raise :exc:`sphinx.environment.NoUri` to suppress
        the :event:`missing-reference` event being emitted.
        """
        if typ == 'depends':
            # 'depends' role is handled just like a 'package' here (resolves the same)
            typ = 'package'
        elif typ == 'requiredby':
            # 'requiredby' role type is deferred to missing_references stage
            return None

        for objtype in self.objtypes_for_role(typ):
            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":
                # Avoid going through the entire repodata CF - we cache a set of the
                # packages available via conda-forge here.
                if not hasattr(env, 'conda_forge_packages'):
                    pkgs = set(RepoData().get_package_data(
                        'name', channels='conda-forge'))
                    env.conda_forge_packages = pkgs
                else:
                    pkgs = env.conda_forge_packages

                if target in pkgs:
                    uri = CONDA_FORGE_FORMAT.format(target)
                    node = nodes.reference('',
                                           '',
                                           internal=False,
                                           refuri=uri,
                                           classes=['conda-forge'])
                    node += contnode
                    return node

        return None  # triggers missing-reference

    def get_objects(self):
        # docs copied from Domain class
        """Return an iterable of "object descriptions", which are tuples with
        five items:

        * `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` -- how "important" the object is (determines placement
          in search results)

          - 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)
예제 #15
0
def setup(app):
    app.add_node(chap_ref, html=(html_visit_chap_ref, None))
    app.add_node(chap_num, html=(html_visit_chap_ref, None))
    app.add_role('chap', XRefRole(nodeclass=chap_ref))
    app.add_role('numchap', XRefRole(nodeclass=chap_num))
예제 #16
0
class SystemDomain(Domain):

    name = "system"
    label = "System definition"
    roles = {"ref": XRefRole()}
    directives = {
        "process": Process,
        "object": Object,
        # 'startSubProcesses': StartSubProcessesDirective,
    }
    indices = [ProcessIndex, ObjectIndex]
    initial_data: dict = {
        "processes": [],  # object list
        "objects": [],  # object list
        "process_consumes": {},
        "process_produces": {},
    }

    def get_full_qualified_name(self, node):
        return "{}.{}".format("system", node.arguments[0])

    def get_objects(self):
        for obj in self.data["processes"]:
            yield (obj)
        for obj in self.data["objects"]:
            yield (obj)

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        match = [
            (docname, anchor)
            for name, sig, typ, docname, anchor, prio in self.get_objects()
            if sig == target
        ]

        if len(match) > 0:
            todocname = match[0][0]
            targ = match[0][1]

            # print("system domain: found %s %s %r xref" % (todocname, targ, target))
            return make_refnode(builder, fromdocname, todocname, targ,
                                contnode, targ)
        else:
            print("system domain: found nothing for %r xref" % target)
            return None

    def add_process(self, signature, consumes, produces):
        """Add a new process to the domain."""
        name = "{}.{}".format("process", signature)
        anchor = "process-{}".format(signature)

        # self.data['recipe_ingredients'][name] = ingredients
        # name, dispname, type, docname, anchor, priority
        self.data["processes"].append(
            (name, signature, "Process", self.env.docname, anchor, 0))
        self.data["process_consumes"][name] = consumes
        self.data["process_produces"][name] = produces

    def add_object(self, signature, ingredients):
        """Add a new object to the domain."""
        name = "{}.{}".format("object", signature)
        anchor = "object-{}".format(signature)

        # self.data['recipe_ingredients'][name] = ingredients
        # name, dispname, type, docname, anchor, priority
        self.data["objects"].append(
            (name, signature, "Object", self.env.docname, anchor, 0))
예제 #17
0
def setup(app):
    log = logging.getLogger(__name__)
    app.add_builder(NeedsBuilder)
    app.add_config_value(
        'needs_types',
        [
            dict(directive="req",
                 title="Requirement",
                 prefix="R_",
                 color="#BFD8D2",
                 style="node"),
            dict(directive="spec",
                 title="Specification",
                 prefix="S_",
                 color="#FEDCD2",
                 style="node"),
            dict(directive="impl",
                 title="Implementation",
                 prefix="I_",
                 color="#DF744A",
                 style="node"),
            dict(directive="test",
                 title="Test Case",
                 prefix="T_",
                 color="#DCB239",
                 style="node"),
            # Kept for backwards compatibility
            dict(directive="need",
                 title="Need",
                 prefix="N_",
                 color="#9856a5",
                 style="node")
        ],
        'html')
    app.add_config_value('needs_template', DEFAULT_TEMPLATE, 'html')
    app.add_config_value('needs_template_collapse', DEFAULT_TEMPLATE_COLLAPSE,
                         'html')

    app.add_config_value('needs_include_needs', True, 'html')
    app.add_config_value('needs_need_name', "Need", 'html')
    app.add_config_value('needs_spec_name', "Specification", 'html')
    app.add_config_value('needs_id_prefix_needs', "", 'html')
    app.add_config_value('needs_id_prefix_specs', "", 'html')
    app.add_config_value('needs_id_length', 5, 'html')
    app.add_config_value('needs_specs_show_needlist', False, 'html')
    app.add_config_value('needs_id_required', False, 'html')
    app.add_config_value(
        'needs_id_regex', "^[A-Z0-9_]{{{id_length},}}".format(
            id_length=app.config.needs_id_length), 'html')
    app.add_config_value('needs_show_link_type', False, 'html')
    app.add_config_value('needs_show_link_title', False, 'html')
    app.add_config_value('needs_file', "needs.json", 'html')
    app.add_config_value('needs_table_columns',
                         "ID;TITLE;STATUS;TYPE;OUTGOING;TAGS", 'html')
    app.add_config_value('needs_table_style', "DATATABLES", 'html')

    app.add_config_value('needs_collapse_details', True, 'html')

    app.add_config_value('needs_role_need_template', "{title} ({id})", 'html')

    app.add_config_value('needs_extra_options', {}, 'html')
    app.add_config_value('needs_title_optional', False, 'html')
    app.add_config_value('needs_max_title_length', -1, 'html')
    app.add_config_value('needs_title_from_content', False, 'html')

    app.add_config_value('needs_diagram_template', DEFAULT_DIAGRAM_TEMPLATE,
                         'html')

    # app.add_config_value('needs_functions', None, 'html')
    app.add_config_value('needs_global_options', {}, 'html')
    app.add_config_value('needs_hide_options', [], 'html')

    # If given, only the defined status are allowed.
    # Values needed for each status:
    # * name
    # * description
    # Example: [{"name": "open", "description": "open status"}, {...}, {...}]
    app.add_config_value('needs_statuses', False, 'html')

    # If given, only the defined tags are allowed.
    # Values needed for each tag:
    # * name
    # * description
    # Example: [{"name": "new", "description": "new needs"}, {...}, {...}]
    app.add_config_value('needs_tags', False, 'html')

    # Path of css file, which shall be used for need style
    app.add_config_value('needs_css', "modern.css", 'html')

    # Prefix for need_part output in tables
    app.add_config_value('needs_part_prefix', u'\u2192\u00a0', 'html')

    # As values from conf.py are not available during setup phase, we have to import and read them by our own.
    # Otherwise this "app.config.needs_types" would always return the default values only.
    try:
        import imp
        # If sphinx gets started multiple times inside a python process, the following module gets also
        # loaded several times. This has a drawback, as the config from the current build gets somehow merged
        # with the config from the previous builds.
        # So if the current config does not define a parameter, which was set in build before, the "old" value is
        # taken. This is dangerous, because a developer may simply want to use the defaults (like the predefined types)
        # and therefore does not set this specific value. But instead he would get the value from a previous build.
        # So we generate a random module name for our configuration, so that this is loaded for the first time.
        # Drawback: The old modules will still exist (but are not used).
        #
        # From https://docs.python.org/2.7/library/functions.html#reload
        # "When a module is reloaded, its dictionary (containing the module’s global variables) is retained.
        # Redefinitions of names will override the old definitions, so this is generally not a problem.
        # If the new version of a module does not define a name that was defined by the old version,
        # the old definition remains"

        # Be sure, our current working directory is the folder, which stores the conf.py.
        # Inside the conf.py there may be relatives paths, which would be incorrect, if our cwd is wrong.
        old_cwd = os.getcwd()
        os.chdir(app.confdir)
        module_name = "needs_app_conf_" + ''.join(
            random.choice(string.ascii_uppercase) for _ in range(5))
        config = imp.load_source(module_name,
                                 os.path.join(app.confdir, "conf.py"))
        os.chdir(
            old_cwd
        )  # Lets switch back the cwd, otherwise other stuff may not run...
        types = getattr(config, "needs_types", app.config.needs_types)
        extra_options = getattr(config, "needs_extra_options",
                                app.config.needs_extra_options)
        title_optional = getattr(config, "needs_title_optional",
                                 app.config.needs_title_optional)
        title_from_content = getattr(config, "needs_title_from_content",
                                     app.config.needs_title_from_content)
        app.needs_functions = getattr(config, "needs_functions", [])
        latex_visit = getattr(config, "needs_latex_visit", latex_visit_default)
        latex_depart = getattr(config, "needs_latex_depart",
                               latex_depart_default)
    except IOError:
        types = app.config.needs_types
    except Exception as e:
        log.error("Error during sphinxcontrib-needs setup: {0}, {1}".format(
            os.path.join(app.confdir, "conf.py"), e))
        types = app.config.needs_types

    # Define nodes
    app.add_node(Need,
                 html=(html_visit, html_depart),
                 latex=(latex_visit, latex_depart))
    app.add_node(Needfilter, )
    app.add_node(Needimport)
    app.add_node(Needlist)
    app.add_node(Needtable)
    app.add_node(Needflow)
    app.add_node(NeedPart,
                 html=(visitor_dummy, visitor_dummy),
                 latex=(visitor_dummy, visitor_dummy))

    ########################################################################
    # DIRECTIVES
    ########################################################################

    # Define directives
    # Update NeedDirective to use customized options
    NeedDirective.option_spec.update(extra_options)
    if title_optional or title_from_content:
        NeedDirective.required_arguments = 0
        NeedDirective.optional_arguments = 1

    for type in types:
        # Register requested types of needs
        app.add_directive(type["directive"], NeedDirective)
        app.add_directive("{0}_list".format(type["directive"]), NeedDirective)

    app.add_directive('needfilter', NeedfilterDirective)
    app.add_directive('needlist', NeedlistDirective)
    app.add_directive('needtable', NeedtableDirective)
    app.add_directive('needflow', NeedflowDirective)

    app.add_directive('needimport', NeedimportDirective)

    ########################################################################
    # ROLES
    ########################################################################
    # Provides :need:`ABC_123` for inline links.
    app.add_role(
        'need',
        XRefRole(nodeclass=Need_ref,
                 innernodeclass=nodes.emphasis,
                 warn_dangling=True))

    app.add_role(
        'need_incoming',
        XRefRole(nodeclass=Need_incoming,
                 innernodeclass=nodes.emphasis,
                 warn_dangling=True))

    app.add_role(
        'need_outgoing',
        XRefRole(nodeclass=Need_outgoing,
                 innernodeclass=nodes.emphasis,
                 warn_dangling=True))

    app.add_role(
        'need_part',
        XRefRole(nodeclass=NeedPart,
                 innernodeclass=nodes.inline,
                 warn_dangling=True))
    # Shortcut for need_inline
    app.add_role(
        'np',
        XRefRole(nodeclass=NeedPart,
                 innernodeclass=nodes.inline,
                 warn_dangling=True))

    app.add_role(
        'need_count',
        XRefRole(nodeclass=NeedCount,
                 innernodeclass=nodes.inline,
                 warn_dangling=True))

    ########################################################################
    # EVENTS
    ########################################################################
    # Make connections to events
    app.connect('env-purge-doc', purge_needs)
    app.connect('env-before-read-docs', prepare_env)
    app.connect('doctree-resolved', add_sections)
    app.connect('doctree-resolved', process_need_nodes)
    app.connect('doctree-resolved', process_dynamic_values)
    app.connect('doctree-resolved', process_needfilters)
    app.connect('doctree-resolved', process_needlist)
    app.connect('doctree-resolved', process_needtables)
    app.connect('doctree-resolved', process_needflow)
    app.connect('doctree-resolved', process_need_part)
    app.connect('doctree-resolved', process_need_ref)
    app.connect('doctree-resolved', process_need_incoming)
    app.connect('doctree-resolved', process_need_outgoing)
    app.connect('doctree-resolved', process_need_count)
    app.connect('env-updated', install_datatables_static_files)

    # Call this after all JS files, which perform DOM manipulation, have been called.
    # Otherwise newly added dom objects can not be collapsed
    app.connect('env-updated', install_collapse_static_files)

    # This should be called last, so that need-styles can override styles from used libraries
    app.connect('env-updated', install_styles_static_files)

    return {'version': VERSION}  # identifies the version of our extension
예제 #18
0
파일: ext.py 프로젝트: zmadi1/buildbot
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'),
        'reportgen': ObjType('reportgen', 'reportgen'),
        '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'),
        'raction': ObjType('raction', 'raction'),
    }

    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',
                                  ]),
        'reportgen':
        make_ref_target_directive('reportgen',
                                  indextemplates=[
                                      'single: Report Generators; %s',
                                      'single: %s Report Generator',
                                  ]),
        '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(),
        'reportgen': 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("reportgen", "Reporter Generator 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 '{}'".format(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)

    def merge_domaindata(self, docnames, otherdata):
        for typ in self.object_types:
            if typ not in otherdata['targets']:
                continue

            if typ not in self.data['targets']:
                self.data['targets'][typ] = otherdata['targets'][typ]
                continue

            self_data = self.data['targets'][typ]
            other_data = otherdata['targets'][typ]

            for target_name, target_data in other_data.items():
                if target_name in self_data:
                    # for some reason we end up with multiple references to the same things in
                    # multiple domains. If both instances point to the same location, ignore it,
                    # otherwise issue a warning.
                    if other_data[target_name] == self_data[target_name]:
                        continue

                    self_path = '{0}#{1}'.format(
                        self.env.doc2path(self_data[target_name][0]),
                        self_data[target_name][1])

                    other_path = '{0}#{1}'.format(
                        self.env.doc2path(other_data[target_name][0]),
                        other_data[target_name][1])

                    logger.warning(('Duplicate index {} reference {} in {}, '
                                    'other instance in {}').format(
                                        typ, target_name, self_path,
                                        other_path))
                else:
                    self_data[target_name] = target_data
예제 #19
0
class ZeekDomain(Domain):
    """Zeek domain."""

    name = "zeek"
    label = "Zeek"

    object_types = {
        "type": ObjType(_("type"), "type"),
        "namespace": ObjType(_("namespace"), "namespace"),
        "id": ObjType(_("id"), "id"),
        "keyword": ObjType(_("keyword"), "keyword"),
        "enum": ObjType(_("enum"), "enum"),
        "attr": ObjType(_("attr"), "attr"),
    }

    directives = {
        "type": ZeekGeneric,
        "namespace": ZeekNamespace,
        "id": ZeekIdentifier,
        "keyword": ZeekKeyword,
        "enum": ZeekEnum,
        "attr": ZeekAttribute,
    }

    roles = {
        "type": XRefRole(),
        "namespace": XRefRole(),
        "id": XRefRole(),
        "keyword": XRefRole(),
        "enum": XRefRole(),
        "attr": XRefRole(),
        "see": XRefRole(),
    }

    indices = [
        ZeekNotices,
    ]

    initial_data = {
        "objects": {},  # fullname -> docname, objtype
    }

    def clear_doc(self, docname):
        to_delete = []

        for (typ, name), doc in self.data["objects"].items():
            if doc == docname:
                to_delete.append((typ, name))

        for (typ, name) in to_delete:
            del self.data["objects"][typ, name]

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        objects = self.data["objects"]
        if typ == "see":
            if target not in self.data["idtypes"]:
                logger.warning('%s: unknown target for ":zeek:see:`%s`"',
                               fromdocname, target)
                return []
            objtype = self.data["idtypes"][target]
            return make_refnode(
                builder,
                fromdocname,
                objects[objtype, target],
                objtype + "-" + target,
                contnode,
                target + " " + objtype,
            )
        else:
            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,
                    )

    def get_objects(self):
        for (typ, name), docname in self.data["objects"].items():
            yield name, name, typ, docname, typ + "-" + name, 1
예제 #20
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(),
        '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 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, _) in list(self.data['progoptions'].items()):
            if fn == docname:
                del self.data['progoptions'][key]
        for key, (fn, _) in list(self.data['objects'].items()):
            if fn == docname:
                del self.data['objects'][key]
        for key, (fn, _, _) in list(self.data['labels'].items()):
            if fn == docname:
                del self.data['labels'][key]
        for key, (fn, _) 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
            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.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

    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 == title:
                prefix = env.config.numfig_format.get(figtype, '')
                title = prefix.replace('%s', '#')
                newtitle = prefix % '.'.join(map(str, fignumber))
            else:
                newtitle = title.replace('#', '.'.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')
            else:
                try:
                    progname, target = re.split(r' (?=-|--|/|\+)', target, 1)
                except ValueError:
                    return None
                progname = ws_re.sub('-', progname.strip())
            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
예제 #21
0
class GlossaryDomain(Domain):

    name = 'glossary'
    label = 'Glossary'
    roles = {'abbr': XRefRole(), 'abpl': XRefRole(), 'gls': XRefRole()}
    directives = {
        'entry': GlossaryDirective,
    }
    indices = {
        AbbreviationIndex,
    }
    initial_data = {
        "entries": [],
        "names": {},
        "abbreviation": {},
        "abbreviation-name": {},
        "abbreviation-plural": {}
    }

    def get_full_qualified_name(self, node):
        return '{}.{}'.format('recipe', node.arguments[0])

    def get_objects(self):
        for obj in self.data['entries']:
            yield (obj)

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        if typ in {"abbr", "abpl", "gls"}:
            target = f"glossary:{target}".lower()

            # for name, sig, typ, docname, anchor, prio in self.get_objects():
            #     print(name, typ, anchor.lower(), sig)

            match = [(docname, anchor, name, sig) for name, sig, typ, docname,
                     anchor, prio in self.get_objects()
                     if anchor.lower() == target.lower()]

        else:
            return None

        if len(match) > 0:
            todocname = match[0][0]
            targ = match[0][1]

            if typ == "abbr":
                name = self.data['abbreviation-name'][match[0][2]]
            elif typ == "gls":
                name = self.data['names'][match[0][2]]
            elif typ == "abpl" and (match[0][2]
                                    in self.data['abbreviation-plural']):
                name = self.data['abbreviation-plural'][match[0][2]]
            elif typ == "abpl":
                name = self.data['abbreviation-name'][match[0][2]] + "s"
            else:
                name = match[0][2]
            sig = match[0][3]

            if typ in {"abbr", "abpl"}:
                contnode = nodes.abbreviation(text=nodes.Text(name),
                                              explanation=sig)
            else:
                contnode = nodes.Text(name)
            #contnode.elements = [nodes.Text(name)]
            return make_refnode(builder, fromdocname, todocname, targ,
                                contnode, targ)
        else:
            print('Awww, found nothing')
            return None

    def add_entry(self, signature, **kwargs):
        """Add a new entry to the glossary."""
        if "label" in kwargs:
            label = kwargs['label']
            name = f"glossary.{label}"
            anchor = f"glossary:{label}"
        else:
            name = f"glossary.{signature}"
            anchor = f"glossary-{signature}"

        self.data['entries'].append(
            (name, signature, "Glossary", self.env.docname, anchor, 0))

        self.data['names'][name] = signature

        if "abbreviation" in kwargs:
            self.data['abbreviation'][kwargs['abbreviation']] = signature
            self.data['abbreviation-name'][name] = kwargs['abbreviation']
        if "abbreviationpl" in kwargs:
            self.data['abbreviation-plural'][name] = kwargs['abbreviationpl']
예제 #22
0
 def __init__(self, method, **kwargs):
     XRefRole.__init__(self, **kwargs)
     self.method = method
예제 #23
0
파일: zeek.py 프로젝트: zeek/zeek-docs
class ZeekDomain(Domain):
    """Zeek domain."""
    name = 'zeek'
    label = 'Zeek'

    object_types = {
        'type': ObjType(_('type'), 'type'),
        'native-type': ObjType(_('type'), 'type'),
        'namespace': ObjType(_('namespace'), 'namespace'),
        'id': ObjType(_('id'), 'id'),
        'keyword': ObjType(_('keyword'), 'keyword'),
        'enum': ObjType(_('enum'), 'enum'),
        'attr': ObjType(_('attr'), 'attr'),
    }

    directives = {
        'type': ZeekGeneric,
        'native-type': ZeekNativeType,
        'namespace': ZeekNamespace,
        'id': ZeekIdentifier,
        'keyword': ZeekKeyword,
        'enum': ZeekEnum,
        'attr': ZeekAttribute,
    }

    roles = {
        'type': XRefRole(),
        'namespace': XRefRole(),
        'id': XRefRole(),
        'keyword': XRefRole(),
        'enum': XRefRole(),
        'attr': XRefRole(),
        'see': XRefRole(),
    }

    indices = [
        ZeekNotices,
    ]

    initial_data = {
        'objects': {},  # fullname -> docname, objtype
    }

    def clear_doc(self, docname):
        to_delete = []

        for (typ, name), doc in self.data['objects'].items():
            if doc == docname:
                to_delete.append((typ, name))

        for (typ, name) in to_delete:
            del self.data['objects'][typ, name]

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        objects = self.data['objects']

        if typ == "see":
            if target not in self.data['idtypes']:
                logger.warning('%s: unknown target for ":zeek:see:`%s`"',
                               fromdocname, target)
                return []
            objtype = self.data['idtypes'][target]
            return make_refnode(builder, fromdocname, objects[objtype, target],
                                objtype + '-' + target, contnode,
                                target + ' ' + objtype)
        else:
            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)
                else:
                    logger.warning('%s: unknown target for ":zeek:%s:`%s`"',
                                   fromdocname, typ, target)

    def get_objects(self):
        for (typ, name), docname in self.data['objects'].items():
            yield name, name, typ, docname, typ + '-' + name, 1
예제 #24
0
class BroDomain(Domain):
    """Bro domain."""
    name = 'bro'
    label = 'Bro'

    object_types = {
        'type': ObjType(l_('type'), 'type'),
        'namespace': ObjType(l_('namespace'), 'namespace'),
        'id': ObjType(l_('id'), 'id'),
        'enum': ObjType(l_('enum'), 'enum'),
        'attr': ObjType(l_('attr'), 'attr'),
    }

    directives = {
        'type': BroGeneric,
        'namespace': BroNamespace,
        'id': BroIdentifier,
        'enum': BroEnum,
        'attr': BroAttribute,
    }

    roles = {
        'type': XRefRole(),
        'namespace': XRefRole(),
        'id': XRefRole(),
        'enum': XRefRole(),
        'attr': XRefRole(),
        'see': XRefRole(),
    }

    indices = [
        BroNotices,
    ]

    initial_data = {
        'objects': {},  # fullname -> docname, objtype
    }

    def clear_doc(self, docname):
        for (typ, name), doc in self.data['objects'].items():
            if doc == docname:
                del self.data['objects'][typ, name]

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        objects = self.data['objects']
        if typ == "see":
            if target not in self.data['idtypes']:
                self.env.warn(fromdocname,
                              'unknown target for ":bro:see:`%s`"' % (target))
                return []
            objtype = self.data['idtypes'][target]
            return make_refnode(builder, fromdocname, objects[objtype, target],
                                objtype + '-' + target, contnode,
                                target + ' ' + objtype)
        else:
            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)
                else:
                    self.env.warn(
                        fromdocname,
                        'unknown target for ":bro:%s:`%s`"' % (typ, target))

    def get_objects(self):
        for (typ, name), docname in self.data['objects'].iteritems():
            yield name, name, typ, docname, typ + '-' + name, 1
예제 #25
0
 def __init__(self, typename, titleFactory, **kwargs):
     XRefRole.__init__(self, **kwargs)
     self.typename = typename
     self.titleFactory = titleFactory
예제 #26
0
파일: rst.py 프로젝트: rds0751/odfo
class ReSTDomain(Domain):
    """ReStructuredText domain."""
    name = 'rst'
    label = 'reStructuredText'

    object_types = {
        'directive': ObjType(l_('directive'), 'dir'),
        'role': ObjType(l_('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, nodes.Node, nodes.Node) -> nodes.Node  # 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)

    def resolve_any_xref(self, env, fromdocname, builder, target, node,
                         contnode):
        # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[nodes.Node]  # NOQA
        objects = self.data['objects']
        results = []
        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 iteritems(self.data['objects']):
            yield name, name, typ, docname, typ + '-' + name, 1
예제 #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 = "{} '{}'".format(typ, 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)
예제 #28
0
class JsonRpcDomain(Domain):
    name = "jsonrpc"
    label = "Trio JSON-RPC"
    roles = {
        "ref": XRefRole(),
    }
    directives = {
        "dispatch": JsonRpcDispatch,
        "method": JsonRpcMethod,
        "exception": JsonRpcError,
    }
    indices = {
        JsonRpcIndex,
    }
    initial_data: typing.Dict = {
        "errors": dict(),
        "methods": dict(),
    }

    def add_error(self, signature):
        class_name = signature.split(".")[-1]
        name = f"error.{class_name}"
        anchor = f"jsonrpc-error-{class_name}"
        self.data["errors"][name] = (
            class_name,
            "Error",
            self.env.docname,
            anchor,
            0,
        )

    def add_method(self, signature):
        name = f"method.{signature}"
        anchor = f"jsonrpc-method-{signature}"
        self.data["methods"][name] = (
            signature,
            "Method",
            self.env.docname,
            anchor,
            0,
        )

    def get_objects(self):
        for name, err in self.data["errors"].items():
            yield (name, *err)
        for name, meth in self.data["methods"].items():
            yield (name, *meth)

    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
                     contnode):
        if target in JSON_TYPES:
            return
        match = [
            (docname, anchor)
            for name, sig, typ, docname, anchor, prio in self.get_objects()
            if sig == target
        ]
        if len(match) > 0:
            todocname = match[0][0]
            targ = match[0][1]
            return make_refnode(builder, fromdocname, todocname, targ,
                                contnode, targ)
        else:
            return env.get_domain("py").resolve_xref(env, fromdocname, builder,
                                                     typ, target, node,
                                                     contnode)
예제 #29
0
def setup(app):
    log = logging.getLogger(__name__)
    log.debug("Starting setup of sphinx-Needs")
    app.add_builder(NeedsBuilder)
    app.add_config_value(
        'needs_types',
        [
            dict(directive="req",
                 title="Requirement",
                 prefix="R_",
                 color="#BFD8D2",
                 style="node"),
            dict(directive="spec",
                 title="Specification",
                 prefix="S_",
                 color="#FEDCD2",
                 style="node"),
            dict(directive="impl",
                 title="Implementation",
                 prefix="I_",
                 color="#DF744A",
                 style="node"),
            dict(directive="test",
                 title="Test Case",
                 prefix="T_",
                 color="#DCB239",
                 style="node"),
            # Kept for backwards compatibility
            dict(directive="need",
                 title="Need",
                 prefix="N_",
                 color="#9856a5",
                 style="node")
        ],
        'html')
    app.add_config_value('needs_include_needs', True, 'html')
    app.add_config_value('needs_need_name', "Need", 'html')
    app.add_config_value('needs_spec_name', "Specification", 'html')
    app.add_config_value('needs_id_prefix_needs', "", 'html')
    app.add_config_value('needs_id_prefix_specs', "", 'html')
    app.add_config_value('needs_id_length', 5, 'html')
    app.add_config_value('needs_specs_show_needlist', False, 'html')
    app.add_config_value('needs_id_required', False, 'html')
    app.add_config_value(
        'needs_id_regex', "^[A-Z0-9_]{{{id_length},}}".format(
            id_length=app.config.needs_id_length), 'html')
    app.add_config_value('needs_show_link_type', False, 'html')
    app.add_config_value('needs_show_link_title', False, 'html')
    app.add_config_value('needs_file', "needs.json", 'html')
    app.add_config_value('needs_table_columns',
                         "ID;TITLE;STATUS;TYPE;OUTGOING;TAGS", 'html')
    app.add_config_value('needs_table_style', "DATATABLES", 'html')

    app.add_config_value('needs_role_need_template', u"{title} ({id})", 'html')
    app.add_config_value('needs_role_need_max_title_length', 30, 'html')

    app.add_config_value('needs_extra_options', {}, 'html')
    app.add_config_value('needs_title_optional', False, 'html')
    app.add_config_value('needs_max_title_length', -1, 'html')
    app.add_config_value('needs_title_from_content', False, 'html')

    app.add_config_value('needs_diagram_template', DEFAULT_DIAGRAM_TEMPLATE,
                         'html')

    app.add_config_value('needs_functions', [], 'html')
    app.add_config_value('needs_global_options', {}, 'html')

    app.add_config_value('needs_duration_option', 'duration', 'html')
    app.add_config_value('needs_completion_option', 'completion', 'html')

    # If given, only the defined status are allowed.
    # Values needed for each status:
    # * name
    # * description
    # Example: [{"name": "open", "description": "open status"}, {...}, {...}]
    app.add_config_value('needs_statuses', [], 'html')

    # If given, only the defined tags are allowed.
    # Values needed for each tag:
    # * name
    # * description
    # Example: [{"name": "new", "description": "new needs"}, {...}, {...}]
    app.add_config_value('needs_tags', False, 'html')

    # Path of css file, which shall be used for need style
    app.add_config_value('needs_css', "modern.css", 'html')

    # Prefix for need_part output in tables
    app.add_config_value('needs_part_prefix', u'\u2192\u00a0', 'html')

    # List of additional links, which can be used by setting related option
    # Values needed for each new link:
    # * name (will also be the option name)
    # * incoming
    # * copy_link (copy to common links data. Default: True)
    # * color (used for needflow. Default: #000000)
    # Example: [{"name": "blocks, "incoming": "is blocked by", "copy_link": True, "color": "#ffcc00"}]
    app.add_config_value('needs_extra_links', [], 'html')

    app.add_config_value('needs_flow_show_links', False, 'html')
    app.add_config_value('needs_flow_link_types', ["links"], 'html')

    app.add_config_value('needs_warnings', {}, 'html')
    app.add_config_value('needs_layouts', {}, 'html')
    app.add_config_value('needs_default_layout', 'clean', 'html')
    app.add_config_value('needs_default_style', None, 'html')

    app.add_config_value('needs_flow_configs', {}, 'html')

    app.add_config_value('needs_template_folder', 'needs_templates/', 'html')

    app.add_config_value('needs_services', {}, 'html')
    app.add_config_value('needs_service_all_data', False, 'html')

    # Define nodes
    app.add_node(Need,
                 html=(html_visit, html_depart),
                 latex=(latex_visit, latex_depart))
    app.add_node(Needfilter, )
    app.add_node(Needimport)
    app.add_node(Needlist)
    app.add_node(Needtable)
    app.add_node(Needflow)
    app.add_node(Needpie)
    app.add_node(Needsequence)
    app.add_node(Needgantt)
    app.add_node(Needextract)
    app.add_node(Needservice)
    app.add_node(NeedPart,
                 html=(visitor_dummy, visitor_dummy),
                 latex=(visitor_dummy, visitor_dummy))

    ########################################################################
    # DIRECTIVES
    ########################################################################

    # Define directives
    app.add_directive('needfilter', NeedfilterDirective)
    app.add_directive('needlist', NeedlistDirective)
    app.add_directive('needtable', NeedtableDirective)
    app.add_directive('needflow', NeedflowDirective)
    app.add_directive('needpie', NeedpieDirective)
    app.add_directive('needsequence', NeedsequenceDirective)
    app.add_directive('needgantt', NeedganttDirective)
    app.add_directive('needimport', NeedimportDirective)
    app.add_directive('needextract', NeedextractDirective)
    app.add_directive('needservice', NeedserviceDirective)

    ########################################################################
    # ROLES
    ########################################################################
    # Provides :need:`ABC_123` for inline links.
    app.add_role(
        'need',
        XRefRole(nodeclass=Need_ref,
                 innernodeclass=nodes.emphasis,
                 warn_dangling=True))

    app.add_role(
        'need_incoming',
        XRefRole(nodeclass=Need_incoming,
                 innernodeclass=nodes.emphasis,
                 warn_dangling=True))

    app.add_role(
        'need_outgoing',
        XRefRole(nodeclass=Need_outgoing,
                 innernodeclass=nodes.emphasis,
                 warn_dangling=True))

    app.add_role(
        'need_part',
        XRefRole(nodeclass=NeedPart,
                 innernodeclass=nodes.inline,
                 warn_dangling=True))
    # Shortcut for need_part
    app.add_role(
        'np',
        XRefRole(nodeclass=NeedPart,
                 innernodeclass=nodes.inline,
                 warn_dangling=True))

    app.add_role(
        'need_count',
        XRefRole(nodeclass=NeedCount,
                 innernodeclass=nodes.inline,
                 warn_dangling=True))

    ########################################################################
    # EVENTS
    ########################################################################
    # Make connections to events
    app.connect('env-purge-doc', purge_needs)
    app.connect('config-inited', load_config)
    app.connect('env-before-read-docs', prepare_env)
    # app.connect('env-before-read-docs', load_config)
    app.connect('config-inited', check_configuration)

    # There is also the event doctree-read.
    # But it looks like in this event no references are already solved, which
    # makes trouble in our code.
    # However, some sphinx-internal actions (like image collection) are already called during
    # doctree-read. So manipulating the doctree may result in conflicts, as e.g. images get not
    # registered for sphinx. So some sphinx-internal tasks/functions may be called by hand again...
    # See also https://github.com/sphinx-doc/sphinx/issues/7054#issuecomment-578019701 for an example
    app.connect('doctree-resolved', add_sections)
    app.connect('doctree-resolved', process_need_nodes)
    app.connect('doctree-resolved', process_needextract)
    app.connect('doctree-resolved', process_needfilters)
    app.connect('doctree-resolved', process_needlist)
    app.connect('doctree-resolved', process_needtables)
    app.connect('doctree-resolved', process_needflow)
    app.connect('doctree-resolved', process_needpie)
    app.connect('doctree-resolved', process_needsequence)
    app.connect('doctree-resolved', process_needgantt)
    app.connect('doctree-resolved', process_need_part)
    app.connect('doctree-resolved', process_need_ref)
    app.connect('doctree-resolved', process_need_incoming)
    app.connect('doctree-resolved', process_need_outgoing)
    app.connect('doctree-resolved', process_need_count)
    app.connect('build-finished', process_warnings)
    app.connect('env-updated', install_datatables_static_files)
    # app.connect('env-updated', install_feather_icons)

    # Called during consistency check, which if after everything got read in.
    # app.connect('env-check-consistency', process_warnings)

    # Call this after all JS files, which perform DOM manipulation, have been called.
    # Otherwise newly added dom objects can not be collapsed
    app.connect('env-updated', install_collapse_static_files)

    # This should be called last, so that need-styles can override styles from used libraries
    app.connect('env-updated', install_styles_static_files)

    return {
        'version': VERSION,
        'parallel_read_safe':
        False,  # Must be False, otherwise IDs are not found exceptions are raised.
        'parallel_write_safe': True
    }
예제 #30
0
def test_XRefRole(inliner):
    role = XRefRole()

    # implicit
    doctrees, errors = role('ref', 'rawtext', 'text', 5, inliner, {}, [])
    assert len(doctrees) == 1
    assert_node(doctrees[0], [addnodes.pending_xref, nodes.literal, 'text'])
    assert_node(doctrees[0],
                refdoc='dummy',
                refdomain='',
                reftype='ref',
                reftarget='text',
                refexplicit=False,
                refwarn=False)
    assert errors == []

    # explicit
    doctrees, errors = role('ref', 'rawtext', 'title <target>', 5, inliner, {},
                            [])
    assert_node(doctrees[0], [addnodes.pending_xref, nodes.literal, 'title'])
    assert_node(doctrees[0],
                refdoc='dummy',
                refdomain='',
                reftype='ref',
                reftarget='target',
                refexplicit=True,
                refwarn=False)

    # bang
    doctrees, errors = role('ref', 'rawtext', '!title <target>', 5, inliner,
                            {}, [])
    assert_node(doctrees[0], [nodes.literal, 'title <target>'])

    # refdomain
    doctrees, errors = role('test:doc', 'rawtext', 'text', 5, inliner, {}, [])
    assert_node(doctrees[0], [addnodes.pending_xref, nodes.literal, 'text'])
    assert_node(doctrees[0],
                refdoc='dummy',
                refdomain='test',
                reftype='doc',
                reftarget='text',
                refexplicit=False,
                refwarn=False)

    # fix_parens
    role = XRefRole(fix_parens=True)
    doctrees, errors = role('ref', 'rawtext', 'text()', 5, inliner, {}, [])
    assert_node(doctrees[0], [addnodes.pending_xref, nodes.literal, 'text()'])
    assert_node(doctrees[0],
                refdoc='dummy',
                refdomain='',
                reftype='ref',
                reftarget='text',
                refexplicit=False,
                refwarn=False)

    # lowercase
    role = XRefRole(lowercase=True)
    doctrees, errors = role('ref', 'rawtext', 'TEXT', 5, inliner, {}, [])
    assert_node(doctrees[0], [addnodes.pending_xref, nodes.literal, 'TEXT'])
    assert_node(doctrees[0],
                refdoc='dummy',
                refdomain='',
                reftype='ref',
                reftarget='text',
                refexplicit=False,
                refwarn=False)
class JCoadDomain(Domain):
    name = 'jcoad'
    label = 'jCoad'

    object_types = {
        'function': ObjType(_('function'), 'func'),
        'property': ObjType(_('property'), 'prop'),
        'trigger': ObjType(_('trigger'), 'trigger'),
        'condition': ObjType(_('condition'), 'cond'),
        'type': ObjType(_('type'), 'type'),
        'pokeoption': ObjType(_('pokeoption'), 'pokeoption')
    }

    directives = {
        'function': JCoadFunction,
        'trigger': JCoadTrigger,
        'condition': JCoadCondition,
        'property': JCoadProperty,
        'type': JCoadType,
        'pokeoption': JCoadPokemonOption,
    }

    roles = {
        'func': JCoadFunctionXRefRole(),
        'prop': JCoadPropertyXRefRole(),
        'trigger': JCoadTriggerXRefRole(),
        'cond': XRefRole(),
        'type': XRefRole(),
        'pokeoption': XRefRole(),
    }

    initial_data = {
        'objects': {},  # refname -> docname, node_id, objtype
    }

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

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

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

    def find_obj(self, name: str, typ: str) -> Tuple[str, str, str]:
        objtype = next((x for x in self.object_types
                        if self.object_types[x].roles[0] == typ), None)
        return self.objects.get(objtype + '-' +
                                name) if objtype is not None else None

    def resolve_xref(self, env: BuildEnvironment, fromdocname: str,
                     builder: Builder, typ: str, target: str,
                     node: pending_xref, contnode: Element) -> Element:
        obj = self.find_obj(target, typ)
        if not obj:
            return None
        return make_refnode(builder, fromdocname, obj[0], obj[1], contnode,
                            target)

    def clear_doc(self, docname: str) -> None:
        for name, (pkg_docname, node_id, _l) in list(self.objects.items()):
            if pkg_docname == docname:
                del self.objects[name]
예제 #32
0
class ReSTDomain(Domain):
    """ReStructuredText domain."""
    name = 'rst'
    label = 'reStructuredText'

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

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

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

        self.objects[objtype, name] = (self.env.docname, node_id)

    def clear_doc(self, docname: str) -> None:
        for (typ, name), (doc, node_id) in list(self.objects.items()):
            if doc == docname:
                del self.objects[typ, name]

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

    def resolve_xref(self, env: BuildEnvironment, fromdocname: str,
                     builder: Builder, typ: str, target: str,
                     node: pending_xref, contnode: Element) -> Element:
        objtypes = self.objtypes_for_role(typ)
        for objtype in objtypes:
            todocname, node_id = self.objects.get((objtype, target),
                                                  (None, None))
            if todocname:
                return make_refnode(builder, fromdocname, todocname, node_id,
                                    contnode, target + ' ' + objtype)
        return None

    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]]
        for objtype in self.object_types:
            todocname, node_id = self.objects.get((objtype, target),
                                                  (None, None))
            if todocname:
                results.append(
                    ('rst:' + self.role_for_objtype(objtype),
                     make_refnode(builder, fromdocname, todocname, node_id,
                                  contnode, target + ' ' + objtype)))
        return results

    def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
        for (typ, name), (docname, node_id) in self.data['objects'].items():
            yield name, name, typ, docname, node_id, 1
예제 #33
0
 def __call__(self, *args, **kwargs):
     res = XRefRole.__call__(self, *args, **kwargs)
     return res
예제 #34
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'),
        'doc': ObjType(l_('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': {},    # 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',
        '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 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) in list(self.data['citations'].items()):
            if fn == docname:
                del self.data['citations'][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):
        # 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['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_labels(env, docname, document)

    def note_citations(self, env, docname, document):
        # type: (BuildEnvironment, unicode, nodes.Node) -> None
        for node in document.traverse(nodes.citation):
            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)
            self.data['citations'][label] = (docname, node['ids'][0])

    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 iteritems(document.nametypes):
            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 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:
                logger.warning('duplicate label %s, ' % name + 'other instance '
                               'in ' + 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 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

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

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

        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 = self.data['citations'].get(target, ('', ''))
        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 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):
        # 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_figtype(self, node):
        # type: (nodes.Node) -> unicode
        """Get figure type of nodes."""
        def has_child(node, cls):
            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_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
예제 #35
0
 def __call__(self, typ, rawtext, text, lineno, inliner,
              options={}, content=[]):
     #~ print('20130901',typ, rawtext, text, lineno, inliner,options, content)
     typ = 'std:ref'
     return XRefRole.__call__(self, typ, rawtext, text, lineno, 
         inliner, options, content)
예제 #36
0
 def __call__(self, typ, rawtext, text, lineno, inliner,
              options={}, content=[]):
     
     typ = 'std:ref'
     return XRefRole.__call__(self, typ, rawtext, text, lineno,
                              inliner, options, content)
예제 #37
0
파일: ext.py 프로젝트: skins1/buildbot
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'),
        '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',
                                  ]),
        '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',
                                  ]),
        '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),
                                      Field('event',
                                            label='Event',
                                            names=('event', )),
                                      Field('opt',
                                            label='Option',
                                            names=('opt', )),
                                  ]),
    }

    roles = {
        'cfg': XRefRole(),
        'sched': XRefRole(),
        'chsrc': XRefRole(),
        'step': XRefRole(),
        'status': 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("status", "Status Target Index"),
        make_index("cmdline", "Command Line Index"),
        make_index("msg", "MQ Routing Key Index"),
        make_index("event", "Data API Event Index"),
        make_index("rtype", "Data API Resource Type Index"),
        make_index("rpath", "Data API Path 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)
예제 #38
0
    def __init__(self, target_type):
        XRefRole.__init__(self)

        self.target_type = target_type
예제 #39
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', 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(docname, 'duplicate label %s, ' % name +
                         'other instance in ' + env.doc2path(labels[name][0]),
                         node.line)
            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
예제 #40
0
class EmacsLispDomain(Domain):
    """A domain to document Emacs Lisp symbols."""

    name = 'el'
    label = 'Emacs Lisp'
    object_types = {
        'function':
        ObjType('function', 'function', scope='function', searchprio=0),
        'macro':
        ObjType('macro', 'macro', scope='function', searchprio=0),
        'command':
        ObjType('command', 'command', scope='function', searchprio=1),
        'variable':
        ObjType('variable', 'variable', scope='variable', searchprio=0),
        'option':
        ObjType('user option', 'option', scope='variable', searchprio=1),
        'hook':
        ObjType('hook', 'hook', scope='variable', searchprio=0),
        'face':
        ObjType('face', 'face', scope='face', searchprio=0),
        'cl-struct':
        ObjType('CL struct', 'cl-struct', scope='struct', searchprio=0),
        'cl-slot':
        ObjType('slot', 'cl-slot', scope='function', searchprio=0)
    }
    directives = {
        'function': EmacsLispFunction,
        'macro': EmacsLispFunction,
        'command': EmacsLispCommand,
        'variable': EmacsLispSymbol,
        'option': EmacsLispSymbol,
        'hook': EmacsLispSymbol,
        'face': EmacsLispSymbol,
        'cl-struct': EmacsLispCLStruct,
        'cl-slot': EmacsLispCLSlot,
    }
    roles = {
        'symbol': XRefRole(),
        'function': XRefRole(),
        'macro': XRefRole(),
        'command': XRefRole(),
        'variable': XRefRole(),
        'option': XRefRole(),
        'hook': XRefRole(),
        'face': XRefRole(),
        'cl-struct': XRefRole(),
        'cl-slot': EmacsLispSlotXRefRole(),
        # Special markup roles
        'var': var_role,
        'varcode': varcode_role,
    }
    indices = []

    data_version = 2
    initial_data = {
        # fullname -> scope -> (docname, objtype)
        'symbols': {}
    }

    def clear_doc(self, docname):
        symbols = self.data['symbols']
        for symbol, scopes in symbols.items():
            for scope, (object_docname, _) in scopes.items():
                if docname == object_docname:
                    del symbols[symbol][scope]

    def resolve_xref(self, env, fromdoc, builder, objtype, target, node,
                     content):
        scopes = self.data['symbols'][target]
        if objtype == 'symbol' and len(scopes) > 1:
            # The generic symbol reference is ambiguous, because the symbol has
            # multiple scopes attached
            scope = next(
                ifilter(lambda s: s in scopes,
                        ['function', 'variable', 'face', 'struct']), None)
            if not scope:
                # If we have an unknown scope
                raise ValueError('Unknown scopes: {0!r}'.format(scopes))
            message = 'Ambiguous reference to {0}, in scopes {1}, using {2}'.format(
                target, ', '.join(scopes), scope)
            env.warn(fromdoc, message, getattr(node, 'line'))
        else:
            scope = self.object_types[objtype].attrs['scope']
        if scope not in scopes:
            return None
        docname, _ = scopes[scope]
        return make_refnode(builder, fromdoc, docname,
                            make_target(scope, target), content, target)

    def get_objects(self):
        for symbol, scopes in self.data['symbols'].iteritems():
            for scope, (docname, objtype) in scopes.iteritems():
                yield (symbol, symbol, objtype, docname,
                       make_target(scope, symbol),
                       self.object_types[objtype].attrs['searchprio'])
def setup(app):
    '''Extension setup'''

    # Javascript and stylesheet for the tree-view
    # app.add_javascript('jquery.js') #note: can only be included once
    app.add_javascript('https://cdn.rawgit.com/aexmachina/jquery-bonsai/master/jquery.bonsai.js')
    app.add_stylesheet('https://cdn.rawgit.com/aexmachina/jquery-bonsai/master/jquery.bonsai.css')
    app.add_javascript('traceability.js')

    # Configuration for exporting collection to json
    app.add_config_value('traceability_json_export_path',
                         None, 'env')

    # Configuration for adapting items through a callback
    app.add_config_value('traceability_callback_per_item',
                         None, 'env')

    # Create default attributes dictionary. Can be customized in conf.py
    app.add_config_value('traceability_attributes',
                         ['value', 'level', 'status'], 'env')

    # Create default relationships dictionary. Can be customized in conf.py
    app.add_config_value('traceability_relationships',
                         {'fulfills': 'fulfilled_by',
                          'depends_on': 'impacts_on',
                          'implements': 'implemented_by',
                          'realizes': 'realized_by',
                          'validates': 'validated_by',
                          'trace': 'backtrace',
                          'ext_toolname': ''},
                         'env')

    # Configuration for translating the relationship keywords to rendered text
    app.add_config_value('traceability_relationship_to_string',
                         {'fulfills': 'Fulfills',
                          'fulfilled_by': 'Fulfilled by',
                          'depends_on': 'Depends on',
                          'impacts_on': 'Impacts on',
                          'implements': 'Implements',
                          'implemented_by': 'Implemented by',
                          'realizes': 'Realizes',
                          'realized_by': 'Realized by',
                          'validates': 'Validates',
                          'validated_by': 'Validated by',
                          'trace': 'Traces',
                          'backtrace': 'Back traces',
                          'ext_toolname': 'Referento to toolname'},
                         'env')

    # Configuration for translating external relationship to url
    app.add_config_value('traceability_external_relationship_to_url',
                         {'ext_toolname': 'http://toolname.company.com/field1/workitem?field2'},
                         'env')

    # Configuration for enabling the rendering of the relations on every item
    app.add_config_value('traceability_render_relationship_per_item',
                         False, 'env')

    # Configuration for disabling the rendering of the captions for item
    app.add_config_value('traceability_item_no_captions',
                         False, 'env')

    # Configuration for disabling the rendering of the captions for item-list
    app.add_config_value('traceability_list_no_captions',
                         False, 'env')

    # Configuration for disabling the rendering of the captions for item-matrix
    app.add_config_value('traceability_matrix_no_captions',
                         False, 'env')

    # Configuration for disabling the rendering of the captions for item-tree
    app.add_config_value('traceability_tree_no_captions',
                         False, 'env')

    app.add_node(ItemTree)
    app.add_node(ItemMatrix)
    app.add_node(ItemList)
    app.add_node(Item)

    app.add_directive('item', ItemDirective)
    app.add_directive('item-list', ItemListDirective)
    app.add_directive('item-matrix', ItemMatrixDirective)
    app.add_directive('item-2d-matrix', Item2DMatrixDirective)
    app.add_directive('item-tree', ItemTreeDirective)

    app.connect('doctree-resolved', process_item_nodes)
    if sphinx_version >= '1.6.0':
        app.connect('env-check-consistency', perform_consistency_check)
    app.connect('builder-inited', initialize_environment)

    app.add_role('item', XRefRole(nodeclass=PendingItemXref,
                                  innernodeclass=nodes.emphasis,
                                  warn_dangling=True))