diff options
Diffstat (limited to 'sphinx/application.py')
-rw-r--r-- | sphinx/application.py | 148 |
1 files changed, 119 insertions, 29 deletions
diff --git a/sphinx/application.py b/sphinx/application.py index ad3a08330..99753b73a 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -14,21 +14,24 @@ 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 +from docutils.parsers.rst import Directive, convert_directive_function, \ + directives, roles import sphinx -from sphinx.roles import xfileref_role, innernodetypes +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 ObjType, all_domains +from sphinx.domains.std import GenericObject, Target, StandardDomain from sphinx.builders import BUILTIN_BUILDERS -from sphinx.directives import GenericDesc, Target, additional_xref_types -from sphinx.environment import SphinxStandaloneReader -from sphinx.util import pycompat # imported for side-effects +from sphinx.environment import BuildEnvironment, SphinxStandaloneReader +from sphinx.util import ENOENT, pycompat # pycompat imported for side-effects from sphinx.util.tags import Tags -from sphinx.util.compat import Directive, directive_dwim from sphinx.util.console import bold @@ -49,6 +52,7 @@ events = { } CONFIG_FILENAME = 'conf.py' +ENV_PICKLE_FILENAME = 'environment.pickle' class Sphinx(object): @@ -61,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 @@ -103,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 == ENOENT: + 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) @@ -115,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): @@ -277,17 +334,21 @@ class Sphinx(object): if depart: setattr(translator, 'depart_'+node.__name__, depart) - def add_directive(self, name, obj, content=None, arguments=None, **options): + def _directive_helper(self, obj, content=None, arguments=None, **options): if isinstance(obj, clstypes) and issubclass(obj, Directive): if content or arguments or options: raise ExtensionError('when adding directive classes, no ' 'additional arguments may be given') - directives.register_directive(name, directive_dwim(obj)) + return obj else: obj.content = content - obj.arguments = arguments + obj.arguments = arguments or (0, 0, False) obj.options = options - directives.register_directive(name, obj) + return convert_directive_function(obj) + + def add_directive(self, name, obj, content=None, arguments=None, **options): + directives.register_directive( + name, self._directive_helper(obj, content, arguments, **options)) def add_role(self, name, role): roles.register_local_role(name, role) @@ -298,23 +359,52 @@ class Sphinx(object): role = roles.GenericRole(name, nodeclass) roles.register_local_role(name, role) - def add_description_unit(self, directivename, rolename, indextemplate='', - parse_node=None, ref_nodeclass=None): - additional_xref_types[directivename] = (rolename, indextemplate, - parse_node) - directives.register_directive(directivename, - directive_dwim(GenericDesc)) - roles.register_local_role(rolename, xfileref_role) - if ref_nodeclass is not None: - innernodetypes[rolename] = ref_nodeclass + def add_domain(self, domain): + # XXX needs to be documented + # XXX what about subclassing and overriding? + if domain.name in all_domains: + raise ExtensionError('domain %s already registered' % domain.name) + all_domains[domain.name] = domain + + def add_directive_to_domain(self, domain, name, obj, + content=None, arguments=None, **options): + # XXX needs to be documented + if domain not in all_domains: + raise ExtensionError('domain %s not yet registered' % domain) + all_domains[domain].directives[name] = \ + self._directive_helper(obj, content, arguments, **options) + + def add_role_to_domain(self, domain, name, role): + # XXX needs to be documented + if domain not in all_domains: + raise ExtensionError('domain %s not yet registered' % domain) + all_domains[domain].roles[name] = role + + def add_object_type(self, directivename, rolename, indextemplate='', + parse_node=None, ref_nodeclass=None, objname=''): + StandardDomain.object_types[directivename] = \ + ObjType(objname or directivename, rolename) + # create a subclass of GenericObject as the new directive + new_directive = type(directivename, (GenericObject, object), + {'indextemplate': indextemplate, + 'parse_node': staticmethod(parse_node)}) + StandardDomain.directives[directivename] = new_directive + # XXX support more options? + StandardDomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass) + + # backwards compatible alias + add_description_unit = add_object_type def add_crossref_type(self, directivename, rolename, indextemplate='', - ref_nodeclass=None): - additional_xref_types[directivename] = (rolename, indextemplate, None) - directives.register_directive(directivename, directive_dwim(Target)) - roles.register_local_role(rolename, xfileref_role) - if ref_nodeclass is not None: - innernodetypes[rolename] = ref_nodeclass + ref_nodeclass=None, objname=''): + StandardDomain.object_types[directivename] = \ + ObjType(objname or directivename, rolename) + # create a subclass of Target as the new directive + new_directive = type(directivename, (Target, object), + {'indextemplate': indextemplate}) + StandardDomain.directives[directivename] = new_directive + # XXX support more options? + StandardDomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass) def add_transform(self, transform): SphinxStandaloneReader.transforms.append(transform) |