summaryrefslogtreecommitdiff
path: root/sphinx/application.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/application.py')
-rw-r--r--sphinx/application.py82
1 files changed, 51 insertions, 31 deletions
diff --git a/sphinx/application.py b/sphinx/application.py
index 8f90e3e64..1e3435c5a 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -36,7 +36,8 @@ from sphinx.domains import ObjType, BUILTIN_DOMAINS
from sphinx.domains.std import GenericObject, Target, StandardDomain
from sphinx.builders import BUILTIN_BUILDERS
from sphinx.environment import BuildEnvironment, SphinxStandaloneReader
-from sphinx.util import pycompat # imported for side-effects
+from sphinx.util import pycompat # noqa: imported for side-effects
+from sphinx.util import import_object
from sphinx.util.tags import Tags
from sphinx.util.osutil import ENOENT
from sphinx.util.console import bold, lightgray, darkgray, darkgreen, \
@@ -77,7 +78,9 @@ class Sphinx(object):
self._extensions = {}
self._extension_metadata = {}
self._listeners = {}
+ self._setting_up_extension = ['?']
self.domains = BUILTIN_DOMAINS.copy()
+ self.buildername = buildername
self.builderclasses = BUILTIN_BUILDERS.copy()
self.builder = None
self.env = None
@@ -110,7 +113,7 @@ class Sphinx(object):
self.messagelog = deque(maxlen=10)
# say hello to the world
- self.info(bold('Running Sphinx v%s' % sphinx.__version__))
+ self.info(bold('Running Sphinx v%s' % sphinx.__display_version__))
# status code for command-line application
self.statuscode = 0
@@ -142,6 +145,7 @@ class Sphinx(object):
self.setup_extension(extension)
# the config file itself can be an extension
if self.config.setup:
+ self._setting_up_extension = ['conf.py']
# py31 doesn't have 'callable' function for below check
if hasattr(self.config.setup, '__call__'):
self.config.setup(self)
@@ -157,7 +161,7 @@ class Sphinx(object):
# check the Sphinx version if requested
if self.config.needs_sphinx and \
- self.config.needs_sphinx > sphinx.__version__[:3]:
+ self.config.needs_sphinx > sphinx.__display_version__[:3]:
raise VersionRequirementError(
'This project needs at least Sphinx v%s and therefore cannot '
'be built with this version.' % self.config.needs_sphinx)
@@ -184,7 +188,7 @@ class Sphinx(object):
# set up the build environment
self._init_env(freshenv)
# set up the builder
- self._init_builder(buildername)
+ self._init_builder(self.buildername)
def _init_i18n(self):
"""Load translated strings from the configured localedirs if enabled in
@@ -198,7 +202,8 @@ class Sphinx(object):
else:
locale_dirs = []
self.translator, has_translation = locale.init(locale_dirs,
- self.config.language)
+ self.config.language,
+ charset=self.config.source_encoding)
if self.config.language is not None:
if has_translation or self.config.language == 'en':
# "en" never needs to be translated
@@ -262,8 +267,8 @@ class Sphinx(object):
self.builder.compile_update_catalogs()
self.builder.build_update()
- status = (self.statuscode == 0
- and 'succeeded' or 'finished with problems')
+ status = (self.statuscode == 0 and
+ 'succeeded' or 'finished with problems')
if self._warncount:
self.info(bold('build %s, %s warning%s.' %
(status, self._warncount,
@@ -424,6 +429,7 @@ class Sphinx(object):
self.debug('[app] setting up extension: %r', extension)
if extension in self._extensions:
return
+ self._setting_up_extension.append(extension)
try:
mod = __import__(extension, None, None, ['setup'])
except ImportError as err:
@@ -445,34 +451,29 @@ class Sphinx(object):
'version.' % (extension, err))
if ext_meta is None:
ext_meta = {}
- if not ext_meta.get('version'):
- ext_meta['version'] = 'unknown version'
+ # special-case for compatibility
+ if extension == 'rst2pdf.pdfbuilder':
+ ext_meta = {'parallel_read_safe': True}
+ try:
+ if not ext_meta.get('version'):
+ ext_meta['version'] = 'unknown version'
+ except Exception:
+ self.warn('extension %r returned an unsupported object from '
+ 'its setup() function; it should return None or a '
+ 'metadata dictionary' % extension)
+ ext_meta = {'version': 'unknown version'}
self._extensions[extension] = mod
self._extension_metadata[extension] = ext_meta
+ self._setting_up_extension.pop()
def require_sphinx(self, version):
# check the Sphinx version if requested
- if version > sphinx.__version__[:3]:
+ if version > sphinx.__display_version__[:3]:
raise VersionRequirementError(version)
def import_object(self, objname, source=None):
"""Import an object from a 'module.name' string."""
- try:
- module, name = objname.rsplit('.', 1)
- except ValueError as err:
- raise ExtensionError('Invalid full object name %s' % objname +
- (source and ' (needed for %s)' % source or ''),
- err)
- try:
- return getattr(__import__(module, None, None, [name]), name)
- except ImportError as err:
- raise ExtensionError('Could not import %s' % module +
- (source and ' (needed for %s)' % source or ''),
- err)
- except AttributeError as err:
- raise ExtensionError('Could not find %s' % objname +
- (source and ' (needed for %s)' % source or ''),
- err)
+ return import_object(objname, source=None)
# event interface
@@ -501,8 +502,9 @@ class Sphinx(object):
def emit(self, event, *args):
try:
self.debug2('[app] emitting event: %r%s', event, repr(args)[:100])
- except Exception: # not every object likes to be repr()'d (think
- # random stuff coming via autodoc)
+ except Exception:
+ # not every object likes to be repr()'d (think
+ # random stuff coming via autodoc)
pass
results = []
if event in self._listeners:
@@ -533,13 +535,14 @@ class Sphinx(object):
builder.name, self.builderclasses[builder.name].__module__))
self.builderclasses[builder.name] = builder
- def add_config_value(self, name, default, rebuild):
- self.debug('[app] adding config value: %r', (name, default, rebuild))
+ def add_config_value(self, name, default, rebuild, types=()):
+ self.debug('[app] adding config value: %r',
+ (name, default, rebuild) + ((types,) if types else ()))
if name in self.config.values:
raise ExtensionError('Config value %r already present' % name)
if rebuild in (False, True):
rebuild = rebuild and 'env' or ''
- self.config.values[name] = (default, rebuild)
+ self.config.values[name] = (default, rebuild, types)
def add_event(self, name):
self.debug('[app] adding event: %r', name)
@@ -553,6 +556,11 @@ class Sphinx(object):
def add_node(self, node, **kwds):
self.debug('[app] adding node: %r', (node, kwds))
+ if not kwds.pop('override', False) and \
+ hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__):
+ self.warn('while setting up extension %s: node class %r is '
+ 'already registered, its visitors will be overridden' %
+ (self._setting_up_extension, node.__name__))
nodes._add_node_class_names([node.__name__])
for key, val in iteritems(kwds):
try:
@@ -597,17 +605,29 @@ class Sphinx(object):
def add_directive(self, name, obj, content=None, arguments=None, **options):
self.debug('[app] adding directive: %r',
(name, obj, content, arguments, options))
+ if name in directives._directives:
+ self.warn('while setting up extension %s: directive %r is '
+ 'already registered, it will be overridden' %
+ (self._setting_up_extension[-1], name))
directives.register_directive(
name, self._directive_helper(obj, content, arguments, **options))
def add_role(self, name, role):
self.debug('[app] adding role: %r', (name, role))
+ if name in roles._roles:
+ self.warn('while setting up extension %s: role %r is '
+ 'already registered, it will be overridden' %
+ (self._setting_up_extension[-1], name))
roles.register_local_role(name, role)
def add_generic_role(self, name, nodeclass):
# don't use roles.register_generic_role because it uses
# register_canonical_role
self.debug('[app] adding generic role: %r', (name, nodeclass))
+ if name in roles._roles:
+ self.warn('while setting up extension %s: role %r is '
+ 'already registered, it will be overridden' %
+ (self._setting_up_extension[-1], name))
role = roles.GenericRole(name, nodeclass)
roles.register_local_role(name, role)