summaryrefslogtreecommitdiff
path: root/sphinx/application.py
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2010-02-28 10:21:00 +0100
committerGeorg Brandl <georg@python.org>2010-02-28 10:21:00 +0100
commit887ee5f5291ccf51bdddf137a4cd8df20b3482a5 (patch)
tree3dbe8d2ef949192fa98e98f0489fb0dbfdc8be2b /sphinx/application.py
parentcb653c494f300f5cc5208524b100878eca8ff8be (diff)
parenta8cca36b28a33b22e7d79600cfbbd33f5ec4f09a (diff)
downloadsphinx-887ee5f5291ccf51bdddf137a4cd8df20b3482a5.tar.gz
merge with trunk
Diffstat (limited to 'sphinx/application.py')
-rw-r--r--sphinx/application.py180
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)