buildframework/helium/external/python/lib/common/Sphinx-0.5.1-py2.5.egg/sphinx/environment.py
author wbernard
Wed, 23 Dec 2009 19:29:07 +0200
changeset 179 d8ac696cc51f
permissions -rw-r--r--
helium_7.0-r14027
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
179
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     1
# -*- coding: utf-8 -*-
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     2
"""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     3
    sphinx.environment
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     4
    ~~~~~~~~~~~~~~~~~~
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     5
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     6
    Global creation environment.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     7
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     8
    :copyright: 2007-2008 by Georg Brandl.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     9
    :license: BSD.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    10
"""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    11
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    12
import re
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    13
import os
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    14
import time
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    15
import heapq
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    16
import types
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    17
import imghdr
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    18
import difflib
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    19
import cPickle as pickle
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    20
from os import path
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    21
from glob import glob
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    22
from string import uppercase
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    23
from itertools import izip, groupby
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    24
try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    25
    import hashlib
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    26
    md5 = hashlib.md5
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    27
except ImportError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    28
    # 2.4 compatibility
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    29
    import md5
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    30
    md5 = md5.new
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    31
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    32
from docutils import nodes
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    33
from docutils.io import FileInput, NullOutput
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    34
from docutils.core import Publisher
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    35
from docutils.utils import Reporter, relative_path
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    36
from docutils.readers import standalone
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    37
from docutils.parsers.rst import roles
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    38
from docutils.parsers.rst.languages import en as english
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    39
from docutils.parsers.rst.directives.html import MetaBody
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    40
from docutils.writers import UnfilteredWriter
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    41
from docutils.transforms import Transform
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    42
from docutils.transforms.parts import ContentsFilter
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    43
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    44
from sphinx import addnodes
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    45
from sphinx.util import get_matching_docs, SEP, ustrftime
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    46
from sphinx.directives import additional_xref_types
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    47
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    48
default_settings = {
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    49
    'embed_stylesheet': False,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    50
    'cloak_email_addresses': True,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    51
    'pep_base_url': 'http://www.python.org/dev/peps/',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    52
    'rfc_base_url': 'http://rfc.net/',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    53
    'input_encoding': 'utf-8',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    54
    'doctitle_xform': False,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    55
    'sectsubtitle_xform': False,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    56
}
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    57
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    58
# This is increased every time an environment attribute is added
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    59
# or changed to properly invalidate pickle files.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    60
ENV_VERSION = 26
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    61
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    62
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    63
default_substitutions = set([
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    64
    'version',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    65
    'release',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    66
    'today',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    67
])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    68
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    69
dummy_reporter = Reporter('', 4, 4)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    70
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    71
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    72
class RedirStream(object):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    73
    def __init__(self, writefunc):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    74
        self.writefunc = writefunc
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    75
    def write(self, text):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    76
        if text.strip():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    77
            self.writefunc(text)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    78
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    79
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    80
class NoUri(Exception):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    81
    """Raised by get_relative_uri if there is no URI available."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    82
    pass
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    83
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    84
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    85
class DefaultSubstitutions(Transform):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    86
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    87
    Replace some substitutions if they aren't defined in the document.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    88
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    89
    # run before the default Substitutions
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    90
    default_priority = 210
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    91
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    92
    def apply(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    93
        config = self.document.settings.env.config
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    94
        # only handle those not otherwise defined in the document
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    95
        to_handle = default_substitutions - set(self.document.substitution_defs)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    96
        for ref in self.document.traverse(nodes.substitution_reference):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    97
            refname = ref['refname']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    98
            if refname in to_handle:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    99
                text = config[refname]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   100
                if refname == 'today' and not text:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   101
                    # special handling: can also specify a strftime format
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   102
                    text = ustrftime(config.today_fmt or _('%B %d, %Y'))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   103
                ref.replace_self(nodes.Text(text, text))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   104
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   105
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   106
class MoveModuleTargets(Transform):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   107
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   108
    Move module targets to their nearest enclosing section title.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   109
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   110
    default_priority = 210
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   111
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   112
    def apply(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   113
        for node in self.document.traverse(nodes.target):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   114
            if not node['ids']:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   115
                continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   116
            if node['ids'][0].startswith('module-') and \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   117
                   node.parent.__class__ is nodes.section:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   118
                node.parent['ids'] = node['ids']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   119
                node.parent.remove(node)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   120
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   121
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   122
class HandleCodeBlocks(Transform):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   123
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   124
    Move doctest blocks out of blockquotes.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   125
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   126
    default_priority = 210
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   127
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   128
    def apply(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   129
        for node in self.document.traverse(nodes.block_quote):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   130
            if len(node.children) == 1 and isinstance(node.children[0],
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   131
                                                      nodes.doctest_block):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   132
                node.replace_self(node.children[0])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   133
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   134
class CitationReferences(Transform):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   135
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   136
    Handle citation references before the default docutils transform does.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   137
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   138
    default_priority = 619
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   139
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   140
    def apply(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   141
        for citnode in self.document.traverse(nodes.citation_reference):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   142
            cittext = citnode.astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   143
            refnode = addnodes.pending_xref(cittext, reftype='citation',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   144
                                            reftarget=cittext)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   145
            refnode += nodes.Text('[' + cittext + ']')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   146
            citnode.parent.replace(citnode, refnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   147
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   148
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   149
class SphinxStandaloneReader(standalone.Reader):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   150
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   151
    Add our own transforms.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   152
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   153
    transforms = [CitationReferences, DefaultSubstitutions, MoveModuleTargets,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   154
                  HandleCodeBlocks]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   155
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   156
    def get_transforms(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   157
        return standalone.Reader.get_transforms(self) + self.transforms
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   158
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   159
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   160
class SphinxDummyWriter(UnfilteredWriter):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   161
    supported = ('html',)  # needed to keep "meta" nodes
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   162
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   163
    def translate(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   164
        pass
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   165
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   166
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   167
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   168
class SphinxContentsFilter(ContentsFilter):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   169
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   170
    Used with BuildEnvironment.add_toc_from() to discard cross-file links
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   171
    within table-of-contents link nodes.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   172
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   173
    def visit_pending_xref(self, node):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   174
        text = node.astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   175
        self.parent.append(nodes.literal(text, text))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   176
        raise nodes.SkipNode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   177
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   178
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   179
class BuildEnvironment:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   180
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   181
    The environment in which the ReST files are translated.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   182
    Stores an inventory of cross-file targets and provides doctree
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   183
    transformations to resolve links to them.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   184
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   185
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   186
    # --------- ENVIRONMENT PERSISTENCE ----------------------------------------
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   187
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   188
    @staticmethod
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   189
    def frompickle(config, filename):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   190
        picklefile = open(filename, 'rb')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   191
        try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   192
            env = pickle.load(picklefile)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   193
        finally:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   194
            picklefile.close()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   195
        env.config.values = config.values
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   196
        if env.version != ENV_VERSION:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   197
            raise IOError('env version not current')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   198
        return env
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   199
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   200
    def topickle(self, filename):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   201
        # remove unpicklable attributes
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   202
        warnfunc = self._warnfunc
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   203
        self.set_warnfunc(None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   204
        values = self.config.values
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   205
        del self.config.values
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   206
        picklefile = open(filename, 'wb')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   207
        # remove potentially pickling-problematic values from config
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   208
        for key, val in vars(self.config).items():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   209
            if key.startswith('_') or \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   210
                   isinstance(val, types.ModuleType) or \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   211
                   isinstance(val, types.FunctionType) or \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   212
                   isinstance(val, (type, types.ClassType)):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   213
                del self.config[key]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   214
        try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   215
            pickle.dump(self, picklefile, pickle.HIGHEST_PROTOCOL)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   216
        finally:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   217
            picklefile.close()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   218
        # reset attributes
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   219
        self.config.values = values
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   220
        self.set_warnfunc(warnfunc)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   221
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   222
    # --------- ENVIRONMENT INITIALIZATION -------------------------------------
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   223
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   224
    def __init__(self, srcdir, doctreedir, config):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   225
        self.doctreedir = doctreedir
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   226
        self.srcdir = srcdir
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   227
        self.config = config
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   228
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   229
        # the application object; only set while update() runs
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   230
        self.app = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   231
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   232
        # the docutils settings for building
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   233
        self.settings = default_settings.copy()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   234
        self.settings['env'] = self
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   235
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   236
        # the function to write warning messages with
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   237
        self._warnfunc = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   238
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   239
        # this is to invalidate old pickles
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   240
        self.version = ENV_VERSION
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   241
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   242
        # All "docnames" here are /-separated and relative and exclude the source suffix.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   243
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   244
        self.found_docs = set()     # contains all existing docnames
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   245
        self.all_docs = {}          # docname -> mtime at the time of build
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   246
                                    # contains all built docnames
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   247
        self.dependencies = {}      # docname -> set of dependent file names, relative to
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   248
                                    # documentation root
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   249
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   250
        # File metadata
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   251
        self.metadata = {}          # docname -> dict of metadata items
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   252
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   253
        # TOC inventory
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   254
        self.titles = {}            # docname -> title node
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   255
        self.tocs = {}              # docname -> table of contents nodetree
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   256
        self.toc_num_entries = {}   # docname -> number of real entries
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   257
                                    # used to determine when to show the TOC in a sidebar
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   258
                                    # (don't show if it's only one item)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   259
        self.toctree_includes = {}  # docname -> list of toctree includefiles
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   260
        self.files_to_rebuild = {}  # docname -> set of files (containing its TOCs)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   261
                                    # to rebuild too
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   262
        self.glob_toctrees = set()  # docnames that have :glob: toctrees
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   263
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   264
        # X-ref target inventory
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   265
        self.descrefs = {}          # fullname -> docname, desctype
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   266
        self.filemodules = {}       # docname -> [modules]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   267
        self.modules = {}           # modname -> docname, synopsis, platform, deprecated
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   268
        self.labels = {}            # labelname -> docname, labelid, sectionname
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   269
        self.anonlabels = {}        # labelname -> docname, labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   270
        self.progoptions = {}       # (program, name) -> docname, labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   271
        self.reftargets = {}        # (type, name) -> docname, labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   272
                                    # where type is term, token, envvar, citation
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   273
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   274
        # Other inventories
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   275
        self.indexentries = {}      # docname -> list of
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   276
                                    # (type, string, target, aliasname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   277
        self.versionchanges = {}    # version -> list of
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   278
                                    # (type, docname, lineno, module, descname, content)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   279
        self.images = {}            # absolute path -> (docnames, unique filename)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   280
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   281
        # These are set while parsing a file
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   282
        self.docname = None         # current document name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   283
        self.currmodule = None      # current module name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   284
        self.currclass = None       # current class name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   285
        self.currdesc = None        # current descref name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   286
        self.currprogram = None     # current program name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   287
        self.index_num = 0          # autonumber for index targets
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   288
        self.gloss_entries = set()  # existing definition labels
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   289
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   290
        # Some magically present labels
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   291
        self.labels['genindex'] = ('genindex', '', _('Index'))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   292
        self.labels['modindex'] = ('modindex', '', _('Module Index'))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   293
        self.labels['search']   = ('search', '', _('Search Page'))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   294
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   295
    def set_warnfunc(self, func):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   296
        self._warnfunc = func
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   297
        self.settings['warning_stream'] = RedirStream(func)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   298
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   299
    def warn(self, docname, msg, lineno=None):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   300
        if docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   301
            if lineno is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   302
                lineno = ''
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   303
            self._warnfunc('%s:%s: %s' % (self.doc2path(docname), lineno, msg))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   304
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   305
            self._warnfunc('GLOBAL:: ' + msg)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   306
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   307
    def clear_doc(self, docname):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   308
        """Remove all traces of a source file in the inventory."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   309
        if docname in self.all_docs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   310
            self.all_docs.pop(docname, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   311
            self.metadata.pop(docname, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   312
            self.dependencies.pop(docname, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   313
            self.titles.pop(docname, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   314
            self.tocs.pop(docname, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   315
            self.toc_num_entries.pop(docname, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   316
            self.toctree_includes.pop(docname, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   317
            self.filemodules.pop(docname, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   318
            self.indexentries.pop(docname, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   319
            self.glob_toctrees.discard(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   320
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   321
            for subfn, fnset in self.files_to_rebuild.items():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   322
                fnset.discard(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   323
                if not fnset:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   324
                    del self.files_to_rebuild[subfn]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   325
            for fullname, (fn, _) in self.descrefs.items():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   326
                if fn == docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   327
                    del self.descrefs[fullname]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   328
            for modname, (fn, _, _, _) in self.modules.items():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   329
                if fn == docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   330
                    del self.modules[modname]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   331
            for labelname, (fn, _, _) in self.labels.items():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   332
                if fn == docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   333
                    del self.labels[labelname]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   334
            for key, (fn, _) in self.reftargets.items():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   335
                if fn == docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   336
                    del self.reftargets[key]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   337
            for key, (fn, _) in self.progoptions.items():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   338
                if fn == docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   339
                    del self.progoptions[key]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   340
            for version, changes in self.versionchanges.items():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   341
                new = [change for change in changes if change[1] != docname]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   342
                changes[:] = new
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   343
            for fullpath, (docs, _) in self.images.items():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   344
                docs.discard(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   345
                if not docs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   346
                    del self.images[fullpath]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   347
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   348
    def doc2path(self, docname, base=True, suffix=None):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   349
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   350
        Return the filename for the document name.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   351
        If base is True, return absolute path under self.srcdir.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   352
        If base is None, return relative path to self.srcdir.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   353
        If base is a path string, return absolute path under that.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   354
        If suffix is not None, add it instead of config.source_suffix.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   355
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   356
        suffix = suffix or self.config.source_suffix
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   357
        if base is True:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   358
            return path.join(self.srcdir, docname.replace(SEP, path.sep)) + suffix
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   359
        elif base is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   360
            return docname.replace(SEP, path.sep) + suffix
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   361
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   362
            return path.join(base, docname.replace(SEP, path.sep)) + suffix
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   363
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   364
    def find_files(self, config):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   365
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   366
        Find all source files in the source dir and put them in self.found_docs.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   367
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   368
        exclude_dirs  = [d.replace(SEP, path.sep) for d in config.exclude_dirs]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   369
        exclude_trees = [d.replace(SEP, path.sep) for d in config.exclude_trees]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   370
        self.found_docs = set(get_matching_docs(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   371
            self.srcdir, config.source_suffix, exclude_docs=set(config.unused_docs),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   372
            exclude_dirs=exclude_dirs, exclude_trees=exclude_trees,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   373
            exclude_dirnames=['_sources'] + config.exclude_dirnames))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   374
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   375
    def get_outdated_files(self, config_changed):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   376
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   377
        Return (added, changed, removed) sets.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   378
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   379
        # clear all files no longer present
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   380
        removed = set(self.all_docs) - self.found_docs
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   381
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   382
        added = set()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   383
        changed = set()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   384
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   385
        if config_changed:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   386
            # config values affect e.g. substitutions
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   387
            added = self.found_docs
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   388
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   389
            for docname in self.found_docs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   390
                if docname not in self.all_docs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   391
                    added.add(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   392
                    continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   393
                # if the doctree file is not there, rebuild
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   394
                if not path.isfile(self.doc2path(docname, self.doctreedir,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   395
                                                 '.doctree')):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   396
                    changed.add(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   397
                    continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   398
                # check the mtime of the document
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   399
                mtime = self.all_docs[docname]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   400
                newmtime = path.getmtime(self.doc2path(docname))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   401
                if newmtime > mtime:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   402
                    changed.add(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   403
                    continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   404
                # finally, check the mtime of dependencies
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   405
                for dep in self.dependencies.get(docname, ()):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   406
                    try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   407
                        # this will do the right thing when dep is absolute too
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   408
                        deppath = path.join(self.srcdir, dep)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   409
                        if not path.isfile(deppath):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   410
                            changed.add(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   411
                            break
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   412
                        depmtime = path.getmtime(deppath)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   413
                        if depmtime > mtime:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   414
                            changed.add(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   415
                            break
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   416
                    except EnvironmentError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   417
                        # give it another chance
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   418
                        changed.add(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   419
                        break
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   420
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   421
        return added, changed, removed
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   422
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   423
    def update(self, config, srcdir, doctreedir, app=None):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   424
        """(Re-)read all files new or changed since last update.  Yields a summary
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   425
        and then docnames as it processes them.  Store all environment docnames
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   426
        in the canonical format (ie using SEP as a separator in place of
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   427
        os.path.sep)."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   428
        config_changed = False
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   429
        if self.config is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   430
            msg = '[new config] '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   431
            config_changed = True
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   432
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   433
            # check if a config value was changed that affects how doctrees are read
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   434
            for key, descr in config.config_values.iteritems():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   435
                if not descr[1]:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   436
                    continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   437
                if self.config[key] != config[key]:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   438
                    msg = '[config changed] '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   439
                    config_changed = True
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   440
                    break
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   441
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   442
                msg = ''
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   443
            # this value is not covered by the above loop because it is handled
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   444
            # specially by the config class
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   445
            if self.config.extensions != config.extensions:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   446
                msg = '[extensions changed] '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   447
                config_changed = True
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   448
        # the source and doctree directories may have been relocated
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   449
        self.srcdir = srcdir
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   450
        self.doctreedir = doctreedir
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   451
        self.find_files(config)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   452
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   453
        added, changed, removed = self.get_outdated_files(config_changed)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   454
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   455
        # if files were added or removed, all documents with globbed toctrees
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   456
        # must be reread
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   457
        if added or removed:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   458
            changed.update(self.glob_toctrees)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   459
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   460
        msg += '%s added, %s changed, %s removed' % (len(added), len(changed),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   461
                                                     len(removed))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   462
        yield msg
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   463
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   464
        self.config = config
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   465
        self.app = app
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   466
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   467
        # clear all files no longer present
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   468
        for docname in removed:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   469
            if app:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   470
                app.emit('env-purge-doc', self, docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   471
            self.clear_doc(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   472
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   473
        # read all new and changed files
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   474
        for docname in sorted(added | changed):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   475
            yield docname
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   476
            self.read_doc(docname, app=app)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   477
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   478
        if config.master_doc not in self.all_docs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   479
            self.warn(None, 'master file %s not found' %
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   480
                      self.doc2path(config.master_doc))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   481
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   482
        self.app = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   483
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   484
        # remove all non-existing images from inventory
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   485
        for imgsrc in self.images.keys():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   486
            if not os.access(path.join(self.srcdir, imgsrc), os.R_OK):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   487
                del self.images[imgsrc]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   488
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   489
        if app:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   490
            app.emit('env-updated', self)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   491
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   492
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   493
    # --------- SINGLE FILE READING --------------------------------------------
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   494
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   495
    def read_doc(self, docname, src_path=None, save_parsed=True, app=None):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   496
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   497
        Parse a file and add/update inventory entries for the doctree.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   498
        If srcpath is given, read from a different source file.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   499
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   500
        # remove all inventory entries for that file
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   501
        if app:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   502
            app.emit('env-purge-doc', self, docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   503
        self.clear_doc(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   504
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   505
        if src_path is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   506
            src_path = self.doc2path(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   507
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   508
        if self.config.default_role:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   509
            role_fn, messages = roles.role(self.config.default_role, english,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   510
                                           0, dummy_reporter)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   511
            if role_fn:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   512
                roles._roles[''] = role_fn
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   513
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   514
                self.warn(docname, 'default role %s not found' %
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   515
                          self.config.default_role)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   516
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   517
        self.docname = docname
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   518
        self.settings['input_encoding'] = self.config.source_encoding
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   519
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   520
        class SphinxSourceClass(FileInput):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   521
            def read(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   522
                data = FileInput.read(self)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   523
                if app:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   524
                    arg = [data]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   525
                    app.emit('source-read', docname, arg)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   526
                    data = arg[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   527
                return data
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   528
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   529
        # publish manually
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   530
        pub = Publisher(reader=SphinxStandaloneReader(),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   531
                        writer=SphinxDummyWriter(),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   532
                        source_class=SphinxSourceClass,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   533
                        destination_class=NullOutput)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   534
        pub.set_components(None, 'restructuredtext', None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   535
        pub.process_programmatic_settings(None, self.settings, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   536
        pub.set_source(None, src_path)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   537
        pub.set_destination(None, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   538
        try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   539
            pub.publish()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   540
            doctree = pub.document
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   541
        except UnicodeError, err:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   542
            from sphinx.application import SphinxError
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   543
            raise SphinxError(err.message)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   544
        self.filter_messages(doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   545
        self.process_dependencies(docname, doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   546
        self.process_images(docname, doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   547
        self.process_metadata(docname, doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   548
        self.create_title_from(docname, doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   549
        self.note_labels_from(docname, doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   550
        self.note_indexentries_from(docname, doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   551
        self.note_citations_from(docname, doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   552
        self.build_toc_from(docname, doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   553
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   554
        # store time of reading, used to find outdated files
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   555
        self.all_docs[docname] = time.time()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   556
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   557
        if app:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   558
            app.emit('doctree-read', doctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   559
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   560
        # make it picklable
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   561
        doctree.reporter = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   562
        doctree.transformer = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   563
        doctree.settings.warning_stream = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   564
        doctree.settings.env = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   565
        doctree.settings.record_dependencies = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   566
        for metanode in doctree.traverse(MetaBody.meta):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   567
            # docutils' meta nodes aren't picklable because the class is nested
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   568
            metanode.__class__ = addnodes.meta
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   569
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   570
        # cleanup
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   571
        self.docname = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   572
        self.currmodule = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   573
        self.currclass = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   574
        self.gloss_entries = set()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   575
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   576
        if save_parsed:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   577
            # save the parsed doctree
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   578
            doctree_filename = self.doc2path(docname, self.doctreedir, '.doctree')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   579
            dirname = path.dirname(doctree_filename)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   580
            if not path.isdir(dirname):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   581
                os.makedirs(dirname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   582
            f = open(doctree_filename, 'wb')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   583
            try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   584
                pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   585
            finally:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   586
                f.close()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   587
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   588
            return doctree
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   589
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   590
    def filter_messages(self, doctree):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   591
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   592
        Filter system messages from a doctree.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   593
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   594
        filterlevel = self.config.keep_warnings and 2 or 5
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   595
        for node in doctree.traverse(nodes.system_message):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   596
            if node['level'] < filterlevel:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   597
                node.parent.remove(node)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   598
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   599
    def process_dependencies(self, docname, doctree):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   600
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   601
        Process docutils-generated dependency info.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   602
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   603
        deps = doctree.settings.record_dependencies
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   604
        if not deps:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   605
            return
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   606
        docdir = path.dirname(self.doc2path(docname, base=None))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   607
        for dep in deps.list:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   608
            dep = path.join(docdir, dep)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   609
            self.dependencies.setdefault(docname, set()).add(dep)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   610
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   611
    def process_images(self, docname, doctree):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   612
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   613
        Process and rewrite image URIs.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   614
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   615
        existing_names = set(v[1] for v in self.images.itervalues())
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   616
        docdir = path.dirname(self.doc2path(docname, base=None))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   617
        for node in doctree.traverse(nodes.image):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   618
            # Map the mimetype to the corresponding image.  The writer may
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   619
            # choose the best image from these candidates.  The special key * is
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   620
            # set if there is only single candiate to be used by a writer.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   621
            # The special key ? is set for nonlocal URIs.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   622
            node['candidates'] = candidates = {}
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   623
            imguri = node['uri']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   624
            if imguri.find('://') != -1:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   625
                self.warn(docname, 'Nonlocal image URI found: %s' % imguri, node.line)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   626
                candidates['?'] = imguri
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   627
                continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   628
            # imgpath is the image path *from srcdir*
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   629
            imgpath = path.normpath(path.join(docdir, imguri))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   630
            # set imgpath as default URI
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   631
            node['uri'] = imgpath
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   632
            if imgpath.endswith(os.extsep + '*'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   633
                for filename in glob(path.join(self.srcdir, imgpath)):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   634
                    new_imgpath = relative_path(self.srcdir, filename)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   635
                    if filename.lower().endswith('.pdf'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   636
                        candidates['application/pdf'] = new_imgpath
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   637
                    elif filename.lower().endswith('.svg'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   638
                        candidates['image/svg+xml'] = new_imgpath
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   639
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   640
                        try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   641
                            f = open(filename, 'rb')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   642
                            try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   643
                                imgtype = imghdr.what(f)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   644
                            finally:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   645
                                f.close()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   646
                        except (OSError, IOError):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   647
                            self.warn(docname, 'Image file %s not readable' % filename)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   648
                        if imgtype:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   649
                            candidates['image/' + imgtype] = new_imgpath
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   650
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   651
                candidates['*'] = imgpath
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   652
            # map image paths to unique image names (so that they can be put
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   653
            # into a single directory)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   654
            for imgpath in candidates.itervalues():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   655
                self.dependencies.setdefault(docname, set()).add(imgpath)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   656
                if not os.access(path.join(self.srcdir, imgpath), os.R_OK):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   657
                    self.warn(docname, 'Image file not readable: %s' % imgpath,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   658
                              node.line)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   659
                if imgpath in self.images:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   660
                    self.images[imgpath][0].add(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   661
                    continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   662
                uniquename = path.basename(imgpath)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   663
                base, ext = path.splitext(uniquename)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   664
                i = 0
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   665
                while uniquename in existing_names:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   666
                    i += 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   667
                    uniquename = '%s%s%s' % (base, i, ext)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   668
                self.images[imgpath] = (set([docname]), uniquename)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   669
                existing_names.add(uniquename)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   670
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   671
    def process_metadata(self, docname, doctree):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   672
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   673
        Process the docinfo part of the doctree as metadata.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   674
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   675
        self.metadata[docname] = md = {}
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   676
        try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   677
            docinfo = doctree[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   678
        except IndexError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   679
            # probably an empty document
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   680
            return
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   681
        if docinfo.__class__ is not nodes.docinfo:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   682
            # nothing to see here
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   683
            return
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   684
        for node in docinfo:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   685
            if node.__class__ is nodes.author:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   686
                # handled specially by docutils
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   687
                md['author'] = node.astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   688
            elif node.__class__ is nodes.field:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   689
                name, body = node
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   690
                md[name.astext()] = body.astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   691
        del doctree[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   692
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   693
    def create_title_from(self, docname, document):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   694
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   695
        Add a title node to the document (just copy the first section title),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   696
        and store that title in the environment.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   697
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   698
        for node in document.traverse(nodes.section):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   699
            titlenode = nodes.title()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   700
            visitor = SphinxContentsFilter(document)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   701
            node[0].walkabout(visitor)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   702
            titlenode += visitor.get_entry_text()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   703
            self.titles[docname] = titlenode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   704
            return
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   705
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   706
    def note_labels_from(self, docname, document):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   707
        for name, explicit in document.nametypes.iteritems():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   708
            if not explicit:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   709
                continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   710
            labelid = document.nameids[name]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   711
            if labelid is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   712
                continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   713
            node = document.ids[labelid]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   714
            if name.isdigit() or node.has_key('refuri') or \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   715
                   node.tagname.startswith('desc_'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   716
                # ignore footnote labels, labels automatically generated from a
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   717
                # link and description units
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   718
                continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   719
            if name in self.labels:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   720
                self.warn(docname, 'duplicate label %s, ' % name +
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   721
                          'other instance in %s' % self.doc2path(self.labels[name][0]),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   722
                          node.line)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   723
            self.anonlabels[name] = docname, labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   724
            if node.tagname == 'section':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   725
                sectname = node[0].astext() # node[0] == title node
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   726
            elif node.tagname == 'figure':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   727
                for n in node:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   728
                    if n.tagname == 'caption':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   729
                        sectname = n.astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   730
                        break
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   731
                else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   732
                    continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   733
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   734
                # anonymous-only labels
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   735
                continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   736
            self.labels[name] = docname, labelid, sectname
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   737
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   738
    def note_indexentries_from(self, docname, document):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   739
        entries = self.indexentries[docname] = []
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   740
        for node in document.traverse(addnodes.index):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   741
            entries.extend(node['entries'])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   742
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   743
    def note_citations_from(self, docname, document):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   744
        for node in document.traverse(nodes.citation):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   745
            label = node[0].astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   746
            if ('citation', label) in self.reftargets:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   747
                self.warn(docname, 'duplicate citation %s, ' % label +
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   748
                          'other instance in %s' % self.doc2path(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   749
                    self.reftargets['citation', label][0]), node.line)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   750
            self.reftargets['citation', label] = (docname, node['ids'][0])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   751
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   752
    def note_toctree(self, docname, toctreenode):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   753
        """Note a TOC tree directive in a document and gather information about
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   754
           file relations from it."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   755
        if toctreenode['glob']:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   756
            self.glob_toctrees.add(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   757
        includefiles = toctreenode['includefiles']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   758
        for includefile in includefiles:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   759
            # note that if the included file is rebuilt, this one must be
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   760
            # too (since the TOC of the included file could have changed)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   761
            self.files_to_rebuild.setdefault(includefile, set()).add(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   762
        self.toctree_includes.setdefault(docname, []).extend(includefiles)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   763
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   764
    def build_toc_from(self, docname, document):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   765
        """Build a TOC from the doctree and store it in the inventory."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   766
        numentries = [0] # nonlocal again...
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   767
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   768
        try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   769
            maxdepth = int(self.metadata[docname].get('tocdepth', 0))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   770
        except ValueError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   771
            maxdepth = 0
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   772
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   773
        def build_toc(node, depth=1):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   774
            entries = []
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   775
            for subnode in node:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   776
                if isinstance(subnode, addnodes.toctree):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   777
                    # just copy the toctree node which is then resolved
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   778
                    # in self.get_and_resolve_doctree
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   779
                    item = subnode.copy()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   780
                    entries.append(item)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   781
                    # do the inventory stuff
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   782
                    self.note_toctree(docname, subnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   783
                    continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   784
                if not isinstance(subnode, nodes.section):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   785
                    continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   786
                title = subnode[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   787
                # copy the contents of the section title, but without references
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   788
                # and unnecessary stuff
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   789
                visitor = SphinxContentsFilter(document)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   790
                title.walkabout(visitor)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   791
                nodetext = visitor.get_entry_text()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   792
                if not numentries[0]:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   793
                    # for the very first toc entry, don't add an anchor
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   794
                    # as it is the file's title anyway
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   795
                    anchorname = ''
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   796
                else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   797
                    anchorname = '#' + subnode['ids'][0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   798
                numentries[0] += 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   799
                reference = nodes.reference('', '', refuri=docname,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   800
                                            anchorname=anchorname,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   801
                                            *nodetext)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   802
                para = addnodes.compact_paragraph('', '', reference)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   803
                item = nodes.list_item('', para)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   804
                if maxdepth == 0 or depth < maxdepth:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   805
                    item += build_toc(subnode, depth+1)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   806
                entries.append(item)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   807
            if entries:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   808
                return nodes.bullet_list('', *entries)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   809
            return []
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   810
        toc = build_toc(document)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   811
        if toc:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   812
            self.tocs[docname] = toc
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   813
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   814
            self.tocs[docname] = nodes.bullet_list('')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   815
        self.toc_num_entries[docname] = numentries[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   816
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   817
    def get_toc_for(self, docname):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   818
        """Return a TOC nodetree -- for use on the same page only!"""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   819
        toc = self.tocs[docname].deepcopy()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   820
        for node in toc.traverse(nodes.reference):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   821
            node['refuri'] = node['anchorname']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   822
        return toc
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   823
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   824
    # -------
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   825
    # these are called from docutils directives and therefore use self.docname
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   826
    #
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   827
    def note_descref(self, fullname, desctype, line):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   828
        if fullname in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   829
            self.warn(self.docname,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   830
                      'duplicate canonical description name %s, ' % fullname +
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   831
                      'other instance in %s' % self.doc2path(self.descrefs[fullname][0]),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   832
                      line)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   833
        self.descrefs[fullname] = (self.docname, desctype)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   834
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   835
    def note_module(self, modname, synopsis, platform, deprecated):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   836
        self.modules[modname] = (self.docname, synopsis, platform, deprecated)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   837
        self.filemodules.setdefault(self.docname, []).append(modname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   838
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   839
    def note_progoption(self, optname, labelid):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   840
        self.progoptions[self.currprogram, optname] = (self.docname, labelid)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   841
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   842
    def note_reftarget(self, type, name, labelid):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   843
        self.reftargets[type, name] = (self.docname, labelid)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   844
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   845
    def note_versionchange(self, type, version, node, lineno):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   846
        self.versionchanges.setdefault(version, []).append(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   847
            (type, self.docname, lineno, self.currmodule, self.currdesc, node.astext()))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   848
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   849
    def note_dependency(self, filename):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   850
        basename = path.dirname(self.doc2path(self.docname, base=None))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   851
        # this will do the right thing when filename is absolute too
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   852
        filename = path.join(basename, filename)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   853
        self.dependencies.setdefault(self.docname, set()).add(filename)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   854
    # -------
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   855
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   856
    # --------- RESOLVING REFERENCES AND TOCTREES ------------------------------
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   857
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   858
    def get_doctree(self, docname):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   859
        """Read the doctree for a file from the pickle and return it."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   860
        doctree_filename = self.doc2path(docname, self.doctreedir, '.doctree')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   861
        f = open(doctree_filename, 'rb')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   862
        try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   863
            doctree = pickle.load(f)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   864
        finally:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   865
            f.close()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   866
        doctree.settings.env = self
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   867
        doctree.reporter = Reporter(self.doc2path(docname), 2, 4,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   868
                                    stream=RedirStream(self._warnfunc))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   869
        return doctree
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   870
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   871
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   872
    def get_and_resolve_doctree(self, docname, builder, doctree=None,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   873
                                prune_toctrees=True):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   874
        """Read the doctree from the pickle, resolve cross-references and
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   875
           toctrees and return it."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   876
        if doctree is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   877
            doctree = self.get_doctree(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   878
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   879
        # resolve all pending cross-references
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   880
        self.resolve_references(doctree, docname, builder)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   881
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   882
        # now, resolve all toctree nodes
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   883
        for toctreenode in doctree.traverse(addnodes.toctree):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   884
            result = self.resolve_toctree(docname, builder, toctreenode,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   885
                                          prune=prune_toctrees)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   886
            if result is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   887
                toctreenode.replace_self([])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   888
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   889
                toctreenode.replace_self(result)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   890
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   891
        return doctree
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   892
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   893
    def resolve_toctree(self, docname, builder, toctree, prune=True, maxdepth=0,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   894
                        titles_only=False):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   895
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   896
        Resolve a *toctree* node into individual bullet lists with titles
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   897
        as items, returning None (if no containing titles are found) or
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   898
        a new node.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   899
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   900
        If *prune* is True, the tree is pruned to *maxdepth*, or if that is 0,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   901
        to the value of the *maxdepth* option on the *toctree* node.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   902
        If *titles_only* is True, only toplevel document titles will be in the
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   903
        resulting tree.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   904
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   905
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   906
        def _walk_depth(node, depth, maxdepth, titleoverrides):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   907
            """Utility: Cut a TOC at a specified depth."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   908
            for subnode in node.children[:]:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   909
                if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   910
                    subnode['classes'].append('toctree-l%d' % (depth-1))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   911
                    _walk_depth(subnode, depth, maxdepth, titleoverrides)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   912
                elif isinstance(subnode, nodes.bullet_list):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   913
                    if maxdepth > 0 and depth > maxdepth:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   914
                        subnode.parent.replace(subnode, [])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   915
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   916
                        _walk_depth(subnode, depth+1, maxdepth, titleoverrides)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   917
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   918
        def _entries_from_toctree(toctreenode, separate=False):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   919
            """Return TOC entries for a toctree node."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   920
            includefiles = map(str, toctreenode['includefiles'])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   921
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   922
            entries = []
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   923
            for includefile in includefiles:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   924
                try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   925
                    toc = self.tocs[includefile].deepcopy()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   926
                    if not toc.children:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   927
                        # empty toc means: no titles will show up in the toctree
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   928
                        self.warn(docname, 'toctree contains reference to document '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   929
                                  '%r that doesn\'t have a title: no link will be '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   930
                                  'generated' % includefile)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   931
                except KeyError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   932
                    # this is raised if the included file does not exist
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   933
                    self.warn(docname, 'toctree contains reference to nonexisting '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   934
                              'document %r' % includefile)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   935
                else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   936
                    # if titles_only is given, only keep the main title and
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   937
                    # sub-toctrees
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   938
                    if titles_only:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   939
                        # delete everything but the toplevel title(s) and toctrees
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   940
                        for toplevel in toc:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   941
                            # nodes with length 1 don't have any children anyway
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   942
                            if len(toplevel) > 1:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   943
                                subtoctrees = toplevel.traverse(addnodes.toctree)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   944
                                toplevel[1][:] = subtoctrees
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   945
                    # resolve all sub-toctrees
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   946
                    for toctreenode in toc.traverse(addnodes.toctree):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   947
                        i = toctreenode.parent.index(toctreenode) + 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   948
                        for item in _entries_from_toctree(toctreenode):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   949
                            toctreenode.parent.insert(i, item)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   950
                            i += 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   951
                        toctreenode.parent.remove(toctreenode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   952
                    if separate:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   953
                        entries.append(toc)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   954
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   955
                        entries.extend(toc.children)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   956
            return entries
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   957
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   958
        maxdepth = maxdepth or toctree.get('maxdepth', -1)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   959
        titleoverrides = toctree.get('includetitles', {})
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   960
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   961
        tocentries = _entries_from_toctree(toctree, separate=True)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   962
        if not tocentries:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   963
            return None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   964
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   965
        newnode = addnodes.compact_paragraph('', '', *tocentries)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   966
        newnode['toctree'] = True
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   967
        # prune the tree to maxdepth and replace titles, also set level classes
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   968
        _walk_depth(newnode, 1, prune and maxdepth or 0, titleoverrides)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   969
        # replace titles, if needed, and set the target paths in the
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   970
        # toctrees (they are not known at TOC generation time)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   971
        for refnode in newnode.traverse(nodes.reference):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   972
            refnode['refuri'] = builder.get_relative_uri(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   973
                docname, refnode['refuri']) + refnode['anchorname']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   974
            if titleoverrides and not refnode['anchorname'] \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   975
                   and refnode['refuri'] in titleoverrides:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   976
                newtitle = titleoverrides[refnode['refuri']]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   977
                refnode.children = [nodes.Text(newtitle)]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   978
        return newnode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   979
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   980
    descroles = frozenset(('data', 'exc', 'func', 'class', 'const', 'attr', 'obj',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   981
                           'meth', 'cfunc', 'cmember', 'cdata', 'ctype', 'cmacro'))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   982
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   983
    def resolve_references(self, doctree, fromdocname, builder):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   984
        reftarget_roles = set(('token', 'term', 'citation'))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   985
        # add all custom xref types too
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   986
        reftarget_roles.update(i[0] for i in additional_xref_types.values())
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   987
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   988
        for node in doctree.traverse(addnodes.pending_xref):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   989
            contnode = node[0].deepcopy()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   990
            newnode = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   991
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   992
            typ = node['reftype']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   993
            target = node['reftarget']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   994
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   995
            try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   996
                if typ == 'ref':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   997
                    if node['refcaption']:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   998
                        # reference to anonymous label; the reference uses the supplied
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   999
                        # link caption
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1000
                        docname, labelid = self.anonlabels.get(target, ('',''))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1001
                        sectname = node.astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1002
                        if not docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1003
                            newnode = doctree.reporter.system_message(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1004
                                2, 'undefined label: %s' % target)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1005
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1006
                        # reference to the named label; the final node will contain the
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1007
                        # section name after the label
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1008
                        docname, labelid, sectname = self.labels.get(target, ('','',''))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1009
                        if not docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1010
                            newnode = doctree.reporter.system_message(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1011
                                2, 'undefined label: %s -- if you don\'t ' % target +
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1012
                                'give a link caption the label must precede a section '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1013
                                'header.')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1014
                    if docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1015
                        newnode = nodes.reference('', '')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1016
                        innernode = nodes.emphasis(sectname, sectname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1017
                        if docname == fromdocname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1018
                            newnode['refid'] = labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1019
                        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1020
                            # set more info in contnode in case the get_relative_uri call
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1021
                            # raises NoUri, the builder will then have to resolve these
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1022
                            contnode = addnodes.pending_xref('')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1023
                            contnode['refdocname'] = docname
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1024
                            contnode['refsectname'] = sectname
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1025
                            newnode['refuri'] = builder.get_relative_uri(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1026
                                fromdocname, docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1027
                            if labelid:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1028
                                newnode['refuri'] += '#' + labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1029
                        newnode.append(innernode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1030
                elif typ == 'keyword':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1031
                    # keywords are referenced by named labels
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1032
                    docname, labelid, _ = self.labels.get(target, ('','',''))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1033
                    if not docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1034
                        #self.warn(fromdocname, 'unknown keyword: %s' % target)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1035
                        newnode = contnode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1036
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1037
                        newnode = nodes.reference('', '')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1038
                        if docname == fromdocname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1039
                            newnode['refid'] = labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1040
                        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1041
                            newnode['refuri'] = builder.get_relative_uri(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1042
                                fromdocname, docname) + '#' + labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1043
                        newnode.append(contnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1044
                elif typ == 'option':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1045
                    progname = node['refprogram']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1046
                    docname, labelid = self.progoptions.get((progname, target), ('', ''))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1047
                    if not docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1048
                        newnode = contnode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1049
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1050
                        newnode = nodes.reference('', '')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1051
                        if docname == fromdocname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1052
                            newnode['refid'] = labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1053
                        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1054
                            newnode['refuri'] = builder.get_relative_uri(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1055
                                fromdocname, docname) + '#' + labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1056
                        newnode.append(contnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1057
                elif typ in reftarget_roles:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1058
                    docname, labelid = self.reftargets.get((typ, target), ('', ''))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1059
                    if not docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1060
                        if typ == 'term':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1061
                            self.warn(fromdocname, 'term not in glossary: %s' % target,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1062
                                      node.line)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1063
                        elif typ == 'citation':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1064
                            self.warn(fromdocname, 'citation not found: %s' % target,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1065
                                      node.line)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1066
                        newnode = contnode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1067
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1068
                        newnode = nodes.reference('', '')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1069
                        if docname == fromdocname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1070
                            newnode['refid'] = labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1071
                        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1072
                            newnode['refuri'] = builder.get_relative_uri(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1073
                                fromdocname, docname, typ) + '#' + labelid
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1074
                        newnode.append(contnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1075
                elif typ == 'mod':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1076
                    docname, synopsis, platform, deprecated = \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1077
                        self.modules.get(target, ('','','', ''))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1078
                    if not docname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1079
                        newnode = builder.app.emit_firstresult('missing-reference',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1080
                                                               self, node, contnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1081
                        if not newnode:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1082
                            newnode = contnode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1083
                    elif docname == fromdocname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1084
                        # don't link to self
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1085
                        newnode = contnode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1086
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1087
                        newnode = nodes.reference('', '')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1088
                        newnode['refuri'] = builder.get_relative_uri(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1089
                            fromdocname, docname) + '#module-' + target
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1090
                        newnode['reftitle'] = '%s%s%s' % (
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1091
                            (platform and '(%s) ' % platform),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1092
                            synopsis, (deprecated and ' (deprecated)' or ''))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1093
                        newnode.append(contnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1094
                elif typ in self.descroles:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1095
                    # "descrefs"
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1096
                    modname = node['modname']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1097
                    clsname = node['classname']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1098
                    searchorder = node.hasattr('refspecific') and 1 or 0
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1099
                    name, desc = self.find_desc(modname, clsname,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1100
                                                target, typ, searchorder)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1101
                    if not desc:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1102
                        newnode = builder.app.emit_firstresult('missing-reference',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1103
                                                               self, node, contnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1104
                        if not newnode:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1105
                            newnode = contnode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1106
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1107
                        newnode = nodes.reference('', '')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1108
                        if desc[0] == fromdocname:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1109
                            newnode['refid'] = name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1110
                        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1111
                            newnode['refuri'] = (
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1112
                                builder.get_relative_uri(fromdocname, desc[0])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1113
                                + '#' + name)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1114
                        newnode['reftitle'] = name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1115
                        newnode.append(contnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1116
                else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1117
                    raise RuntimeError('unknown xfileref node encountered: %s' % node)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1118
            except NoUri:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1119
                newnode = contnode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1120
            if newnode:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1121
                node.replace_self(newnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1122
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1123
        # allow custom references to be resolved
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1124
        builder.app.emit('doctree-resolved', doctree, fromdocname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1125
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1126
    def create_index(self, builder, _fixre=re.compile(r'(.*) ([(][^()]*[)])')):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1127
        """Create the real index from the collected index entries."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1128
        new = {}
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1129
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1130
        def add_entry(word, subword, dic=new):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1131
            entry = dic.get(word)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1132
            if not entry:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1133
                dic[word] = entry = [[], {}]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1134
            if subword:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1135
                add_entry(subword, '', dic=entry[1])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1136
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1137
                try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1138
                    entry[0].append(builder.get_relative_uri('genindex', fn)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1139
                                    + '#' + tid)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1140
                except NoUri:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1141
                    pass
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1142
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1143
        for fn, entries in self.indexentries.iteritems():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1144
            # new entry types must be listed in directives/other.py!
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1145
            for type, string, tid, alias in entries:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1146
                if type == 'single':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1147
                    try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1148
                        entry, subentry = string.split(';', 1)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1149
                    except ValueError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1150
                        entry, subentry = string, ''
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1151
                    if not entry:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1152
                        self.warn(fn, 'invalid index entry %r' % string)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1153
                        continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1154
                    add_entry(entry.strip(), subentry.strip())
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1155
                elif type == 'pair':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1156
                    try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1157
                        first, second = map(lambda x: x.strip(),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1158
                                            string.split(';', 1))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1159
                        if not first or not second:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1160
                            raise ValueError
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1161
                    except ValueError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1162
                        self.warn(fn, 'invalid pair index entry %r' % string)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1163
                        continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1164
                    add_entry(first, second)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1165
                    add_entry(second, first)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1166
                elif type == 'triple':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1167
                    try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1168
                        first, second, third = map(lambda x: x.strip(),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1169
                                                   string.split(';', 2))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1170
                        if not first or not second or not third:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1171
                            raise ValueError
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1172
                    except ValueError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1173
                        self.warn(fn, 'invalid triple index entry %r' % string)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1174
                        continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1175
                    add_entry(first, second+' '+third)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1176
                    add_entry(second, third+', '+first)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1177
                    add_entry(third, first+' '+second)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1178
                else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1179
                    self.warn(fn, 'unknown index entry type %r' % type)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1180
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1181
        newlist = new.items()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1182
        newlist.sort(key=lambda t: t[0].lower())
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1183
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1184
        # fixup entries: transform
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1185
        #   func() (in module foo)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1186
        #   func() (in module bar)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1187
        # into
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1188
        #   func()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1189
        #     (in module foo)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1190
        #     (in module bar)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1191
        oldkey = ''
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1192
        oldsubitems = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1193
        i = 0
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1194
        while i < len(newlist):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1195
            key, (targets, subitems) = newlist[i]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1196
            # cannot move if it hassubitems; structure gets too complex
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1197
            if not subitems:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1198
                m = _fixre.match(key)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1199
                if m:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1200
                    if oldkey == m.group(1):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1201
                        # prefixes match: add entry as subitem of the previous entry
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1202
                        oldsubitems.setdefault(m.group(2), [[], {}])[0].extend(targets)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1203
                        del newlist[i]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1204
                        continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1205
                    oldkey = m.group(1)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1206
                else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1207
                    oldkey = key
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1208
            oldsubitems = subitems
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1209
            i += 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1210
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1211
        # group the entries by letter
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1212
        def keyfunc((k, v), ltrs=uppercase+'_'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1213
            # hack: mutate the subitems dicts to a list in the keyfunc
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1214
            v[1] = sorted((si, se) for (si, (se, void)) in v[1].iteritems())
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1215
            # now calculate the key
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1216
            letter = k[0].upper()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1217
            if letter in ltrs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1218
                return letter
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1219
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1220
                # get all other symbols under one heading
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1221
                return 'Symbols'
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1222
        return [(key, list(group)) for (key, group) in groupby(newlist, keyfunc)]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1223
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1224
    def collect_relations(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1225
        relations = {}
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1226
        getinc = self.toctree_includes.get
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1227
        def collect(parents, docname, previous, next):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1228
            includes = getinc(docname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1229
            # previous
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1230
            if not previous:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1231
                # if no previous sibling, go to parent
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1232
                previous = parents[0][0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1233
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1234
                # else, go to previous sibling, or if it has children, to
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1235
                # the last of its children, or if that has children, to the
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1236
                # last of those, and so forth
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1237
                while 1:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1238
                    previncs = getinc(previous)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1239
                    if previncs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1240
                        previous = previncs[-1]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1241
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1242
                        break
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1243
            # next
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1244
            if includes:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1245
                # if it has children, go to first of them
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1246
                next = includes[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1247
            elif next:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1248
                # else, if next sibling, go to it
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1249
                pass
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1250
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1251
                # else, go to the next sibling of the parent, if present,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1252
                # else the grandparent's sibling, if present, and so forth
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1253
                for parname, parindex in parents:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1254
                    parincs = getinc(parname)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1255
                    if parincs and parindex + 1 < len(parincs):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1256
                        next = parincs[parindex+1]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1257
                        break
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1258
                # else it will stay None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1259
            # same for children
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1260
            if includes:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1261
                for subindex, args in enumerate(izip(includes, [None] + includes,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1262
                                                     includes[1:] + [None])):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1263
                    collect([(docname, subindex)] + parents, *args)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1264
            relations[docname] = [parents[0][0], previous, next]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1265
        collect([(None, 0)], self.config.master_doc, None, None)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1266
        return relations
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1267
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1268
    def check_consistency(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1269
        """Do consistency checks."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1270
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1271
        for docname in sorted(self.all_docs):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1272
            if docname not in self.files_to_rebuild:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1273
                if docname == self.config.master_doc:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1274
                    # the master file is not included anywhere ;)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1275
                    continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1276
                self.warn(docname, 'document isn\'t included in any toctree')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1277
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1278
    # --------- QUERYING -------------------------------------------------------
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1279
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1280
    def find_desc(self, modname, classname, name, type, searchorder=0):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1281
        """Find a description node matching "name", perhaps using
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1282
           the given module and/or classname."""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1283
        # skip parens
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1284
        if name[-2:] == '()':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1285
            name = name[:-2]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1286
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1287
        if not name:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1288
            return None, None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1289
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1290
        # don't add module and class names for C things
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1291
        if type[0] == 'c' and type not in ('class', 'const'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1292
            # skip trailing star and whitespace
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1293
            name = name.rstrip(' *')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1294
            if name in self.descrefs and self.descrefs[name][1][0] == 'c':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1295
                return name, self.descrefs[name]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1296
            return None, None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1297
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1298
        newname = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1299
        if searchorder == 1:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1300
            if modname and classname and \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1301
                   modname + '.' + classname + '.' + name in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1302
                newname = modname + '.' + classname + '.' + name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1303
            elif modname and modname + '.' + name in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1304
                newname = modname + '.' + name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1305
            elif name in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1306
                newname = name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1307
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1308
            if name in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1309
                newname = name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1310
            elif modname and modname + '.' + name in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1311
                newname = modname + '.' + name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1312
            elif modname and classname and \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1313
                     modname + '.' + classname + '.' + name in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1314
                newname = modname + '.' + classname + '.' + name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1315
            # special case: builtin exceptions have module "exceptions" set
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1316
            elif type == 'exc' and '.' not in name and \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1317
                 'exceptions.' + name in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1318
                newname = 'exceptions.' + name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1319
            # special case: object methods
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1320
            elif type in ('func', 'meth') and '.' not in name and \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1321
                 'object.' + name in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1322
                newname = 'object.' + name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1323
        if newname is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1324
            return None, None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1325
        return newname, self.descrefs[newname]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1326
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1327
    def find_keyword(self, keyword, avoid_fuzzy=False, cutoff=0.6, n=20):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1328
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1329
        Find keyword matches for a keyword. If there's an exact match, just return
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1330
        it, else return a list of fuzzy matches if avoid_fuzzy isn't True.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1331
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1332
        Keywords searched are: first modules, then descrefs.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1333
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1334
        Returns: None if nothing found
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1335
                 (type, docname, anchorname) if exact match found
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1336
                 list of (quality, type, docname, anchorname, description) if fuzzy
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1337
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1338
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1339
        if keyword in self.modules:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1340
            docname, title, system, deprecated = self.modules[keyword]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1341
            return 'module', docname, 'module-' + keyword
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1342
        if keyword in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1343
            docname, ref_type = self.descrefs[keyword]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1344
            return ref_type, docname, keyword
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1345
        # special cases
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1346
        if '.' not in keyword:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1347
            # exceptions are documented in the exceptions module
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1348
            if 'exceptions.'+keyword in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1349
                docname, ref_type = self.descrefs['exceptions.'+keyword]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1350
                return ref_type, docname, 'exceptions.'+keyword
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1351
            # special methods are documented as object methods
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1352
            if 'object.'+keyword in self.descrefs:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1353
                docname, ref_type = self.descrefs['object.'+keyword]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1354
                return ref_type, docname, 'object.'+keyword
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1355
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1356
        if avoid_fuzzy:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1357
            return
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1358
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1359
        # find fuzzy matches
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1360
        s = difflib.SequenceMatcher()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1361
        s.set_seq2(keyword.lower())
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1362
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1363
        def possibilities():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1364
            for title, (fn, desc, _, _) in self.modules.iteritems():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1365
                yield ('module', fn, 'module-'+title, desc)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1366
            for title, (fn, desctype) in self.descrefs.iteritems():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1367
                yield (desctype, fn, title, '')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1368
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1369
        def dotsearch(string):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1370
            parts = string.lower().split('.')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1371
            for idx in xrange(0, len(parts)):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1372
                yield '.'.join(parts[idx:])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1373
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1374
        result = []
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1375
        for type, docname, title, desc in possibilities():
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1376
            best_res = 0
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1377
            for part in dotsearch(title):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1378
                s.set_seq1(part)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1379
                if s.real_quick_ratio() >= cutoff and \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1380
                   s.quick_ratio() >= cutoff and \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1381
                   s.ratio() >= cutoff and \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1382
                   s.ratio() > best_res:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1383
                    best_res = s.ratio()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1384
            if best_res:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1385
                result.append((best_res, type, docname, title, desc))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1386
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
  1387
        return heapq.nlargest(n, result)