Merge branch 'stable' into 3860_errors_caused_by_remote_images

This commit is contained in:
Takeshi KOMIYA
2017-07-01 17:21:21 +09:00
committed by GitHub
23 changed files with 202 additions and 141 deletions

View File

@@ -41,6 +41,9 @@ Bugs fixed
* #3860: Don't download images when builders not supported images
* #3860: Remote image URIs without filename break builders not supported remote
images
* #3833: command line messages are translated unintentionally with ``language``
setting.
* #3840: make checking ``epub_uid`` strict
Testing
--------

View File

@@ -34,6 +34,7 @@ epub_theme = 'epub'
epub_basename = 'sphinx'
epub_author = 'Georg Brandl'
epub_publisher = 'http://sphinx-doc.org/'
epub_uid = 'web-site'
epub_scheme = 'url'
epub_identifier = epub_publisher
epub_pre_files = [('index.xhtml', 'Welcome')]

View File

@@ -1360,7 +1360,10 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
.. confval:: epub_uid
A unique identifier for the document. This is put in the Dublin Core
metadata. You may use a random string. The default value is ``'unknown'``.
metadata. You may use a
`XML's Name format <https://www.w3.org/TR/REC-xml/#NT-NameStartChar>`_ string.
You can't use hyphen, period, numbers as a first character.
The default value is ``'unknown'``.
.. confval:: epub_cover

View File

@@ -9,7 +9,7 @@ upload = upload --sign --identity=36580288
[extract_messages]
mapping_file = babel.cfg
output_file = sphinx/locale/sphinx.pot
keywords = _ l_ lazy_gettext
keywords = _ __ l_ lazy_gettext
[update_catalog]
input_file = sphinx/locale/sphinx.pot

View File

@@ -34,7 +34,7 @@ from sphinx.environment import BuildEnvironment
from sphinx.events import EventManager
from sphinx.extension import verify_required_extensions
from sphinx.io import SphinxStandaloneReader
from sphinx.locale import _
from sphinx.locale import __
from sphinx.registry import SphinxComponentRegistry
from sphinx.util import pycompat # noqa: F401
from sphinx.util import import_object
@@ -179,8 +179,8 @@ class Sphinx(object):
# check the Sphinx version if requested
if self.config.needs_sphinx and self.config.needs_sphinx > sphinx.__display_version__:
raise VersionRequirementError(
_('This project needs at least Sphinx v%s and therefore cannot '
'be built with this version.') % self.config.needs_sphinx)
__('This project needs at least Sphinx v%s and therefore cannot '
'be built with this version.') % self.config.needs_sphinx)
# set confdir to srcdir if -C given (!= no confdir); a few pieces
# of code expect a confdir to be set
@@ -206,9 +206,9 @@ class Sphinx(object):
self.config.setup(self)
else:
raise ConfigError(
_("'setup' as currently defined in conf.py isn't a Python callable. "
"Please modify its definition to make it a callable function. This is "
"needed for conf.py to behave as a Sphinx extension.")
__("'setup' as currently defined in conf.py isn't a Python callable. "
"Please modify its definition to make it a callable function. This is "
"needed for conf.py to behave as a Sphinx extension.")
)
# now that we know all config values, collect them from conf.py
@@ -220,7 +220,7 @@ class Sphinx(object):
# check primary_domain if requested
primary_domain = self.config.primary_domain
if primary_domain and not self.registry.has_domain(primary_domain):
logger.warning(_('primary_domain %r not found, ignored.'), primary_domain)
logger.warning(__('primary_domain %r not found, ignored.'), primary_domain)
# create the builder
self.builder = self.create_builder(buildername)
@@ -257,7 +257,7 @@ class Sphinx(object):
if self.config.language is not None:
if has_translation or self.config.language == 'en':
# "en" never needs to be translated
logger.info(_('done'))
logger.info(__('done'))
else:
logger.info('not available for built-in messages')
@@ -278,19 +278,19 @@ class Sphinx(object):
self.env.domains[domain.name] = domain
else:
try:
logger.info(bold(_('loading pickled environment... ')), nonl=True)
logger.info(bold(__('loading pickled environment... ')), nonl=True)
filename = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
self.env = BuildEnvironment.frompickle(filename, self)
self.env.domains = {}
for domain in self.registry.create_domains(self.env):
# this can raise if the data version doesn't fit
self.env.domains[domain.name] = domain
logger.info(_('done'))
logger.info(__('done'))
except Exception as err:
if isinstance(err, IOError) and err.errno == ENOENT:
logger.info(_('not yet created'))
logger.info(__('not yet created'))
else:
logger.info(_('failed: %s'), err)
logger.info(__('failed: %s'), err)
self._init_env(freshenv=True)
def preload_builder(self, name):
@@ -300,7 +300,7 @@ class Sphinx(object):
def create_builder(self, name):
# type: (unicode) -> Builder
if name is None:
logger.info(_('No builder selected, using default: html'))
logger.info(__('No builder selected, using default: html'))
name = 'html'
return self.registry.create_builder(self, name)
@@ -339,13 +339,13 @@ class Sphinx(object):
self.builder.build_update()
status = (self.statuscode == 0 and
_('succeeded') or _('finished with problems'))
__('succeeded') or __('finished with problems'))
if self._warncount:
logger.info(bold(_('build %s, %s warning%s.') %
logger.info(bold(__('build %s, %s warning%s.') %
(status, self._warncount,
self._warncount != 1 and 's' or '')))
else:
logger.info(bold(_('build %s.') % status))
logger.info(bold(__('build %s.') % status))
except Exception as err:
# delete the saved env to force a fresh build next time
envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
@@ -504,7 +504,7 @@ class Sphinx(object):
logger.debug('[app] adding config value: %r',
(name, default, rebuild) + ((types,) if types else ())) # type: ignore
if name in self.config:
raise ExtensionError(_('Config value %r already present') % name)
raise ExtensionError(__('Config value %r already present') % name)
if rebuild in (False, True):
rebuild = rebuild and 'env' or ''
self.config.add(name, default, rebuild, types)
@@ -516,7 +516,7 @@ class Sphinx(object):
def set_translator(self, name, translator_class):
# type: (unicode, Type[nodes.NodeVisitor]) -> None
logger.info(bold(_('Change of translator for the %s builder.') % name))
logger.info(bold(__('Change of translator for the %s builder.') % name))
self.registry.add_translator(name, translator_class)
def add_node(self, node, **kwds):
@@ -524,8 +524,8 @@ class Sphinx(object):
logger.debug('[app] adding node: %r', (node, kwds))
if not kwds.pop('override', False) and \
hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__):
logger.warning(_('while setting up extension %s: node class %r is '
'already registered, its visitors will be overridden'),
logger.warning(__('while setting up extension %s: node class %r is '
'already registered, its visitors will be overridden'),
self._setting_up_extension, node.__name__,
type='app', subtype='add_node')
nodes._add_node_class_names([node.__name__])
@@ -533,8 +533,8 @@ class Sphinx(object):
try:
visit, depart = val
except ValueError:
raise ExtensionError(_('Value for key %r must be a '
'(visit, depart) function tuple') % key)
raise ExtensionError(__('Value for key %r must be a '
'(visit, depart) function tuple') % key)
translator = self.registry.translators.get(key)
translators = []
if translator is not None:
@@ -580,8 +580,8 @@ class Sphinx(object):
logger.debug('[app] adding directive: %r',
(name, obj, content, arguments, options))
if name in directives._directives:
logger.warning(_('while setting up extension %s: directive %r is '
'already registered, it will be overridden'),
logger.warning(__('while setting up extension %s: directive %r is '
'already registered, it will be overridden'),
self._setting_up_extension[-1], name,
type='app', subtype='add_directive')
directive = directive_helper(obj, content, arguments, **options)
@@ -591,8 +591,8 @@ class Sphinx(object):
# type: (unicode, Any) -> None
logger.debug('[app] adding role: %r', (name, role))
if name in roles._roles:
logger.warning(_('while setting up extension %s: role %r is '
'already registered, it will be overridden'),
logger.warning(__('while setting up extension %s: role %r is '
'already registered, it will be overridden'),
self._setting_up_extension[-1], name,
type='app', subtype='add_role')
roles.register_local_role(name, role)
@@ -603,8 +603,8 @@ class Sphinx(object):
# register_canonical_role
logger.debug('[app] adding generic role: %r', (name, nodeclass))
if name in roles._roles:
logger.warning(_('while setting up extension %s: role %r is '
'already registered, it will be overridden'),
logger.warning(__('while setting up extension %s: role %r is '
'already registered, it will be overridden'),
self._setting_up_extension[-1], name,
type='app', subtype='add_generic_role')
role = roles.GenericRole(name, nodeclass)

View File

@@ -17,7 +17,7 @@ from collections import namedtuple
from sphinx import package_dir
from sphinx.config import string_classes, ENUM
from sphinx.builders import _epub_base
from sphinx.util import logging
from sphinx.util import logging, xmlname_checker
from sphinx.util.fileutil import copy_asset_file
if False:
@@ -89,8 +89,8 @@ class Epub3Builder(_epub_base.EpubBuilder):
'conf value "epub_language" (or "language") '
'should not be empty for EPUB3')
# <package> unique-identifier attribute
if not self.app.config.epub_uid:
self.app.warn('conf value "epub_uid" should not be empty for EPUB3')
if not xmlname_checker().match(self.app.config.epub_uid):
self.app.warn('conf value "epub_uid" should be XML NAME for EPUB3')
# dc:title
if not self.app.config.epub_title:
self.app.warn(

View File

@@ -16,7 +16,7 @@ from six import PY2, PY3, iteritems, string_types, binary_type, text_type, integ
from typing import Any, NamedTuple, Union
from sphinx.errors import ConfigError
from sphinx.locale import l_, _
from sphinx.locale import l_, __
from sphinx.util import logging
from sphinx.util.i18n import format_date
from sphinx.util.osutil import cd
@@ -233,8 +233,8 @@ class Config(object):
else:
defvalue = self.values[name][0]
if isinstance(defvalue, dict):
raise ValueError(_('cannot override dictionary config setting %r, '
'ignoring (use %r to set individual elements)') %
raise ValueError(__('cannot override dictionary config setting %r, '
'ignoring (use %r to set individual elements)') %
(name, name + '.key=value'))
elif isinstance(defvalue, list):
return value.split(',')
@@ -242,13 +242,13 @@ class Config(object):
try:
return int(value)
except ValueError:
raise ValueError(_('invalid number %r for config value %r, ignoring') %
raise ValueError(__('invalid number %r for config value %r, ignoring') %
(value, name))
elif hasattr(defvalue, '__call__'):
return value
elif defvalue is not None and not isinstance(defvalue, string_types):
raise ValueError(_('cannot override config setting %r with unsupported '
'type, ignoring') % name)
raise ValueError(__('cannot override config setting %r with unsupported '
'type, ignoring') % name)
else:
return value
@@ -277,7 +277,8 @@ class Config(object):
config.setdefault(realvalname, {})[key] = value
continue
elif valname not in self.values:
logger.warning(_('unknown config value %r in override, ignoring'), valname)
logger.warning(__('unknown config value %r in override, ignoring'),
valname)
continue
if isinstance(value, string_types):
config[valname] = self.convert_overrides(valname, value)
@@ -296,7 +297,7 @@ class Config(object):
if name.startswith('_'):
raise AttributeError(name)
if name not in self.values:
raise AttributeError(_('No such config value: %s') % name)
raise AttributeError(__('No such config value: %s') % name)
default = self.values[name][0]
if hasattr(default, '__call__'):
return default(self)

View File

@@ -16,7 +16,7 @@ from docutils.parsers.rst import Directive, directives
from docutils.statemachine import ViewList
from sphinx import addnodes
from sphinx.locale import _
from sphinx.locale import __
from sphinx.util import logging
from sphinx.util import parselinenos
from sphinx.util.nodes import set_source_info
@@ -63,7 +63,7 @@ def dedent_lines(lines, dedent, location=None):
return lines
if any(s[:dedent].strip() for s in lines):
logger.warning(_('Over dedent has detected'), location=location)
logger.warning(__('Over dedent has detected'), location=location)
new_lines = []
for line in lines:
@@ -83,7 +83,7 @@ def container_wrapper(directive, literal_node, caption):
directive.state.nested_parse(ViewList([caption], source=''),
directive.content_offset, parsed)
if isinstance(parsed[0], nodes.system_message):
msg = _('Invalid caption: %s' % parsed[0].astext())
msg = __('Invalid caption: %s' % parsed[0].astext())
raise ValueError(msg)
caption_node = nodes.caption(parsed[0].rawsource, '',
*parsed[0].children)
@@ -198,7 +198,7 @@ class LiteralIncludeReader(object):
# type: () -> None
for option1, option2 in self.INVALID_OPTIONS_PAIR:
if option1 in self.options and option2 in self.options:
raise ValueError(_('Cannot use both "%s" and "%s" options') %
raise ValueError(__('Cannot use both "%s" and "%s" options') %
(option1, option2))
def read_file(self, filename, location=None):
@@ -211,10 +211,10 @@ class LiteralIncludeReader(object):
return text.splitlines(True)
except (IOError, OSError):
raise IOError(_('Include file %r not found or reading it failed') % filename)
raise IOError(__('Include file %r not found or reading it failed') % filename)
except UnicodeError:
raise UnicodeError(_('Encoding %r used for reading included file %r seems to '
'be wrong, try giving an :encoding: option') %
raise UnicodeError(__('Encoding %r used for reading included file %r seems to '
'be wrong, try giving an :encoding: option') %
(self.encoding, filename))
def read(self, location=None):
@@ -251,7 +251,7 @@ class LiteralIncludeReader(object):
analyzer = ModuleAnalyzer.for_file(self.filename, '')
tags = analyzer.find_tags()
if pyobject not in tags:
raise ValueError(_('Object named %r not found in include file %r') %
raise ValueError(__('Object named %r not found in include file %r') %
(pyobject, self.filename))
else:
start = tags[pyobject][1]
@@ -277,12 +277,12 @@ class LiteralIncludeReader(object):
if all(first + i == n for i, n in enumerate(linelist)):
self.lineno_start += linelist[0]
else:
raise ValueError(_('Cannot use "lineno-match" with a disjoint '
'set of "lines"'))
raise ValueError(__('Cannot use "lineno-match" with a disjoint '
'set of "lines"'))
lines = [lines[n] for n in linelist if n < len(lines)]
if lines == []:
raise ValueError(_('Line spec %r: no lines pulled from include file %r') %
raise ValueError(__('Line spec %r: no lines pulled from include file %r') %
(linespec, self.filename))
return lines

View File

@@ -44,7 +44,7 @@ from sphinx.util.matching import compile_matchers
from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks
from sphinx.util.websupport import is_commentable
from sphinx.errors import SphinxError, ExtensionError
from sphinx.locale import _
from sphinx.locale import __
from sphinx.transforms import SphinxTransformer
from sphinx.versioning import add_uids, merge_doctrees
from sphinx.deprecation import RemovedInSphinx17Warning, RemovedInSphinx20Warning
@@ -565,10 +565,10 @@ class BuildEnvironment(object):
if parallel_available and len(docnames) > 5 and self.app.parallel > 1:
for ext in itervalues(self.app.extensions):
if ext.parallel_read_safe is None:
logger.warning(_('the %s extension does not declare if it is safe '
'for parallel reading, assuming it isn\'t - please '
'ask the extension author to check and make it '
'explicit'), ext.name)
logger.warning(__('the %s extension does not declare if it is safe '
'for parallel reading, assuming it isn\'t - please '
'ask the extension author to check and make it '
'explicit'), ext.name)
logger.warning('doing serial read')
break
elif ext.parallel_read_safe is False:

View File

@@ -17,7 +17,7 @@ from collections import OrderedDict, defaultdict
from six import itervalues
from sphinx.errors import ExtensionError
from sphinx.locale import _
from sphinx.locale import __
if False:
# For type annotation
@@ -54,13 +54,13 @@ class EventManager(object):
def add(self, name):
# type: (unicode) -> None
if name in self.events:
raise ExtensionError(_('Event %r already present') % name)
raise ExtensionError(__('Event %r already present') % name)
self.events[name] = ''
def connect(self, name, callback):
# type: (unicode, Callable) -> int
if name not in self.events:
raise ExtensionError(_('Unknown event name: %s') % name)
raise ExtensionError(__('Unknown event name: %s') % name)
listener_id = self.next_listener_id
self.next_listener_id += 1

View File

@@ -25,7 +25,7 @@ from docutils.statemachine import ViewList
import sphinx
from sphinx.errors import SphinxError
from sphinx.locale import _
from sphinx.locale import _, __
from sphinx.util import logging
from sphinx.util.i18n import search_image_for_language
from sphinx.util.osutil import ensuredir, ENOENT, EPIPE, EINVAL
@@ -93,8 +93,8 @@ class Graphviz(Directive):
document = self.state.document
if self.content:
return [document.reporter.warning(
_('Graphviz directive cannot have both content and '
'a filename argument'), line=self.lineno)]
__('Graphviz directive cannot have both content and '
'a filename argument'), line=self.lineno)]
env = self.state.document.settings.env
argument = search_image_for_language(self.arguments[0], env)
rel_filename, filename = env.relfn2path(argument)
@@ -104,13 +104,13 @@ class Graphviz(Directive):
dotcode = fp.read()
except (IOError, OSError):
return [document.reporter.warning(
_('External Graphviz file %r not found or reading '
'it failed') % filename, line=self.lineno)]
__('External Graphviz file %r not found or reading '
'it failed') % filename, line=self.lineno)]
else:
dotcode = '\n'.join(self.content)
if not dotcode.strip():
return [self.state_machine.reporter.warning(
_('Ignoring "graphviz" directive without content.'),
__('Ignoring "graphviz" directive without content.'),
line=self.lineno)]
node = graphviz()
node['code'] = dotcode
@@ -201,8 +201,8 @@ def render_dot(self, code, options, format, prefix='graphviz'):
except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
logger.warning(_('dot command %r cannot be run (needed for graphviz '
'output), check the graphviz_dot setting'), graphviz_dot)
logger.warning(__('dot command %r cannot be run (needed for graphviz '
'output), check the graphviz_dot setting'), graphviz_dot)
if not hasattr(self.builder, '_graphviz_warned_dot'):
self.builder._graphviz_warned_dot = {}
self.builder._graphviz_warned_dot[graphviz_dot] = True
@@ -219,11 +219,11 @@ def render_dot(self, code, options, format, prefix='graphviz'):
stdout, stderr = p.stdout.read(), p.stderr.read()
p.wait()
if p.returncode != 0:
raise GraphvizError(_('dot exited with error:\n[stderr]\n%s\n'
'[stdout]\n%s') % (stderr, stdout))
raise GraphvizError(__('dot exited with error:\n[stderr]\n%s\n'
'[stdout]\n%s') % (stderr, stdout))
if not path.isfile(outfn):
raise GraphvizError(_('dot did not produce an output file:\n[stderr]\n%s\n'
'[stdout]\n%s') % (stderr, stdout))
raise GraphvizError(__('dot did not produce an output file:\n[stderr]\n%s\n'
'[stdout]\n%s') % (stderr, stdout))
return relfn, outfn
@@ -233,8 +233,8 @@ def render_dot_html(self, node, code, options, prefix='graphviz',
format = self.builder.config.graphviz_output_format
try:
if format not in ('png', 'svg'):
raise GraphvizError(_("graphviz_output_format must be one of 'png', "
"'svg', but is %r") % format)
raise GraphvizError(__("graphviz_output_format must be one of 'png', "
"'svg', but is %r") % format)
fname, outfn = render_dot(self, code, options, format, prefix)
except GraphvizError as exc:
logger.warning('dot code %r: ' % code + str(exc))

View File

@@ -11,7 +11,7 @@
import subprocess
from sphinx.errors import ExtensionError
from sphinx.locale import _
from sphinx.locale import __
from sphinx.transforms.post_transforms.images import ImageConverter
from sphinx.util import logging
from sphinx.util.osutil import ENOENT, EPIPE, EINVAL
@@ -43,8 +43,8 @@ class ImagemagickConverter(ImageConverter):
else:
return False
except (OSError, IOError):
logger.warning(_('convert command %r cannot be run.'
'check the image_converter setting'),
logger.warning(__('convert command %r cannot be run.'
'check the image_converter setting'),
self.config.image_converter)
return False
@@ -60,8 +60,8 @@ class ImagemagickConverter(ImageConverter):
except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
logger.warning(_('convert command %r cannot be run.'
'check the image_converter setting'),
logger.warning(__('convert command %r cannot be run.'
'check the image_converter setting'),
self.config.image_converter)
return False
@@ -73,8 +73,8 @@ class ImagemagickConverter(ImageConverter):
stdout, stderr = p.stdout.read(), p.stderr.read()
p.wait()
if p.returncode != 0:
raise ExtensionError(_('convert exited with error:\n'
'[stderr]\n%s\n[stdout]\n%s') %
raise ExtensionError(__('convert exited with error:\n'
'[stderr]\n%s\n[stdout]\n%s') %
(stderr, stdout))
return True

View File

@@ -13,7 +13,7 @@ from docutils import nodes, utils
from docutils.parsers.rst import Directive, directives
from sphinx.roles import XRefRole
from sphinx.locale import _
from sphinx.locale import __
from sphinx.domains import Domain
from sphinx.util.nodes import make_refnode, set_source_info
@@ -103,7 +103,7 @@ class MathDomain(Domain):
equations = self.data['objects']
if labelid in equations:
path = env.doc2path(equations[labelid][0])
msg = _('duplicate label of equation %s, other instance in %s') % (labelid, path)
msg = __('duplicate label of equation %s, other instance in %s') % (labelid, path)
raise UserWarning(msg)
else:
eqno = self.get_next_equation_number(docname)

View File

@@ -12,7 +12,7 @@
from six import iteritems
from sphinx.errors import VersionRequirementError
from sphinx.locale import _
from sphinx.locale import __
from sphinx.util import logging
if False:
@@ -50,12 +50,12 @@ def verify_required_extensions(app, requirements):
for extname, reqversion in iteritems(requirements):
extension = app.extensions.get(extname)
if extension is None:
logger.warning(_('The %s extension is required by needs_extensions settings,'
'but it is not loaded.'), extname)
logger.warning(__('The %s extension is required by needs_extensions settings,'
'but it is not loaded.'), extname)
continue
if extension.version == 'unknown version' or reqversion > extension.version:
raise VersionRequirementError(_('This project needs the extension %s at least in '
'version %s and therefore cannot be built with '
'the loaded version (%s).') %
raise VersionRequirementError(__('This project needs the extension %s at least in '
'version %s and therefore cannot be built with '
'the loaded version (%s).') %
(extname, reqversion, extension.version))

View File

@@ -242,6 +242,16 @@ else:
return message
def __(message):
# type: (unicode) -> unicode
"""A dummy wrapper to i18n'ize exceptions and command line messages.
In future, the messages are translated using LC_MESSAGES or any other
locale settings.
"""
return message
def init(locale_dirs, language, catalog='sphinx'):
# type: (List, unicode, unicode) -> Tuple[Any, bool]
"""Look for message catalogs in `locale_dirs` and *ensure* that there is at

View File

@@ -19,7 +19,7 @@ from sphinx.errors import ExtensionError, SphinxError, VersionRequirementError
from sphinx.extension import Extension
from sphinx.domains import ObjType
from sphinx.domains.std import GenericObject, Target
from sphinx.locale import _
from sphinx.locale import __
from sphinx.roles import XRefRole
from sphinx.util import logging
from sphinx.util.docutils import directive_helper
@@ -53,9 +53,9 @@ class SphinxComponentRegistry(object):
def add_builder(self, builder):
# type: (Type[Builder]) -> None
if not hasattr(builder, 'name'):
raise ExtensionError(_('Builder class %s has no "name" attribute') % builder)
raise ExtensionError(__('Builder class %s has no "name" attribute') % builder)
if builder.name in self.builders:
raise ExtensionError(_('Builder %r already exists (in module %s)') %
raise ExtensionError(__('Builder %r already exists (in module %s)') %
(builder.name, self.builders[builder.name].__module__))
self.builders[builder.name] = builder
@@ -69,22 +69,22 @@ class SphinxComponentRegistry(object):
try:
entry_point = next(entry_points)
except StopIteration:
raise SphinxError(_('Builder name %s not registered or available'
' through entry point') % name)
raise SphinxError(__('Builder name %s not registered or available'
' through entry point') % name)
self.load_extension(app, entry_point.module_name)
def create_builder(self, app, name):
# type: (Sphinx, unicode) -> Builder
if name not in self.builders:
raise SphinxError(_('Builder name %s not registered') % name)
raise SphinxError(__('Builder name %s not registered') % name)
return self.builders[name](app)
def add_domain(self, domain):
# type: (Type[Domain]) -> None
if domain.name in self.domains:
raise ExtensionError(_('domain %s already registered') % domain.name)
raise ExtensionError(__('domain %s already registered') % domain.name)
self.domains[domain.name] = domain
def has_domain(self, domain):
@@ -99,30 +99,30 @@ class SphinxComponentRegistry(object):
def override_domain(self, domain):
# type: (Type[Domain]) -> None
if domain.name not in self.domains:
raise ExtensionError(_('domain %s not yet registered') % domain.name)
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 %s '
'domain') % domain.name)
raise ExtensionError(__('new domain not a subclass of registered %s '
'domain') % domain.name)
self.domains[domain.name] = domain
def add_directive_to_domain(self, domain, name, obj,
has_content=None, argument_spec=None, **option_spec):
# type: (unicode, unicode, Any, bool, Any, Any) -> None
if domain not in self.domains:
raise ExtensionError(_('domain %s not yet registered') % domain)
raise ExtensionError(__('domain %s not yet registered') % domain)
directive = directive_helper(obj, has_content, argument_spec, **option_spec)
self.domains[domain].directives[name] = directive
def add_role_to_domain(self, domain, name, role):
# type: (unicode, unicode, Any) -> None
if domain not in self.domains:
raise ExtensionError(_('domain %s not yet registered') % domain)
raise ExtensionError(__('domain %s not yet registered') % domain)
self.domains[domain].roles[name] = role
def add_index_to_domain(self, domain, index):
# type: (unicode, Type[Index]) -> None
if domain not in self.domains:
raise ExtensionError(_('domain %s not yet registered') % domain)
raise ExtensionError(__('domain %s not yet registered') % domain)
self.domains[domain].indices.append(index)
def add_object_type(self, directivename, rolename, indextemplate='',
@@ -157,7 +157,7 @@ class SphinxComponentRegistry(object):
def add_source_parser(self, suffix, parser):
# type: (unicode, Parser) -> None
if suffix in self.source_parsers:
raise ExtensionError(_('source_parser for %r is already registered') % suffix)
raise ExtensionError(__('source_parser for %r is already registered') % suffix)
self.source_parsers[suffix] = parser
def get_source_parsers(self):
@@ -184,8 +184,8 @@ class SphinxComponentRegistry(object):
if extname in app.extensions: # alread loaded
return
if extname in EXTENSION_BLACKLIST:
logger.warning(_('the extension %r was already merged with Sphinx since '
'version %s; this extension is ignored.'),
logger.warning(__('the extension %r was already merged with Sphinx since '
'version %s; this extension is ignored.'),
extname, EXTENSION_BLACKLIST[extname])
return
@@ -195,12 +195,12 @@ class SphinxComponentRegistry(object):
try:
mod = __import__(extname, None, None, ['setup'])
except ImportError as err:
logger.verbose(_('Original exception:\n') + traceback.format_exc())
raise ExtensionError(_('Could not import extension %s') % extname, err)
logger.verbose(__('Original exception:\n') + traceback.format_exc())
raise ExtensionError(__('Could not import extension %s') % extname, err)
if not hasattr(mod, 'setup'):
logger.warning(_('extension %r has no setup() function; is it really '
'a Sphinx extension module?'), extname)
logger.warning(__('extension %r has no setup() function; is it really '
'a Sphinx extension module?'), extname)
metadata = {} # type: Dict[unicode, Any]
else:
try:
@@ -208,9 +208,9 @@ class SphinxComponentRegistry(object):
except VersionRequirementError as err:
# add the extension name to the version required
raise VersionRequirementError(
_('The %s extension used by this project needs at least '
'Sphinx v%s; it therefore cannot be built with this '
'version.') % (extname, err)
__('The %s extension used by this project needs at least '
'Sphinx v%s; it therefore cannot be built with this '
'version.') % (extname, err)
)
if metadata is None:
@@ -218,9 +218,9 @@ class SphinxComponentRegistry(object):
if extname == 'rst2pdf.pdfbuilder':
metadata['parallel_read_safe'] = True
elif not isinstance(metadata, dict):
logger.warning(_('extension %r returned an unsupported object from '
'its setup() function; it should return None or a '
'metadata dictionary'), extname)
logger.warning(__('extension %r returned an unsupported object from '
'its setup() function; it should return None or a '
'metadata dictionary'), extname)
app.extensions[extname] = Extension(extname, mod, **metadata)
app._setting_up_extension.pop()

View File

@@ -23,7 +23,7 @@ from six.moves import configparser
from sphinx import package_dir
from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.errors import ThemeError
from sphinx.locale import _
from sphinx.locale import __
from sphinx.util import logging
from sphinx.util.osutil import ensuredir
@@ -80,15 +80,15 @@ class Theme(object):
try:
inherit = self.config.get('theme', 'inherit')
except configparser.NoSectionError:
raise ThemeError(_('theme %r doesn\'t have "theme" setting') % name)
raise ThemeError(__('theme %r doesn\'t have "theme" setting') % name)
except configparser.NoOptionError:
raise ThemeError(_('theme %r doesn\'t have "inherit" setting') % name)
raise ThemeError(__('theme %r doesn\'t have "inherit" setting') % name)
if inherit != 'none':
try:
self.base = factory.create(inherit)
except ThemeError:
raise ThemeError(_('no theme named %r found, inherited by %r') %
raise ThemeError(__('no theme named %r found, inherited by %r') %
(inherit, name))
def get_theme_dirs(self):
@@ -113,8 +113,8 @@ class Theme(object):
return self.base.get_config(section, name, default)
if default is NODEFAULT:
raise ThemeError(_('setting %s.%s occurs in none of the '
'searched theme configs') % (section, name))
raise ThemeError(__('setting %s.%s occurs in none of the '
'searched theme configs') % (section, name))
else:
return default
@@ -234,7 +234,7 @@ class HTMLThemeFactory(object):
if callable(target):
themedir = target()
if not isinstance(themedir, string_types):
logger.warning(_('Theme extension %r does not respond correctly.') %
logger.warning(__('Theme extension %r does not respond correctly.') %
entry_point.module_name)
else:
themedir = target
@@ -261,8 +261,8 @@ class HTMLThemeFactory(object):
name = entry[:-4]
themes[name] = pathname
else:
logger.warning(_('file %r on theme path is not a valid '
'zipfile or contains no theme'), entry)
logger.warning(__('file %r on theme path is not a valid '
'zipfile or contains no theme'), entry)
else:
if path.isfile(path.join(pathname, THEMECONF)):
themes[entry] = pathname
@@ -277,11 +277,11 @@ class HTMLThemeFactory(object):
if name not in self.themes:
if name == 'sphinx_rtd_theme':
raise ThemeError(_('sphinx_rtd_theme is no longer a hard dependency '
'since version 1.4.0. Please install it manually.'
'(pip install sphinx_rtd_theme)'))
raise ThemeError(__('sphinx_rtd_theme is no longer a hard dependency '
'since version 1.4.0. Please install it manually.'
'(pip install sphinx_rtd_theme)'))
else:
raise ThemeError(_('no theme named %r found '
'(missing theme.conf?)') % name)
raise ThemeError(__('no theme named %r found '
'(missing theme.conf?)') % name)
return Theme(name, self.themes[name], factory=self)

View File

@@ -17,7 +17,7 @@ from docutils.utils import get_source_line
from sphinx import addnodes
from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.environment import NoUri
from sphinx.locale import _
from sphinx.locale import __
from sphinx.transforms import SphinxTransform
from sphinx.util import logging
@@ -135,8 +135,8 @@ class ReferencesResolver(SphinxTransform):
return None
if len(results) > 1:
nice_results = ' or '.join(':%s:' % r[0] for r in results)
logger.warning(_('more than one target found for \'any\' cross-'
'reference %r: could be %s'), target, nice_results,
logger.warning(__('more than one target found for \'any\' cross-'
'reference %r: could be %s'), target, nice_results,
location=node)
res_role, newnode = results[0]
# Override "any" class with the actual role type to get the styling
@@ -165,10 +165,10 @@ class ReferencesResolver(SphinxTransform):
if domain and typ in domain.dangling_warnings:
msg = domain.dangling_warnings[typ]
elif node.get('refdomain', 'std') not in ('', 'std'):
msg = (_('%s:%s reference target not found: %%(target)s') %
msg = (__('%s:%s reference target not found: %%(target)s') %
(node['refdomain'], typ))
else:
msg = _('%r reference target not found: %%(target)s') % typ
msg = __('%r reference target not found: %%(target)s') % typ
logger.warning(msg % {'target': target},
location=node, type='ref', subtype=typ)

View File

@@ -631,3 +631,36 @@ def epoch_to_rfc1123(epoch):
def rfc1123_to_epoch(rfc1123):
return mktime(strptime(rfc1123, '%a, %d %b %Y %H:%M:%S %Z'))
def xmlname_checker():
# https://www.w3.org/TR/REC-xml/#NT-Name
# Only Python 3.3 or newer support character code in regular expression
name_start_chars = [
u':', [u'A', u'Z'], u'_', [u'a', u'z'], [u'\u00C0', u'\u00D6'],
[u'\u00D8', u'\u00F6'], [u'\u00F8', u'\u02FF'], [u'\u0370', u'\u037D'],
[u'\u037F', u'\u1FFF'], [u'\u200C', u'\u200D'], [u'\u2070', u'\u218F'],
[u'\u2C00', u'\u2FEF'], [u'\u3001', u'\uD7FF'], [u'\uF900', u'\uFDCF'],
[u'\uFDF0', u'\uFFFD']]
if sys.version_info.major == 3:
name_start_chars.append([u'\U00010000', u'\U000EFFFF'])
name_chars = [
u"\\-", u"\\.", [u'0', u'9'], u'\u00B7', [u'\u0300', u'\u036F'],
[u'\u203F', u'\u2040']
]
def convert(entries, splitter=u'|'):
results = []
for entry in entries:
if isinstance(entry, list):
results.append(u'[%s]' % convert(entry, u'-'))
else:
results.append(entry)
return splitter.join(results)
start_chars_regex = convert(name_start_chars)
name_chars_regex = convert(name_chars)
return re.compile(u'(%s)(%s|%s)*' % (
start_chars_regex, start_chars_regex, name_chars_regex))

View File

@@ -35,9 +35,8 @@ class _DeprecationWrapper(object):
def __getattr__(self, attr):
# type: (str) -> Any
if attr in self._deprecated:
warnings.warn("sphinx.util.compat.%s is deprecated and will be "
"removed in Sphinx 1.7, please use the standard "
"library version instead." % attr,
warnings.warn("sphinx.util.compat.%s is deprecated and will be removed "
"in Sphinx 1.7, please use docutils' instead." % attr,
RemovedInSphinx17Warning)
return self._deprecated[attr]
return getattr(self._mod, attr)

View File

@@ -22,7 +22,7 @@ from docutils.utils import Reporter
from docutils.parsers.rst import directives, roles, convert_directive_function
from sphinx.errors import ExtensionError
from sphinx.locale import _
from sphinx.locale import __
from sphinx.util import logging
logger = logging.getLogger(__name__)
@@ -193,6 +193,6 @@ def directive_helper(obj, has_content=None, argument_spec=None, **option_spec):
return convert_directive_function(obj)
else:
if has_content or argument_spec or option_spec:
raise ExtensionError(_('when adding directive classes, no '
'additional arguments may be given'))
raise ExtensionError(__('when adding directive classes, no '
'additional arguments may be given'))
return obj

View File

@@ -245,3 +245,5 @@ def test_epub_writing_mode(app):
# vertical / writing-mode (CSS)
css = (app.outdir / '_static' / 'epub.css').text()
assert 'writing-mode: vertical-rl;' in css

View File

@@ -14,7 +14,8 @@ from mock import patch
from sphinx.util import logging
from sphinx.util import (
display_chunk, encode_uri, parselinenos, split_docinfo, status_iterator
display_chunk, encode_uri, parselinenos, split_docinfo, status_iterator,
xmlname_checker
)
from sphinx.testing.util import strip_escseq
@@ -115,3 +116,11 @@ def test_parselinenos():
parselinenos('-', 10)
with pytest.raises(ValueError):
parselinenos('3-1', 10)
def test_xmlname_check():
checker = xmlname_checker()
assert checker.match('id-pub')
assert checker.match('webpage')
assert not checker.match('1bfda21')