diff options
| author | Georg Brandl <georg@python.org> | 2010-02-28 10:21:00 +0100 |
|---|---|---|
| committer | Georg Brandl <georg@python.org> | 2010-02-28 10:21:00 +0100 |
| commit | 887ee5f5291ccf51bdddf137a4cd8df20b3482a5 (patch) | |
| tree | 3dbe8d2ef949192fa98e98f0489fb0dbfdc8be2b /sphinx/application.py | |
| parent | cb653c494f300f5cc5208524b100878eca8ff8be (diff) | |
| parent | a8cca36b28a33b22e7d79600cfbbd33f5ec4f09a (diff) | |
| download | sphinx-887ee5f5291ccf51bdddf137a4cd8df20b3482a5.tar.gz | |
merge with trunk
Diffstat (limited to 'sphinx/application.py')
| -rw-r--r-- | sphinx/application.py | 180 |
1 files changed, 144 insertions, 36 deletions
diff --git a/sphinx/application.py b/sphinx/application.py index 636d436c..22ca54d4 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -14,22 +14,26 @@ 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, \ VersionRequirementError +from sphinx.domains import ObjType, BUILTIN_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.environment import BuildEnvironment, SphinxStandaloneReader from sphinx.util import pycompat # imported for side-effects from sphinx.util.tags import Tags -from sphinx.util.compat import Directive, directive_dwim +from sphinx.util.osutil import ENOENT from sphinx.util.console import bold @@ -45,23 +49,27 @@ events = { 'missing-reference': 'env, node, contnode', 'doctree-resolved': 'doctree, docname', 'env-updated': 'env', + 'html-collect-pages': 'builder', 'html-page-context': 'pagename, context, doctree or None', 'build-finished': 'exception', } CONFIG_FILENAME = 'conf.py' +ENV_PICKLE_FILENAME = 'environment.pickle' class Sphinx(object): def __init__(self, srcdir, confdir, outdir, doctreedir, buildername, - confoverrides, status, warning=sys.stderr, freshenv=False, - warningiserror=False, tags=None): + confoverrides=None, status=sys.stdout, warning=sys.stderr, + freshenv=False, warningiserror=False, tags=None): self.next_listener_id = 0 self._extensions = {} self._listeners = {} + self.domains = BUILTIN_DOMAINS.copy() self.builderclasses = BUILTIN_BUILDERS.copy() self.builder = None + self.env = None self.srcdir = srcdir self.confdir = confdir @@ -92,7 +100,8 @@ class Sphinx(object): # read config self.tags = Tags(tags) - self.config = Config(confdir, CONFIG_FILENAME, confoverrides, self.tags) + self.config = Config(confdir, CONFIG_FILENAME, + confoverrides or {}, self.tags) self.config.check_unicode(self.warn) # set confdir to srcdir if -C given (!= no confdir); a few pieces @@ -117,8 +126,62 @@ class Sphinx(object): 'This project needs at least Sphinx v%s and therefore cannot ' 'be built with this version.' % self.config.needs_sphinx) + # 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 self.domains.keys(): + self.env.domains[domain] = self.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 self.domains.keys(): + # this can raise if the data version doesn't fit + self.env.domains[domain] = self.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) @@ -129,14 +192,12 @@ 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): + def build(self, force_all=False, filenames=None): try: - if all_files: + if force_all: self.builder.build_all() elif filenames: self.builder.build_specific(filenames) @@ -242,11 +303,11 @@ class Sphinx(object): event.pop(listener_id, None) def emit(self, event, *args): - result = [] + results = [] if event in self._listeners: for _, callback in self._listeners[event].iteritems(): - result.append(callback(self, *args)) - return result + results.append(callback(self, *args)) + return results def emit_firstresult(self, event, *args): for result in self.emit(event, *args): @@ -296,6 +357,9 @@ class Sphinx(object): from sphinx.writers.latex import LaTeXTranslator as translator elif key == 'text': from sphinx.writers.text import TextTranslator as translator + elif key == 'man': + from sphinx.writers.manpage import ManualPageTranslator \ + as translator else: # ignore invalid keys for compatibility continue @@ -303,17 +367,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) @@ -324,23 +392,63 @@ 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): + if domain.name in self.domains: + raise ExtensionError('domain %s already registered' % domain.name) + self.domains[domain.name] = domain + + def override_domain(self, domain): + if domain.name not in self.domains: + raise ExtensionError('domain %s not yet registered' % domain.name) + if not issubclass(domain, self.domains[domain.name]): + raise ExtensionError('new domain not a subclass of registered ' + 'domain' % domain.name) + self.domains[domain.name] = domain + + def add_directive_to_domain(self, domain, name, obj, + content=None, arguments=None, **options): + if domain not in self.domains: + raise ExtensionError('domain %s not yet registered' % domain) + self.domains[domain].directives[name] = \ + self._directive_helper(obj, content, arguments, **options) + + def add_role_to_domain(self, domain, name, role): + if domain not in self.domains: + raise ExtensionError('domain %s not yet registered' % domain) + self.domains[domain].roles[name] = role + + # XXX needs documentation + def add_index_to_domain(self, domain, name, localname, shortname, func): + if domain not in self.domains: + raise ExtensionError('domain %s not yet registered' % domain) + self.domains[domain].indices.append((name, longname, shortname)) + setattr(self.domains[domain], '_get_%s_index' % name, func) + + 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) |
