source: rtems-docs/common/sphinxcontrib/bibtex/__init__.py @ aa4f8e2

5
Last change on this file since aa4f8e2 was aa4f8e2, checked in by Chris Johns <chrisj@…>, on 08/07/17 at 11:58:52

Add the sphinxcontrib.bibtex extension to the repo.

  • Property mode set to 100644
File size: 5.1 KB
Line 
1# -*- coding: utf-8 -*-
2"""
3    Sphinx Interface
4    ~~~~~~~~~~~~~~~~
5
6    .. autofunction:: setup
7    .. autofunction:: init_bibtex_cache
8    .. autofunction:: purge_bibtex_cache
9    .. autofunction:: process_citations
10    .. autofunction:: process_citation_references
11    .. autofunction:: check_duplicate_labels
12"""
13
14import docutils.nodes
15import docutils.parsers.rst
16from sphinxcontrib.bibtex.cache import Cache
17from sphinxcontrib.bibtex.nodes import bibliography
18from sphinxcontrib.bibtex.roles import CiteRole
19from sphinxcontrib.bibtex.directives import BibliographyDirective
20from sphinxcontrib.bibtex.transforms import BibliographyTransform
21import six
22
23
24def init_bibtex_cache(app):
25    """Create ``app.env.bibtex_cache`` if it does not exist yet.
26
27    :param app: The sphinx application.
28    :type app: :class:`sphinx.application.Sphinx`
29    """
30    if not hasattr(app.env, "bibtex_cache"):
31        app.env.bibtex_cache = Cache()
32
33
34def purge_bibtex_cache(app, env, docname):
35    """Remove all information related to *docname* from the cache.
36
37    :param app: The sphinx application.
38    :type app: :class:`sphinx.application.Sphinx`
39    :param env: The sphinx build environment.
40    :type env: :class:`sphinx.environment.BuildEnvironment`
41    """
42    env.bibtex_cache.purge(docname)
43
44
45def process_citations(app, doctree, docname):
46    """Replace labels of citation nodes by actual labels.
47
48    :param app: The sphinx application.
49    :type app: :class:`sphinx.application.Sphinx`
50    :param doctree: The document tree.
51    :type doctree: :class:`docutils.nodes.document`
52    :param docname: The document name.
53    :type docname: :class:`str`
54    """
55    for node in doctree.traverse(docutils.nodes.citation):
56        key = node[0].astext()
57        try:
58            label = app.env.bibtex_cache.get_label_from_key(key)
59        except KeyError:
60            app.warn("could not relabel citation [%s]" % key)
61        else:
62            node[0] = docutils.nodes.label('', label)
63
64
65def process_citation_references(app, doctree, docname):
66    """Replace text of citation reference nodes by actual labels.
67
68    :param app: The sphinx application.
69    :type app: :class:`sphinx.application.Sphinx`
70    :param doctree: The document tree.
71    :type doctree: :class:`docutils.nodes.document`
72    :param docname: The document name.
73    :type docname: :class:`str`
74    """
75    # sphinx has already turned citation_reference nodes
76    # into reference nodes, so iterate over reference nodes
77    for node in doctree.traverse(docutils.nodes.reference):
78        # exclude sphinx [source] labels
79        if isinstance(node[0], docutils.nodes.Element):
80            if 'viewcode-link' in node[0]['classes']:
81                continue
82        text = node[0].astext()
83        if text.startswith('[') and text.endswith(']'):
84            key = text[1:-1]
85            try:
86                label = app.env.bibtex_cache.get_label_from_key(key)
87            except KeyError:
88                app.warn("could not relabel citation reference [%s]" % key)
89            else:
90                node[0] = docutils.nodes.Text('[' + label + ']')
91
92
93def check_duplicate_labels(app, env):
94    """Check and warn about duplicate citation labels.
95
96    :param app: The sphinx application.
97    :type app: :class:`sphinx.application.Sphinx`
98    :param env: The sphinx build environment.
99    :type env: :class:`sphinx.environment.BuildEnvironment`
100    """
101    label_to_key = {}
102    for info in env.bibtex_cache.get_all_bibliography_caches():
103        for key, label in six.iteritems(info.labels):
104            if label in label_to_key:
105                app.warn(
106                    "duplicate label for keys %s and %s"
107                    % (key, label_to_key[label]))
108            else:
109                label_to_key[label] = key
110
111
112def setup(app):
113    """Set up the bibtex extension:
114
115    * register config values
116    * register directives
117    * register nodes
118    * register roles
119    * register transforms
120    * connect events to functions
121
122    :param app: The sphinx application.
123    :type app: :class:`sphinx.application.Sphinx`
124    """
125
126    app.add_config_value("bibtex_default_style", "alpha", "html")
127    app.connect("builder-inited", init_bibtex_cache)
128    app.connect("doctree-resolved", process_citations)
129    app.connect("doctree-resolved", process_citation_references)
130    app.connect("env-purge-doc", purge_bibtex_cache)
131    app.connect("env-updated", check_duplicate_labels)
132
133    # docutils keeps state around during testing, so to avoid spurious
134    # warnings, we detect here whether the directives have already been
135    # registered... very ugly hack but no better solution so far
136    _directives = docutils.parsers.rst.directives._directives
137    if "bibliography" not in _directives:
138        app.add_directive("bibliography", BibliographyDirective)
139        app.add_role("cite", CiteRole())
140        app.add_node(bibliography)
141        app.add_transform(BibliographyTransform)
142    else:
143        assert _directives["bibliography"] is BibliographyDirective
144
145    # Parallel read is not safe at the moment: in the current design,
146    # the document that contains references must be read last for all
147    # references to be resolved.
148    return {'parallel_read_safe': False}
Note: See TracBrowser for help on using the repository browser.