mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
merged
This commit is contained in:
commit
ec24ba6864
@ -14,19 +14,21 @@
|
||||
import sys
|
||||
import types
|
||||
import posixpath
|
||||
from os import path
|
||||
from cStringIO import StringIO
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives, roles
|
||||
|
||||
import sphinx
|
||||
from sphinx import package_dir, locale
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import SphinxError, SphinxWarning, ExtensionError
|
||||
from sphinx.domains import domains
|
||||
from sphinx.domains import all_domains
|
||||
from sphinx.builders import BUILTIN_BUILDERS
|
||||
from sphinx.directives import GenericDesc, Target, additional_xref_types
|
||||
from sphinx.environment import SphinxStandaloneReader
|
||||
from sphinx.environment import BuildEnvironment, SphinxStandaloneReader
|
||||
from sphinx.util import pycompat
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.util.compat import Directive, directive_dwim
|
||||
@ -50,6 +52,7 @@ events = {
|
||||
}
|
||||
|
||||
CONFIG_FILENAME = 'conf.py'
|
||||
ENV_PICKLE_FILENAME = 'environment.pickle'
|
||||
|
||||
|
||||
class Sphinx(object):
|
||||
@ -62,6 +65,7 @@ class Sphinx(object):
|
||||
self._listeners = {}
|
||||
self.builderclasses = BUILTIN_BUILDERS.copy()
|
||||
self.builder = None
|
||||
self.env = None
|
||||
|
||||
self.srcdir = srcdir
|
||||
self.confdir = confdir
|
||||
@ -104,8 +108,62 @@ class Sphinx(object):
|
||||
# now that we know all config values, collect them from conf.py
|
||||
self.config.init_values()
|
||||
|
||||
# set up translation infrastructure
|
||||
self._init_i18n()
|
||||
# set up the build environment
|
||||
self._init_env(freshenv)
|
||||
# set up the builder
|
||||
self._init_builder(buildername)
|
||||
|
||||
def _init_i18n(self):
|
||||
"""
|
||||
Load translated strings from the configured localedirs if
|
||||
enabled in the configuration.
|
||||
"""
|
||||
if self.config.language is not None:
|
||||
self.info(bold('loading translations [%s]... ' %
|
||||
self.config.language), nonl=True)
|
||||
locale_dirs = [None, path.join(package_dir, 'locale')] + \
|
||||
[path.join(self.srcdir, x) for x in self.config.locale_dirs]
|
||||
else:
|
||||
locale_dirs = []
|
||||
self.translator, has_translation = locale.init(locale_dirs,
|
||||
self.config.language)
|
||||
if self.config.language is not None:
|
||||
if has_translation:
|
||||
self.info('done')
|
||||
else:
|
||||
self.info('locale not available')
|
||||
|
||||
def _init_env(self, freshenv):
|
||||
if freshenv:
|
||||
self.env = BuildEnvironment(self.srcdir, self.doctreedir,
|
||||
self.config)
|
||||
self.env.find_files(self.config)
|
||||
for domain in all_domains.keys():
|
||||
self.env.domains[domain] = all_domains[domain](self.env)
|
||||
else:
|
||||
try:
|
||||
self.info(bold('loading pickled environment... '), nonl=True)
|
||||
self.env = BuildEnvironment.frompickle(self.config,
|
||||
path.join(self.doctreedir, ENV_PICKLE_FILENAME))
|
||||
self.env.domains = {}
|
||||
for domain in all_domains.keys():
|
||||
# this can raise if the data version doesn't fit
|
||||
self.env.domains[domain] = all_domains[domain](self.env)
|
||||
self.info('done')
|
||||
except Exception, err:
|
||||
if type(err) is IOError and err.errno == 2:
|
||||
self.info('not yet created')
|
||||
else:
|
||||
self.info('failed: %s' % err)
|
||||
return self._init_env(freshenv=True)
|
||||
|
||||
self.env.set_warnfunc(self.warn)
|
||||
|
||||
def _init_builder(self, buildername):
|
||||
if buildername is None:
|
||||
print >>status, 'No builder selected, using default: html'
|
||||
print >>self._status, 'No builder selected, using default: html'
|
||||
buildername = 'html'
|
||||
if buildername not in self.builderclasses:
|
||||
raise SphinxError('Builder name %s not registered' % buildername)
|
||||
@ -116,9 +174,7 @@ class Sphinx(object):
|
||||
mod, cls = builderclass
|
||||
builderclass = getattr(
|
||||
__import__('sphinx.builders.' + mod, None, None, [cls]), cls)
|
||||
self.builder = builderclass(self, freshenv=freshenv)
|
||||
self.builder.tags = self.tags
|
||||
self.builder.tags.add(self.builder.format)
|
||||
self.builder = builderclass(self)
|
||||
self.emit('builder-inited')
|
||||
|
||||
def build(self, all_files, filenames):
|
||||
@ -300,9 +356,9 @@ class Sphinx(object):
|
||||
roles.register_local_role(name, role)
|
||||
|
||||
def add_domain(self, domain):
|
||||
if domain.name in domains:
|
||||
if domain.name in all_domains:
|
||||
raise ExtensionError('domain %s already registered' % domain.name)
|
||||
domains[domain.name] = domain
|
||||
all_domains[domain.name] = domain
|
||||
|
||||
def add_description_unit(self, directivename, rolename, indextemplate='',
|
||||
parse_node=None, ref_nodeclass=None):
|
||||
@ -311,7 +367,7 @@ class Sphinx(object):
|
||||
directives.register_directive(directivename,
|
||||
directive_dwim(GenericDesc))
|
||||
# XXX support more options?
|
||||
role_func = XRefRole('', innernodeclass=ref_nodeclass)
|
||||
role_func = XRefRole(innernodeclass=ref_nodeclass)
|
||||
roles.register_local_role(rolename, role_func)
|
||||
|
||||
def add_crossref_type(self, directivename, rolename, indextemplate='',
|
||||
@ -319,7 +375,7 @@ class Sphinx(object):
|
||||
additional_xref_types[directivename] = (rolename, indextemplate, None)
|
||||
directives.register_directive(directivename, directive_dwim(Target))
|
||||
# XXX support more options
|
||||
role_func = XRefRole('', innernodeclass=ref_nodeclass)
|
||||
role_func = XRefRole(innernodeclass=ref_nodeclass)
|
||||
roles.register_local_role(rolename, role_func)
|
||||
|
||||
def add_transform(self, transform):
|
||||
|
@ -15,9 +15,7 @@ from os import path
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx import package_dir, locale
|
||||
from sphinx.util import SEP, relative_uri
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.util.console import bold, purple, darkgreen, term_width_line
|
||||
|
||||
# side effect: registers roles and directives
|
||||
@ -25,9 +23,6 @@ from sphinx import roles
|
||||
from sphinx import directives
|
||||
|
||||
|
||||
ENV_PICKLE_FILENAME = 'environment.pickle'
|
||||
|
||||
|
||||
class Builder(object):
|
||||
"""
|
||||
Builds target formats from the reST sources.
|
||||
@ -38,7 +33,8 @@ class Builder(object):
|
||||
# builder's output format, or '' if no document output is produced
|
||||
format = ''
|
||||
|
||||
def __init__(self, app, env=None, freshenv=False):
|
||||
def __init__(self, app):
|
||||
self.env = app.env
|
||||
self.srcdir = app.srcdir
|
||||
self.confdir = app.confdir
|
||||
self.outdir = app.outdir
|
||||
@ -50,18 +46,13 @@ class Builder(object):
|
||||
self.warn = app.warn
|
||||
self.info = app.info
|
||||
self.config = app.config
|
||||
|
||||
self.load_i18n()
|
||||
self.tags = app.tags
|
||||
self.tags.add(self.format)
|
||||
|
||||
# images that need to be copied over (source -> dest)
|
||||
self.images = {}
|
||||
|
||||
# if None, this is set in load_env()
|
||||
self.env = env
|
||||
self.freshenv = freshenv
|
||||
|
||||
self.init()
|
||||
self.load_env()
|
||||
|
||||
# helper methods
|
||||
|
||||
@ -167,50 +158,6 @@ class Builder(object):
|
||||
|
||||
# build methods
|
||||
|
||||
def load_i18n(self):
|
||||
"""
|
||||
Load translated strings from the configured localedirs if
|
||||
enabled in the configuration.
|
||||
"""
|
||||
if self.config.language is not None:
|
||||
self.info(bold('loading translations [%s]... ' %
|
||||
self.config.language), nonl=True)
|
||||
locale_dirs = [None, path.join(package_dir, 'locale')] + \
|
||||
[path.join(self.srcdir, x) for x in self.config.locale_dirs]
|
||||
else:
|
||||
locale_dirs = []
|
||||
self.translator, has_translation = locale.init(locale_dirs,
|
||||
self.config.language)
|
||||
if self.config.language is not None:
|
||||
if has_translation:
|
||||
self.info('done')
|
||||
else:
|
||||
self.info('locale not available')
|
||||
|
||||
def load_env(self):
|
||||
"""Set up the build environment."""
|
||||
if self.env:
|
||||
return
|
||||
if not self.freshenv:
|
||||
try:
|
||||
self.info(bold('loading pickled environment... '), nonl=True)
|
||||
self.env = BuildEnvironment.frompickle(self.config,
|
||||
path.join(self.doctreedir, ENV_PICKLE_FILENAME))
|
||||
self.info('done')
|
||||
except Exception, err:
|
||||
if type(err) is IOError and err.errno == 2:
|
||||
self.info('not found')
|
||||
else:
|
||||
self.info('failed: %s' % err)
|
||||
self.env = BuildEnvironment(self.srcdir, self.doctreedir,
|
||||
self.config)
|
||||
self.env.find_files(self.config)
|
||||
else:
|
||||
self.env = BuildEnvironment(self.srcdir, self.doctreedir,
|
||||
self.config)
|
||||
self.env.find_files(self.config)
|
||||
self.env.set_warnfunc(self.warn)
|
||||
|
||||
def build_all(self):
|
||||
"""Build all source files."""
|
||||
self.build(None, summary='all source files', method='all')
|
||||
@ -290,6 +237,7 @@ class Builder(object):
|
||||
|
||||
if updated_docnames:
|
||||
# save the environment
|
||||
from sphinx.application import ENV_PICKLE_FILENAME
|
||||
self.info(bold('pickling environment... '), nonl=True)
|
||||
self.env.topickle(path.join(self.doctreedir, ENV_PICKLE_FILENAME))
|
||||
self.info('done')
|
||||
|
@ -33,7 +33,8 @@ from sphinx.util import SEP, os_path, relative_uri, ensuredir, \
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.search import js_index
|
||||
from sphinx.theming import Theme
|
||||
from sphinx.builders import Builder, ENV_PICKLE_FILENAME
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.application import ENV_PICKLE_FILENAME
|
||||
from sphinx.highlighting import PygmentsBridge
|
||||
from sphinx.util.console import bold
|
||||
from sphinx.writers.html import HTMLWriter, HTMLTranslator, \
|
||||
@ -239,7 +240,9 @@ class StandaloneHTMLBuilder(Builder):
|
||||
rellinks = []
|
||||
if self.config.html_use_index:
|
||||
rellinks.append(('genindex', _('General Index'), 'I', _('index')))
|
||||
if self.config.html_use_modindex and self.env.modules:
|
||||
# XXX generalization of modindex?
|
||||
if self.config.html_use_modindex and \
|
||||
self.env.domaindata['py']['modules']:
|
||||
rellinks.append(('modindex', _('Global Module Index'),
|
||||
'M', _('modules')))
|
||||
|
||||
@ -404,12 +407,13 @@ class StandaloneHTMLBuilder(Builder):
|
||||
|
||||
# the global module index
|
||||
|
||||
if self.config.html_use_modindex and self.env.modules:
|
||||
moduleindex = self.env.domaindata['py']['modules']
|
||||
if self.config.html_use_modindex and moduleindex:
|
||||
# the sorted list of all modules, for the global module index
|
||||
modules = sorted(((mn, (self.get_relative_uri('modindex', fn) +
|
||||
'#module-' + mn, sy, pl, dep))
|
||||
for (mn, (fn, sy, pl, dep)) in
|
||||
self.env.modules.iteritems()),
|
||||
moduleindex.iteritems()),
|
||||
key=lambda x: x[0].lower())
|
||||
# collect all platforms
|
||||
platforms = set()
|
||||
@ -709,14 +713,15 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.info(bold('dumping object inventory... '), nonl=True)
|
||||
f = open(path.join(self.outdir, INVENTORY_FILENAME), 'w')
|
||||
try:
|
||||
# XXX inventory version 2
|
||||
f.write('# Sphinx inventory version 1\n')
|
||||
f.write('# Project: %s\n' % self.config.project.encode('utf-8'))
|
||||
f.write('# Version: %s\n' % self.config.version)
|
||||
for modname, info in self.env.modules.iteritems():
|
||||
f.write('%s mod %s\n' % (modname, self.get_target_uri(info[0])))
|
||||
for refname, (docname, desctype) in self.env.descrefs.iteritems():
|
||||
f.write('%s %s %s\n' % (refname, desctype,
|
||||
self.get_target_uri(docname)))
|
||||
#for modname, info in self.env.modules.iteritems():
|
||||
# f.write('%s mod %s\n' % (modname, self.get_target_uri(info[0])))
|
||||
#for refname, (docname, desctype) in self.env.descrefs.iteritems():
|
||||
# f.write('%s %s %s\n' % (refname, desctype,
|
||||
# self.get_target_uri(docname)))
|
||||
finally:
|
||||
f.close()
|
||||
self.info('done')
|
||||
|
@ -204,7 +204,10 @@ class DescDirective(Directive):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
self.desctype = self.name
|
||||
if ':' in self.name:
|
||||
self.domain, self.desctype = self.name.split(':', 1)
|
||||
else:
|
||||
self.domain, self.desctype = '', self.name
|
||||
self.env = self.state.document.settings.env
|
||||
self.indexnode = addnodes.index(entries=[])
|
||||
|
||||
@ -366,7 +369,7 @@ class DefaultDomain(Directive):
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
domain_name = arguments[0]
|
||||
env.default_domain = domains.get(domain_name)
|
||||
env.default_domain = env.domains.get(domain_name)
|
||||
|
||||
|
||||
# Note: the target directive is not registered here, it is used by the
|
||||
|
@ -103,75 +103,6 @@ class TocTree(Directive):
|
||||
return ret
|
||||
|
||||
|
||||
class Module(Directive):
|
||||
"""
|
||||
Directive to mark description of a new module.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
'platform': lambda x: x,
|
||||
'synopsis': lambda x: x,
|
||||
'noindex': directives.flag,
|
||||
'deprecated': directives.flag,
|
||||
}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
noindex = 'noindex' in self.options
|
||||
env.currmodule = modname
|
||||
env.note_module(modname, self.options.get('synopsis', ''),
|
||||
self.options.get('platform', ''),
|
||||
'deprecated' in self.options)
|
||||
modulenode = addnodes.module()
|
||||
modulenode['modname'] = modname
|
||||
modulenode['synopsis'] = self.options.get('synopsis', '')
|
||||
targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
|
||||
self.state.document.note_explicit_target(targetnode)
|
||||
ret = [modulenode, targetnode]
|
||||
if 'platform' in self.options:
|
||||
platform = self.options['platform']
|
||||
modulenode['platform'] = platform
|
||||
node = nodes.paragraph()
|
||||
node += nodes.emphasis('', _('Platforms: '))
|
||||
node += nodes.Text(platform, platform)
|
||||
ret.append(node)
|
||||
# the synopsis isn't printed; in fact, it is only used in the
|
||||
# modindex currently
|
||||
if not noindex:
|
||||
indextext = _('%s (module)') % modname
|
||||
inode = addnodes.index(entries=[('single', indextext,
|
||||
'module-' + modname, modname)])
|
||||
ret.insert(0, inode)
|
||||
return ret
|
||||
|
||||
|
||||
class CurrentModule(Directive):
|
||||
"""
|
||||
This directive is just to tell Sphinx that we're documenting
|
||||
stuff in module foo, but links to module foo won't lead here.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
if modname == 'None':
|
||||
env.currmodule = None
|
||||
else:
|
||||
env.currmodule = modname
|
||||
return []
|
||||
|
||||
|
||||
class Author(Directive):
|
||||
"""
|
||||
Directive to give the name of the author of the current document
|
||||
@ -559,8 +490,6 @@ class Only(Directive):
|
||||
|
||||
|
||||
directives.register_directive('toctree', directive_dwim(TocTree))
|
||||
directives.register_directive('module', directive_dwim(Module))
|
||||
directives.register_directive('currentmodule', directive_dwim(CurrentModule))
|
||||
directives.register_directive('sectionauthor', directive_dwim(Author))
|
||||
directives.register_directive('moduleauthor', directive_dwim(Author))
|
||||
directives.register_directive('program', directive_dwim(Program))
|
||||
|
@ -4,17 +4,23 @@
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Support for domains, which are groupings of description directives
|
||||
describing e.g. constructs of one programming language.
|
||||
and roles describing e.g. constructs of one programming language.
|
||||
|
||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
import string
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.directives import DescDirective
|
||||
from sphinx.util import make_refnode
|
||||
from sphinx.util.compat import Directive
|
||||
|
||||
|
||||
class Domain(object):
|
||||
@ -23,6 +29,68 @@ class Domain(object):
|
||||
roles = {}
|
||||
label = ''
|
||||
|
||||
# data value for a fresh environment
|
||||
initial_data = {}
|
||||
# data version
|
||||
data_version = 0
|
||||
|
||||
def __init__(self, env):
|
||||
self.env = env
|
||||
if self.name not in env.domaindata:
|
||||
new_data = self.initial_data.copy()
|
||||
new_data['version'] = self.data_version
|
||||
self.data = env.domaindata[self.name] = new_data
|
||||
else:
|
||||
self.data = env.domaindata[self.name]
|
||||
if self.data['version'] < self.data_version:
|
||||
raise IOError('data of %r domain out of date' % self.label)
|
||||
self._role_cache = {}
|
||||
self._directive_cache = {}
|
||||
|
||||
def clear_doc(self, docname):
|
||||
"""
|
||||
Remove traces of a document in the domain-specific inventories.
|
||||
"""
|
||||
pass
|
||||
|
||||
def role(self, name):
|
||||
"""
|
||||
Return a role adapter function that always gives the registered
|
||||
role its full name ('domain:name') as the first argument.
|
||||
"""
|
||||
if name in self._role_cache:
|
||||
return self._role_cache[name]
|
||||
if name not in self.roles:
|
||||
return None
|
||||
fullname = '%s:%s' % (self.name, name)
|
||||
def role_adapter(typ, rawtext, text, lineno, inliner,
|
||||
options={}, content=[]):
|
||||
return self.roles[name](fullname, rawtext, text, lineno,
|
||||
inliner, options, content)
|
||||
self._role_cache[name] = role_adapter
|
||||
return role_adapter
|
||||
|
||||
def directive(self, name):
|
||||
"""
|
||||
Return a directive adapter class that always gives the registered
|
||||
directive its full name ('domain:name') as ``self.name``.
|
||||
"""
|
||||
if name in self._directive_cache:
|
||||
return self._directive_cache[name]
|
||||
if name not in self.directives:
|
||||
return None
|
||||
fullname = '%s:%s' % (self.name, name)
|
||||
BaseDirective = self.directives[name]
|
||||
class DirectiveAdapter(BaseDirective):
|
||||
def run(self):
|
||||
self.name = fullname
|
||||
return BaseDirective.run(self)
|
||||
self._directive_cache[name] = DirectiveAdapter
|
||||
return DirectiveAdapter
|
||||
|
||||
def resolve_xref(self, typ, target, node, contnode):
|
||||
pass
|
||||
|
||||
|
||||
# REs for Python signatures
|
||||
py_sig_re = re.compile(
|
||||
@ -146,7 +214,15 @@ class PythonDesc(DescDirective):
|
||||
signode['ids'].append(fullname)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.env.note_descref(fullname, self.desctype, self.lineno)
|
||||
objects = self.env.domaindata['py']['objects']
|
||||
if fullname in objects:
|
||||
self.env.warn(
|
||||
self.env.docname,
|
||||
'duplicate object description of %s, ' % fullname +
|
||||
'other instance in ' +
|
||||
self.env.doc2path(objects[fullname][0]),
|
||||
self.lineno)
|
||||
objects[fullname] = (self.env.docname, self.desctype)
|
||||
|
||||
indextext = self.get_index_text(modname, name_cls)
|
||||
if indextext:
|
||||
@ -286,6 +362,75 @@ class ClassmemberDesc(PythonDesc):
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class PyModule(Directive):
|
||||
"""
|
||||
Directive to mark description of a new module.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
'platform': lambda x: x,
|
||||
'synopsis': lambda x: x,
|
||||
'noindex': directives.flag,
|
||||
'deprecated': directives.flag,
|
||||
}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
noindex = 'noindex' in self.options
|
||||
env.currmodule = modname
|
||||
env.domaindata['py']['modules'][modname] = \
|
||||
(env.docname, self.options.get('synopsis', ''),
|
||||
self.options.get('platform', ''), 'deprecated' in self.options)
|
||||
modulenode = addnodes.module()
|
||||
modulenode['modname'] = modname
|
||||
modulenode['synopsis'] = self.options.get('synopsis', '')
|
||||
targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
|
||||
self.state.document.note_explicit_target(targetnode)
|
||||
ret = [modulenode, targetnode]
|
||||
if 'platform' in self.options:
|
||||
platform = self.options['platform']
|
||||
modulenode['platform'] = platform
|
||||
node = nodes.paragraph()
|
||||
node += nodes.emphasis('', _('Platforms: '))
|
||||
node += nodes.Text(platform, platform)
|
||||
ret.append(node)
|
||||
# the synopsis isn't printed; in fact, it is only used in the
|
||||
# modindex currently
|
||||
if not noindex:
|
||||
indextext = _('%s (module)') % modname
|
||||
inode = addnodes.index(entries=[('single', indextext,
|
||||
'module-' + modname, modname)])
|
||||
ret.insert(0, inode)
|
||||
return ret
|
||||
|
||||
|
||||
class PyCurrentModule(Directive):
|
||||
"""
|
||||
This directive is just to tell Sphinx that we're documenting
|
||||
stuff in module foo, but links to module foo won't lead here.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
if modname == 'None':
|
||||
env.currmodule = None
|
||||
else:
|
||||
env.currmodule = modname
|
||||
return []
|
||||
|
||||
|
||||
class PyXRefRole(XRefRole):
|
||||
def process_link(self, env, pnode, has_explicit_title, title, target):
|
||||
pnode['modname'] = env.currmodule
|
||||
@ -321,18 +466,105 @@ class PythonDomain(Domain):
|
||||
'classmethod': ClassmemberDesc,
|
||||
'staticmethod': ClassmemberDesc,
|
||||
'attribute': ClassmemberDesc,
|
||||
'module': PyModule,
|
||||
'currentmodule': PyCurrentModule,
|
||||
}
|
||||
roles = {
|
||||
'data': PyXRefRole('py'),
|
||||
'exc': PyXRefRole('py'),
|
||||
'func': PyXRefRole('py', True),
|
||||
'class': PyXRefRole('py'),
|
||||
'const': PyXRefRole('py'),
|
||||
'attr': PyXRefRole('py'),
|
||||
'meth': PyXRefRole('py', True),
|
||||
'mod': PyXRefRole('py'),
|
||||
'obj': PyXRefRole('py'),
|
||||
'data': PyXRefRole(),
|
||||
'exc': PyXRefRole(),
|
||||
'func': PyXRefRole(fix_parens=True),
|
||||
'class': PyXRefRole(),
|
||||
'const': PyXRefRole(),
|
||||
'attr': PyXRefRole(),
|
||||
'meth': PyXRefRole(fix_parens=True),
|
||||
'mod': PyXRefRole(),
|
||||
'obj': PyXRefRole(),
|
||||
}
|
||||
initial_data = {
|
||||
'objects': {}, # fullname -> docname, desctype
|
||||
'modules': {}, # modname -> docname, synopsis, platform, deprecated
|
||||
}
|
||||
|
||||
def clear_doc(self, docname):
|
||||
for fullname, (fn, _) in self.data['objects'].items():
|
||||
if fn == docname:
|
||||
del self.data['objects'][fullname]
|
||||
for modname, (fn, _, _, _) in self.data['modules'].items():
|
||||
if fn == docname:
|
||||
del self.data['modules'][modname]
|
||||
|
||||
def find_desc(self, env, modname, classname, name, type, searchorder=0):
|
||||
"""
|
||||
Find a Python object description for "name", perhaps using the given
|
||||
module and/or classname.
|
||||
"""
|
||||
# skip parens
|
||||
if name[-2:] == '()':
|
||||
name = name[:-2]
|
||||
|
||||
if not name:
|
||||
return None, None
|
||||
|
||||
objects = self.data['objects']
|
||||
|
||||
newname = None
|
||||
if searchorder == 1:
|
||||
if modname and classname and \
|
||||
modname + '.' + classname + '.' + name in objects:
|
||||
newname = modname + '.' + classname + '.' + name
|
||||
elif modname and modname + '.' + name in objects:
|
||||
newname = modname + '.' + name
|
||||
elif name in objects:
|
||||
newname = name
|
||||
else:
|
||||
if name in objects:
|
||||
newname = name
|
||||
elif modname and modname + '.' + name in objects:
|
||||
newname = modname + '.' + name
|
||||
elif modname and classname and \
|
||||
modname + '.' + classname + '.' + name in objects:
|
||||
newname = modname + '.' + classname + '.' + name
|
||||
# special case: builtin exceptions have module "exceptions" set
|
||||
elif type == 'exc' and '.' not in name and \
|
||||
'exceptions.' + name in objects:
|
||||
newname = 'exceptions.' + name
|
||||
# special case: object methods
|
||||
elif type in ('func', 'meth') and '.' not in name and \
|
||||
'object.' + name in objects:
|
||||
newname = 'object.' + name
|
||||
if newname is None:
|
||||
return None, None
|
||||
return newname, objects[newname]
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder,
|
||||
typ, target, node, contnode):
|
||||
if (typ == 'mod' or
|
||||
typ == 'obj' and target in self.data['modules']):
|
||||
docname, synopsis, platform, deprecated = \
|
||||
self.data['modules'].get(target, ('','','', ''))
|
||||
if not docname:
|
||||
return None
|
||||
elif docname == fromdocname:
|
||||
# don't link to self
|
||||
return contnode
|
||||
else:
|
||||
title = '%s%s%s' % ((platform and '(%s) ' % platform),
|
||||
synopsis,
|
||||
(deprecated and ' (deprecated)' or ''))
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
'module-' + target, contnode, title)
|
||||
else:
|
||||
modname = node['modname']
|
||||
clsname = node['classname']
|
||||
searchorder = node.hasattr('refspecific') and 1 or 0
|
||||
name, desc = self.find_desc(env, modname, clsname,
|
||||
target, typ, searchorder)
|
||||
if not desc:
|
||||
return None
|
||||
else:
|
||||
return make_refnode(builder, fromdocname, desc[0], name,
|
||||
contnode, name)
|
||||
|
||||
|
||||
|
||||
# RE to split at word boundaries
|
||||
@ -370,7 +602,7 @@ class CDesc(DescDirective):
|
||||
if part[0] in string.ascii_letters+'_' and \
|
||||
part not in self.stopwords:
|
||||
pnode = addnodes.pending_xref(
|
||||
'', reftype='ctype', reftarget=part,
|
||||
'', refdomain='c', reftype='type', reftarget=part,
|
||||
modname=None, classname=None)
|
||||
pnode += tnode
|
||||
node += pnode
|
||||
@ -451,7 +683,14 @@ class CDesc(DescDirective):
|
||||
signode['ids'].append(name)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.env.note_descref(name, self.desctype, self.lineno)
|
||||
inv = self.env.domaindata['c']['objects']
|
||||
if name in inv:
|
||||
self.env.warn(
|
||||
self.env.docname,
|
||||
'duplicate C object description of %s, ' % name +
|
||||
'other instance in ' + self.env.doc2path(inv[name][0]),
|
||||
self.lineno)
|
||||
inv[name] = (self.env.docname, self.desctype)
|
||||
|
||||
indextext = self.get_index_text(name)
|
||||
if indextext:
|
||||
@ -470,16 +709,33 @@ class CDomain(Domain):
|
||||
'var': CDesc,
|
||||
}
|
||||
roles = {
|
||||
'member': XRefRole('c'),
|
||||
'macro': XRefRole('c'),
|
||||
'func' : XRefRole('c', True),
|
||||
'data': XRefRole('c'),
|
||||
'type': XRefRole('c'),
|
||||
'member': XRefRole(),
|
||||
'macro': XRefRole(),
|
||||
'func' : XRefRole(fix_parens=True),
|
||||
'data': XRefRole(),
|
||||
'type': XRefRole(),
|
||||
}
|
||||
initial_data = {
|
||||
'objects': {}, # fullname -> docname, desctype
|
||||
}
|
||||
|
||||
def clear_doc(self, docname):
|
||||
for fullname, (fn, _) in self.data['objects'].items():
|
||||
if fn == docname:
|
||||
del self.data['objects'][fullname]
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder,
|
||||
typ, target, node, contnode):
|
||||
# strip pointer asterisk
|
||||
target = target.rstrip(' *')
|
||||
if target not in self.data:
|
||||
return None
|
||||
desc = self.data[target]
|
||||
return make_refnode(builder, fromdocname, desc[0], contnode, target)
|
||||
|
||||
|
||||
# this contains all registered domains
|
||||
domains = {
|
||||
all_domains = {
|
||||
'py': PythonDomain,
|
||||
'c': CDomain,
|
||||
}
|
||||
|
@ -43,9 +43,8 @@ from docutils.transforms.parts import ContentsFilter
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util import movefile, get_matching_docs, SEP, ustrftime, \
|
||||
docname_join, FilenameUniqDict, url_re
|
||||
docname_join, FilenameUniqDict, url_re, make_refnode
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.domains import domains
|
||||
from sphinx.directives import additional_xref_types
|
||||
|
||||
orig_role_function = roles.role
|
||||
@ -214,9 +213,9 @@ class BuildEnvironment:
|
||||
env = pickle.load(picklefile)
|
||||
finally:
|
||||
picklefile.close()
|
||||
env.config.values = config.values
|
||||
if env.version != ENV_VERSION:
|
||||
raise IOError('env version not current')
|
||||
env.config.values = config.values
|
||||
return env
|
||||
|
||||
def topickle(self, filename):
|
||||
@ -225,6 +224,8 @@ class BuildEnvironment:
|
||||
self.set_warnfunc(None)
|
||||
values = self.config.values
|
||||
del self.config.values
|
||||
domains = self.domains
|
||||
del self.domains
|
||||
# first write to a temporary file, so that if dumping fails,
|
||||
# the existing environment won't be overwritten
|
||||
picklefile = open(filename + '.tmp', 'wb')
|
||||
@ -241,6 +242,7 @@ class BuildEnvironment:
|
||||
picklefile.close()
|
||||
movefile(filename + '.tmp', filename)
|
||||
# reset attributes
|
||||
self.domains = domains
|
||||
self.config.values = values
|
||||
self.set_warnfunc(warnfunc)
|
||||
|
||||
@ -254,6 +256,9 @@ class BuildEnvironment:
|
||||
# the application object; only set while update() runs
|
||||
self.app = None
|
||||
|
||||
# all the registered domains, set by the application
|
||||
self.domains = {}
|
||||
|
||||
# the docutils settings for building
|
||||
self.settings = default_settings.copy()
|
||||
self.settings['env'] = self
|
||||
@ -292,10 +297,10 @@ class BuildEnvironment:
|
||||
self.glob_toctrees = set() # docnames that have :glob: toctrees
|
||||
self.numbered_toctrees = set() # docnames that have :numbered: toctrees
|
||||
|
||||
# domain-specific inventories, here to be pickled
|
||||
self.domaindata = {} # domainname -> domain-specific object
|
||||
|
||||
# X-ref target inventory
|
||||
self.descrefs = {} # fullname -> docname, desctype
|
||||
self.modules = {} # modname -> docname, synopsis,
|
||||
# platform, deprecated
|
||||
self.labels = {} # labelname -> docname, labelid, sectionname
|
||||
self.anonlabels = {} # labelname -> docname, labelid
|
||||
self.progoptions = {} # (program, name) -> docname, labelid
|
||||
@ -363,12 +368,6 @@ class BuildEnvironment:
|
||||
fnset.discard(docname)
|
||||
if not fnset:
|
||||
del self.files_to_rebuild[subfn]
|
||||
for fullname, (fn, _) in self.descrefs.items():
|
||||
if fn == docname:
|
||||
del self.descrefs[fullname]
|
||||
for modname, (fn, _, _, _) in self.modules.items():
|
||||
if fn == docname:
|
||||
del self.modules[modname]
|
||||
for labelname, (fn, _, _) in self.labels.items():
|
||||
if fn == docname:
|
||||
del self.labels[labelname]
|
||||
@ -382,6 +381,10 @@ class BuildEnvironment:
|
||||
new = [change for change in changes if change[1] != docname]
|
||||
changes[:] = new
|
||||
|
||||
# XXX why does this not work inside the if?
|
||||
for domain in self.domains.values():
|
||||
domain.clear_doc(docname)
|
||||
|
||||
def doc2path(self, docname, base=True, suffix=None):
|
||||
"""
|
||||
Return the filename for the document name.
|
||||
@ -561,6 +564,7 @@ class BuildEnvironment:
|
||||
# remove all inventory entries for that file
|
||||
if app:
|
||||
app.emit('env-purge-doc', self, docname)
|
||||
|
||||
self.clear_doc(docname)
|
||||
|
||||
if src_path is None:
|
||||
@ -600,18 +604,20 @@ class BuildEnvironment:
|
||||
return data
|
||||
|
||||
# defaults to the global default, but can be re-set in a document
|
||||
self.default_domain = domains.get(self.config.default_domain)
|
||||
self.default_domain = self.domains.get(self.config.default_domain)
|
||||
|
||||
# monkey-patch, so that domain directives take precedence
|
||||
def directive(directive_name, language_module, document):
|
||||
directive_name = directive_name.lower()
|
||||
if ':' in directive_name:
|
||||
domain_name, directive_name = directive_name.split(':', 1)
|
||||
if domain_name in domains:
|
||||
domain = domains[domain_name]
|
||||
if directive_name in domain.directives:
|
||||
return domain.directives[directive_name], []
|
||||
if domain_name in self.domains:
|
||||
domain = self.domains[domain_name]
|
||||
directive = domain.directive(directive_name)
|
||||
if directive is not None:
|
||||
return directive, []
|
||||
elif self.default_domain is not None:
|
||||
directive = self.default_domain.directives.get(directive_name)
|
||||
directive = self.default_domain.directive(directive_name)
|
||||
if directive is not None:
|
||||
return directive, []
|
||||
return orig_directive_function(directive_name, language_module,
|
||||
@ -619,14 +625,16 @@ class BuildEnvironment:
|
||||
directives.directive = directive
|
||||
|
||||
def role(role_name, language_module, lineno, reporter):
|
||||
role_name = role_name.lower()
|
||||
if ':' in role_name:
|
||||
domain_name, role_name = role_name.split(':', 1)
|
||||
if domain_name in domains:
|
||||
domain = domains[domain_name]
|
||||
if role_name in domain.roles:
|
||||
return domain.roles[role_name], []
|
||||
if domain_name in self.domains:
|
||||
domain = self.domains[domain_name]
|
||||
role = domain.role(role_name)
|
||||
if role is not None:
|
||||
return role, []
|
||||
elif self.default_domain is not None:
|
||||
role = self.default_domain.roles.get(role_name)
|
||||
role = self.default_domain.role(role_name)
|
||||
if role is not None:
|
||||
return role, []
|
||||
return orig_role_function(role_name, language_module,
|
||||
@ -678,6 +686,7 @@ class BuildEnvironment:
|
||||
self.docname = None
|
||||
self.currmodule = None
|
||||
self.currclass = None
|
||||
self.default_domain = None
|
||||
self.gloss_entries = set()
|
||||
|
||||
if save_parsed:
|
||||
@ -987,18 +996,6 @@ class BuildEnvironment:
|
||||
# -------
|
||||
# these are called from docutils directives and therefore use self.docname
|
||||
#
|
||||
def note_descref(self, fullname, desctype, line):
|
||||
if fullname in self.descrefs:
|
||||
self.warn(self.docname,
|
||||
'duplicate canonical description name %s, ' % fullname +
|
||||
'other instance in ' +
|
||||
self.doc2path(self.descrefs[fullname][0]),
|
||||
line)
|
||||
self.descrefs[fullname] = (self.docname, desctype)
|
||||
|
||||
def note_module(self, modname, synopsis, platform, deprecated):
|
||||
self.modules[modname] = (self.docname, synopsis, platform, deprecated)
|
||||
|
||||
def note_progoption(self, optname, labelid):
|
||||
self.progoptions[self.currprogram, optname] = (self.docname, labelid)
|
||||
|
||||
@ -1196,11 +1193,8 @@ class BuildEnvironment:
|
||||
docname, refnode['refuri']) + refnode['anchorname']
|
||||
return newnode
|
||||
|
||||
descroles = frozenset(('data', 'exc', 'func', 'class', 'const',
|
||||
'attr', 'obj', 'meth', 'cfunc', 'cmember',
|
||||
'cdata', 'ctype', 'cmacro'))
|
||||
|
||||
def resolve_references(self, doctree, fromdocname, builder):
|
||||
# XXX remove this
|
||||
reftarget_roles = set(('token', 'term', 'citation'))
|
||||
# add all custom xref types too
|
||||
reftarget_roles.update(i[0] for i in additional_xref_types.values())
|
||||
@ -1213,7 +1207,15 @@ class BuildEnvironment:
|
||||
target = node['reftarget']
|
||||
|
||||
try:
|
||||
if typ == 'ref':
|
||||
if node.has_key('refdomain'):
|
||||
# let the domain try to resolve the reference
|
||||
try:
|
||||
domain = self.domains[node['refdomain']]
|
||||
except KeyError:
|
||||
raise NoUri
|
||||
newnode = domain.resolve_xref(self, fromdocname, builder,
|
||||
typ, target, node, contnode)
|
||||
elif typ == 'ref':
|
||||
if node['refcaption']:
|
||||
# reference to anonymous label; the reference uses
|
||||
# the supplied link caption
|
||||
@ -1278,13 +1280,8 @@ class BuildEnvironment:
|
||||
#self.warn(fromdocname, 'unknown keyword: %s' % target)
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
if docname == fromdocname:
|
||||
newnode['refid'] = labelid
|
||||
else:
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname) + '#' + labelid
|
||||
newnode.append(contnode)
|
||||
newnode = make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
elif typ == 'option':
|
||||
progname = node['refprogram']
|
||||
docname, labelid = self.progoptions.get((progname, target),
|
||||
@ -1292,13 +1289,8 @@ class BuildEnvironment:
|
||||
if not docname:
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
if docname == fromdocname:
|
||||
newnode['refid'] = labelid
|
||||
else:
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname) + '#' + labelid
|
||||
newnode.append(contnode)
|
||||
newnode = make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
elif typ in reftarget_roles:
|
||||
docname, labelid = self.reftargets.get((typ, target),
|
||||
('', ''))
|
||||
@ -1313,62 +1305,19 @@ class BuildEnvironment:
|
||||
node.line)
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
if docname == fromdocname:
|
||||
newnode['refid'] = labelid
|
||||
else:
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname, typ) + '#' + labelid
|
||||
newnode.append(contnode)
|
||||
elif typ == 'mod' or \
|
||||
typ == 'obj' and target in self.modules:
|
||||
docname, synopsis, platform, deprecated = \
|
||||
self.modules.get(target, ('','','', ''))
|
||||
if not docname:
|
||||
newnode = builder.app.emit_firstresult(
|
||||
'missing-reference', self, node, contnode)
|
||||
if not newnode:
|
||||
newnode = contnode
|
||||
elif docname == fromdocname:
|
||||
# don't link to self
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname) + '#module-' + target
|
||||
newnode['reftitle'] = '%s%s%s' % (
|
||||
(platform and '(%s) ' % platform),
|
||||
synopsis, (deprecated and ' (deprecated)' or ''))
|
||||
newnode.append(contnode)
|
||||
elif typ in self.descroles:
|
||||
# "descrefs"
|
||||
modname = node['modname']
|
||||
clsname = node['classname']
|
||||
searchorder = node.hasattr('refspecific') and 1 or 0
|
||||
name, desc = self.find_desc(modname, clsname,
|
||||
target, typ, searchorder)
|
||||
if not desc:
|
||||
newnode = builder.app.emit_firstresult(
|
||||
'missing-reference', self, node, contnode)
|
||||
if not newnode:
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
if desc[0] == fromdocname:
|
||||
newnode['refid'] = name
|
||||
else:
|
||||
newnode['refuri'] = (
|
||||
builder.get_relative_uri(fromdocname, desc[0])
|
||||
+ '#' + name)
|
||||
newnode['reftitle'] = name
|
||||
newnode.append(contnode)
|
||||
newnode = make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
else:
|
||||
raise RuntimeError('unknown xfileref node encountered: %s'
|
||||
% node)
|
||||
|
||||
# no new node found? try the missing-reference event
|
||||
if newnode is None:
|
||||
newnode = builder.app.emit_firstresult(
|
||||
'missing-reference', self, node, contnode)
|
||||
except NoUri:
|
||||
newnode = contnode
|
||||
if newnode:
|
||||
node.replace_self(newnode)
|
||||
node.replace_self(newnode or contnode)
|
||||
|
||||
for node in doctree.traverse(addnodes.only):
|
||||
try:
|
||||
@ -1592,52 +1541,3 @@ class BuildEnvironment:
|
||||
# the master file is not included anywhere ;)
|
||||
continue
|
||||
self.warn(docname, 'document isn\'t included in any toctree')
|
||||
|
||||
# --------- QUERYING -------------------------------------------------------
|
||||
|
||||
def find_desc(self, modname, classname, name, type, searchorder=0):
|
||||
"""Find a description node matching "name", perhaps using
|
||||
the given module and/or classname."""
|
||||
# skip parens
|
||||
if name[-2:] == '()':
|
||||
name = name[:-2]
|
||||
|
||||
if not name:
|
||||
return None, None
|
||||
|
||||
# don't add module and class names for C things
|
||||
if type[0] == 'c' and type not in ('class', 'const'):
|
||||
# skip trailing star and whitespace
|
||||
name = name.rstrip(' *')
|
||||
if name in self.descrefs and self.descrefs[name][1][0] == 'c':
|
||||
return name, self.descrefs[name]
|
||||
return None, None
|
||||
|
||||
newname = None
|
||||
if searchorder == 1:
|
||||
if modname and classname and \
|
||||
modname + '.' + classname + '.' + name in self.descrefs:
|
||||
newname = modname + '.' + classname + '.' + name
|
||||
elif modname and modname + '.' + name in self.descrefs:
|
||||
newname = modname + '.' + name
|
||||
elif name in self.descrefs:
|
||||
newname = name
|
||||
else:
|
||||
if name in self.descrefs:
|
||||
newname = name
|
||||
elif modname and modname + '.' + name in self.descrefs:
|
||||
newname = modname + '.' + name
|
||||
elif modname and classname and \
|
||||
modname + '.' + classname + '.' + name in self.descrefs:
|
||||
newname = modname + '.' + classname + '.' + name
|
||||
# special case: builtin exceptions have module "exceptions" set
|
||||
elif type == 'exc' and '.' not in name and \
|
||||
'exceptions.' + name in self.descrefs:
|
||||
newname = 'exceptions.' + name
|
||||
# special case: object methods
|
||||
elif type in ('func', 'meth') and '.' not in name and \
|
||||
'object.' + name in self.descrefs:
|
||||
newname = 'object.' + name
|
||||
if newname is None:
|
||||
return None, None
|
||||
return newname, self.descrefs[newname]
|
||||
|
@ -79,6 +79,7 @@ class CoverageBuilder(Builder):
|
||||
|
||||
def build_c_coverage(self):
|
||||
# Fetch all the info from the header files
|
||||
c_objects = self.env.domaindata['c']['objects']
|
||||
for filename in self.c_sourcefiles:
|
||||
undoc = []
|
||||
f = open(filename, 'r')
|
||||
@ -88,7 +89,7 @@ class CoverageBuilder(Builder):
|
||||
match = regex.match(line)
|
||||
if match:
|
||||
name = match.groups()[0]
|
||||
if name not in self.env.descrefs:
|
||||
if name not in c_objects:
|
||||
for exp in self.c_ignorexps.get(key, ()):
|
||||
if exp.match(name):
|
||||
break
|
||||
@ -116,7 +117,10 @@ class CoverageBuilder(Builder):
|
||||
op.close()
|
||||
|
||||
def build_py_coverage(self):
|
||||
for mod_name in self.env.modules:
|
||||
objects = self.env.domaindata['py']['objects']
|
||||
modules = self.env.domaindata['py']['modules']
|
||||
|
||||
for mod_name in modules:
|
||||
ignore = False
|
||||
for exp in self.mod_ignorexps:
|
||||
if exp.match(mod_name):
|
||||
@ -151,7 +155,7 @@ class CoverageBuilder(Builder):
|
||||
full_name = '%s.%s' % (mod_name, name)
|
||||
|
||||
if inspect.isfunction(obj):
|
||||
if full_name not in self.env.descrefs:
|
||||
if full_name not in objects:
|
||||
for exp in self.fun_ignorexps:
|
||||
if exp.match(name):
|
||||
break
|
||||
@ -162,7 +166,7 @@ class CoverageBuilder(Builder):
|
||||
if exp.match(name):
|
||||
break
|
||||
else:
|
||||
if full_name not in self.env.descrefs:
|
||||
if full_name not in objects:
|
||||
# not documented at all
|
||||
classes[name] = []
|
||||
continue
|
||||
@ -176,7 +180,7 @@ class CoverageBuilder(Builder):
|
||||
continue
|
||||
|
||||
full_attr_name = '%s.%s' % (full_name, attr_name)
|
||||
if full_attr_name not in self.env.descrefs:
|
||||
if full_attr_name not in objects:
|
||||
attrs.append(attr_name)
|
||||
|
||||
if attrs:
|
||||
|
@ -94,7 +94,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
||||
# make the paths into loaders
|
||||
self.loaders = map(SphinxFileSystemLoader, chain)
|
||||
|
||||
use_i18n = builder.translator is not None
|
||||
use_i18n = builder.app.translator is not None
|
||||
extensions = use_i18n and ['jinja2.ext.i18n'] or []
|
||||
self.environment = SandboxedEnvironment(loader=self,
|
||||
extensions=extensions)
|
||||
@ -102,7 +102,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
||||
self.environment.globals['debug'] = contextfunction(pformat)
|
||||
self.environment.globals['accesskey'] = contextfunction(accesskey)
|
||||
if use_i18n:
|
||||
self.environment.install_gettext_translations(builder.translator)
|
||||
self.environment.install_gettext_translations(builder.app.translator)
|
||||
|
||||
def render(self, template, context):
|
||||
return self.environment.get_template(template).render(context)
|
||||
|
@ -137,9 +137,8 @@ class XRefRole(object):
|
||||
nodeclass = addnodes.pending_xref
|
||||
innernodeclass = nodes.literal
|
||||
|
||||
def __init__(self, domain_name, fix_parens=False, lowercase=False,
|
||||
def __init__(self, fix_parens=False, lowercase=False,
|
||||
nodeclass=None, innernodeclass=None):
|
||||
self.domain_name = domain_name
|
||||
self.fix_parens = fix_parens
|
||||
if nodeclass is not None:
|
||||
self.nodeclass = nodeclass
|
||||
@ -169,10 +168,10 @@ class XRefRole(object):
|
||||
typ = env.config.default_role
|
||||
else:
|
||||
typ = typ.lower()
|
||||
if ":" in typ:
|
||||
domain, role = typ.split(":", 1)
|
||||
if ':' not in typ:
|
||||
domain, role = '', typ
|
||||
else:
|
||||
domain, role = self.domain_name, typ
|
||||
domain, role = typ.split(':', 1)
|
||||
text = utils.unescape(text)
|
||||
# if the first character is a bang, don't cross-reference at all
|
||||
if text[0:1] == '!':
|
||||
@ -212,13 +211,13 @@ class OptionXRefRole(XRefRole):
|
||||
|
||||
|
||||
specific_docroles = {
|
||||
'keyword': XRefRole(''),
|
||||
'ref': XRefRole('', lowercase=True, innernodeclass=nodes.emphasis),
|
||||
'token': XRefRole(''),
|
||||
'term': XRefRole('', lowercase=True, innernodeclass=nodes.emphasis),
|
||||
'option': OptionXRefRole('', innernodeclass=addnodes.literal_emphasis),
|
||||
'doc': XRefRole(''),
|
||||
'download': XRefRole('', nodeclass=addnodes.download_reference),
|
||||
'keyword': XRefRole(),
|
||||
'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
|
||||
'token': XRefRole(),
|
||||
'term': XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
|
||||
'option': OptionXRefRole(innernodeclass=addnodes.literal_emphasis),
|
||||
'doc': XRefRole(),
|
||||
'download': XRefRole(nodeclass=addnodes.download_reference),
|
||||
|
||||
'menuselection': menusel_role,
|
||||
'file': emph_literal_role,
|
||||
|
@ -149,6 +149,8 @@ class IndexBuilder(object):
|
||||
|
||||
def get_modules(self, fn2index):
|
||||
rv = {}
|
||||
# XXX implement search capability
|
||||
return rv
|
||||
for name, (doc, _, _, _) in self.env.modules.iteritems():
|
||||
if doc in fn2index:
|
||||
rv[name] = fn2index[doc]
|
||||
@ -157,6 +159,8 @@ class IndexBuilder(object):
|
||||
def get_descrefs(self, fn2index):
|
||||
rv = {}
|
||||
dt = self._desctypes
|
||||
# XXX implement search capability
|
||||
return rv
|
||||
for fullname, (doc, desctype) in self.env.descrefs.iteritems():
|
||||
if doc not in fn2index:
|
||||
continue
|
||||
|
@ -396,8 +396,10 @@ def movefile(source, dest):
|
||||
def copyfile(source, dest):
|
||||
"""Copy a file and its modification times, if possible."""
|
||||
shutil.copyfile(source, dest)
|
||||
try: shutil.copystat(source, dest)
|
||||
except shutil.Error: pass
|
||||
try:
|
||||
shutil.copystat(source, dest)
|
||||
except shutil.Error:
|
||||
pass
|
||||
|
||||
|
||||
def copy_static_entry(source, target, builder, context={}):
|
||||
@ -435,6 +437,23 @@ def split_explicit_title(text):
|
||||
else:
|
||||
return False, text, text
|
||||
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
def make_refnode(builder, fromdocname, todocname, targetid, child, title=None):
|
||||
"""Shortcut to create a reference node."""
|
||||
node = nodes.reference('', '')
|
||||
if fromdocname == todocname:
|
||||
node['refid'] = targetid
|
||||
else:
|
||||
node['refuri'] = (builder.get_relative_uri(fromdocname, todocname)
|
||||
+ '#' + targetid)
|
||||
if title:
|
||||
node['reftitle'] = title
|
||||
node.append(child)
|
||||
return node
|
||||
|
||||
|
||||
# monkey-patch Node.traverse to get more speed
|
||||
# traverse() is called so many times during a build that it saves
|
||||
# on average 20-25% overall build time!
|
||||
@ -464,8 +483,7 @@ def _new_traverse(self, condition=None,
|
||||
return self._old_traverse(condition, include_self,
|
||||
descend, siblings, ascend)
|
||||
|
||||
import docutils.nodes
|
||||
docutils.nodes.Node._old_traverse = docutils.nodes.Node.traverse
|
||||
docutils.nodes.Node._all_traverse = _all_traverse
|
||||
docutils.nodes.Node._fast_traverse = _fast_traverse
|
||||
docutils.nodes.Node.traverse = _new_traverse
|
||||
nodes.Node._old_traverse = nodes.Node.traverse
|
||||
nodes.Node._all_traverse = _all_traverse
|
||||
nodes.Node._fast_traverse = _fast_traverse
|
||||
nodes.Node.traverse = _new_traverse
|
||||
|
@ -43,15 +43,15 @@ Testing description units
|
||||
C items
|
||||
=======
|
||||
|
||||
.. cfunction:: Sphinx_DoSomething()
|
||||
.. c:function:: Sphinx_DoSomething()
|
||||
|
||||
.. cmember:: SphinxStruct.member
|
||||
.. c:member:: SphinxStruct.member
|
||||
|
||||
.. cmacro:: SPHINX_USE_PYTHON
|
||||
.. c:macro:: SPHINX_USE_PYTHON
|
||||
|
||||
.. ctype:: SphinxType
|
||||
.. c:type:: SphinxType
|
||||
|
||||
.. cvar:: sphinx_global
|
||||
.. c:var:: sphinx_global
|
||||
|
||||
|
||||
Testing references
|
||||
|
@ -20,8 +20,8 @@ warnings = []
|
||||
|
||||
def setup_module():
|
||||
global app, env
|
||||
app = TestApp(srcdir='(temp)')
|
||||
env = BuildEnvironment(app.srcdir, app.doctreedir, app.config)
|
||||
app = TestApp(srcdir='(temp)', freshenv=True)
|
||||
env = app.env
|
||||
env.set_warnfunc(lambda *args: warnings.append(args))
|
||||
|
||||
def teardown_module():
|
||||
@ -51,7 +51,7 @@ def test_images():
|
||||
|
||||
tree = env.get_doctree('images')
|
||||
app._warning.reset()
|
||||
htmlbuilder = StandaloneHTMLBuilder(app, env)
|
||||
htmlbuilder = StandaloneHTMLBuilder(app)
|
||||
htmlbuilder.post_process_images(tree)
|
||||
assert "no matching candidate for image URI u'foo.*'" in \
|
||||
app._warning.content[-1]
|
||||
@ -61,7 +61,7 @@ def test_images():
|
||||
set(['img.png', 'img1.png', 'simg.png', 'svgimg.svg'])
|
||||
|
||||
app._warning.reset()
|
||||
latexbuilder = LaTeXBuilder(app, env)
|
||||
latexbuilder = LaTeXBuilder(app)
|
||||
latexbuilder.post_process_images(tree)
|
||||
assert "no matching candidate for image URI u'foo.*'" in \
|
||||
app._warning.content[-1]
|
||||
@ -92,7 +92,7 @@ def test_second_update():
|
||||
assert 'autodoc' not in env.found_docs
|
||||
|
||||
def test_object_inventory():
|
||||
refs = env.descrefs
|
||||
refs = env.domaindata['py']['objects']
|
||||
|
||||
assert 'func_without_module' in refs
|
||||
assert refs['func_without_module'] == ('desc', 'function')
|
||||
@ -109,5 +109,8 @@ def test_object_inventory():
|
||||
assert 'func_in_module' not in refs
|
||||
assert 'func_noindex' not in refs
|
||||
|
||||
assert 'mod' in env.modules
|
||||
assert env.modules['mod'] == ('desc', 'Module synopsis.', 'UNIX', False)
|
||||
assert env.domaindata['py']['modules']['mod'] == \
|
||||
('desc', 'Module synopsis.', 'UNIX', False)
|
||||
|
||||
assert env.domains['py'].data is env.domaindata['py']
|
||||
assert env.domains['c'].data is env.domaindata['c']
|
||||
|
Loading…
Reference in New Issue
Block a user