mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch 'stable'
This commit is contained in:
26
CHANGES
26
CHANGES
@@ -56,7 +56,7 @@ Bugs fixed
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 1.6.3 (in development)
|
||||
Release 1.6.4 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
@@ -71,6 +71,18 @@ Deprecated
|
||||
Features added
|
||||
--------------
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 1.6.3 (released Jul 02, 2017)
|
||||
=====================================
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* latex: hint that code-block continues on next page (refs: #3764, #3792)
|
||||
|
||||
Bugs fixed
|
||||
@@ -96,9 +108,15 @@ Bugs fixed
|
||||
* #3873: Failure of deprecation warning mechanism of
|
||||
``sphinx.util.compat.Directive``
|
||||
* #3874: Bogus warnings for "citation not referenced" for cross-file citations
|
||||
|
||||
Testing
|
||||
--------
|
||||
* #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
|
||||
* #3851, #3706: Fix about box drawing characters for PDF output
|
||||
* #3900: autosummary could not find methods
|
||||
* #3902: Emit error if ``latex_documents`` contains non-unicode string in py2
|
||||
|
||||
Release 1.6.2 (released May 28, 2017)
|
||||
=====================================
|
||||
|
||||
@@ -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')]
|
||||
|
||||
@@ -1351,7 +1351,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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -49,6 +49,11 @@ class translatable(object):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class not_smartquotable(object):
|
||||
"""A node which does not support smart-quotes."""
|
||||
support_smartquotes = False
|
||||
|
||||
|
||||
class toctree(nodes.General, nodes.Element, translatable):
|
||||
"""Node for inserting a "TOC tree"."""
|
||||
|
||||
@@ -91,7 +96,7 @@ class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
"""
|
||||
|
||||
|
||||
class desc_signature_line(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
class desc_signature_line(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for a line in a multi-line object signatures.
|
||||
|
||||
It should only be used in a ``desc_signature`` with ``is_multiline`` set.
|
||||
@@ -101,7 +106,7 @@ class desc_signature_line(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
|
||||
# nodes to use within a desc_signature or desc_signature_line
|
||||
|
||||
class desc_addname(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
class desc_addname(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for additional name parts (module name, class name)."""
|
||||
|
||||
|
||||
@@ -109,7 +114,7 @@ class desc_addname(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
desc_classname = desc_addname
|
||||
|
||||
|
||||
class desc_type(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
class desc_type(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for return types or object type names."""
|
||||
|
||||
|
||||
@@ -120,20 +125,20 @@ class desc_returns(desc_type):
|
||||
return ' -> ' + nodes.TextElement.astext(self)
|
||||
|
||||
|
||||
class desc_name(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
class desc_name(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for the main object name."""
|
||||
|
||||
|
||||
class desc_parameterlist(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
class desc_parameterlist(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for a general parameter list."""
|
||||
child_text_separator = ', '
|
||||
|
||||
|
||||
class desc_parameter(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
class desc_parameter(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for a single parameter."""
|
||||
|
||||
|
||||
class desc_optional(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
class desc_optional(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for marking optional parts of the parameter list."""
|
||||
child_text_separator = ', '
|
||||
|
||||
@@ -142,7 +147,7 @@ class desc_optional(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
return '[' + nodes.TextElement.astext(self) + ']'
|
||||
|
||||
|
||||
class desc_annotation(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
class desc_annotation(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for signature annotations (not Python 3-style annotations)."""
|
||||
|
||||
|
||||
@@ -174,7 +179,7 @@ class productionlist(nodes.Admonition, nodes.Element):
|
||||
"""
|
||||
|
||||
|
||||
class production(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
class production(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for a single grammar production rule."""
|
||||
|
||||
|
||||
@@ -266,13 +271,13 @@ class download_reference(nodes.reference):
|
||||
"""Node for download references, similar to pending_xref."""
|
||||
|
||||
|
||||
class literal_emphasis(nodes.emphasis):
|
||||
class literal_emphasis(nodes.emphasis, not_smartquotable):
|
||||
"""Node that behaves like `emphasis`, but further text processors are not
|
||||
applied (e.g. smartypants for HTML output).
|
||||
"""
|
||||
|
||||
|
||||
class literal_strong(nodes.strong):
|
||||
class literal_strong(nodes.strong, not_smartquotable):
|
||||
"""Node that behaves like `strong`, but further text processors are not
|
||||
applied (e.g. smartypants for HTML output).
|
||||
"""
|
||||
@@ -282,7 +287,7 @@ class abbreviation(nodes.Inline, nodes.TextElement):
|
||||
"""Node for abbreviations with explanations."""
|
||||
|
||||
|
||||
class manpage(nodes.Inline, nodes.TextElement):
|
||||
class manpage(nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for references to manpages."""
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -177,8 +177,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
|
||||
@@ -204,9 +204,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
|
||||
@@ -218,7 +218,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)
|
||||
@@ -255,7 +255,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')
|
||||
|
||||
@@ -276,19 +276,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):
|
||||
@@ -298,7 +298,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)
|
||||
@@ -330,13 +330,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)
|
||||
@@ -451,7 +451,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)
|
||||
@@ -463,7 +463,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):
|
||||
@@ -471,8 +471,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__])
|
||||
@@ -480,8 +480,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:
|
||||
@@ -520,8 +520,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)
|
||||
@@ -531,8 +531,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)
|
||||
@@ -543,8 +543,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)
|
||||
|
||||
@@ -22,6 +22,7 @@ from six import itervalues
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx20Warning
|
||||
from sphinx.environment.adapters.asset import ImageAdapter
|
||||
from sphinx.util import i18n, path_stabilize, logging, status_iterator
|
||||
from sphinx.util.osutil import SEP, relative_uri
|
||||
from sphinx.util.i18n import find_catalog
|
||||
@@ -197,6 +198,7 @@ class Builder(object):
|
||||
def post_process_images(self, doctree):
|
||||
# type: (nodes.Node) -> None
|
||||
"""Pick the best candidate for all image URIs."""
|
||||
images = ImageAdapter(self.env)
|
||||
for node in doctree.traverse(nodes.image):
|
||||
if '?' in node['candidates']:
|
||||
# don't rewrite nonlocal image URIs
|
||||
@@ -207,7 +209,8 @@ class Builder(object):
|
||||
if candidate:
|
||||
break
|
||||
else:
|
||||
logger.warning('no matching candidate for image URI %r', node['uri'],
|
||||
logger.warning('no matching candidate for image URI %r',
|
||||
images.get_original_image_uri(node['uri']),
|
||||
location=node)
|
||||
continue
|
||||
node['uri'] = candidate
|
||||
|
||||
@@ -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
|
||||
from sphinx.util.osutil import make_filename
|
||||
|
||||
@@ -90,8 +90,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(
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
import os
|
||||
from os import path
|
||||
|
||||
from six import text_type
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.io import FileOutput
|
||||
from docutils.utils import new_document
|
||||
@@ -19,7 +21,7 @@ from docutils.frontend import OptionParser
|
||||
|
||||
from sphinx import package_dir, addnodes, highlighting
|
||||
from sphinx.config import string_classes, ENUM
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.errors import SphinxError, ConfigError
|
||||
from sphinx.locale import _
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.environment import NoUri
|
||||
@@ -254,6 +256,26 @@ class LaTeXBuilder(Builder):
|
||||
path.join(self.srcdir, src), err)
|
||||
|
||||
|
||||
def validate_config_values(app):
|
||||
# type: (Sphinx) -> None
|
||||
for document in app.config.latex_documents:
|
||||
try:
|
||||
text_type(document[2])
|
||||
except UnicodeDecodeError:
|
||||
raise ConfigError(
|
||||
'Invalid latex_documents.title found (might contain non-ASCII chars. '
|
||||
'Please use u"..." notation instead): %r' % (document,)
|
||||
)
|
||||
|
||||
try:
|
||||
text_type(document[3])
|
||||
except UnicodeDecodeError:
|
||||
raise ConfigError(
|
||||
'Invalid latex_documents.author found (might contain non-ASCII chars. '
|
||||
'Please use u"..." notation instead): %r' % (document,)
|
||||
)
|
||||
|
||||
|
||||
def default_latex_engine(config):
|
||||
# type: (Config) -> unicode
|
||||
""" Better default latex_engine settings for specific languages. """
|
||||
@@ -276,6 +298,7 @@ def default_latex_docclass(config):
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[unicode, Any]
|
||||
app.add_builder(LaTeXBuilder)
|
||||
app.connect('builder-inited', validate_config_values)
|
||||
|
||||
app.add_config_value('latex_engine', default_latex_engine, None,
|
||||
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex'))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -195,7 +195,10 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
|
||||
continue
|
||||
documenter = get_documenter(value, obj)
|
||||
if documenter.objtype == typ:
|
||||
if imported or getattr(value, '__module__', None) == obj.__name__:
|
||||
if typ == 'method':
|
||||
items.append(name)
|
||||
elif imported or getattr(value, '__module__', None) == obj.__name__:
|
||||
# skip imported members if expected
|
||||
items.append(name)
|
||||
public = [x for x in items
|
||||
if x in include_public or not x.startswith('_')]
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,7 +14,7 @@ from docutils.parsers.rst import Directive, directives
|
||||
|
||||
from sphinx.config import string_classes
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.locale import _
|
||||
from sphinx.locale import __
|
||||
from sphinx.domains import Domain
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.nodes import make_refnode, set_source_info
|
||||
@@ -113,7 +113,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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1426,6 +1426,41 @@
|
||||
% figure legend comes after caption and may contain arbitrary body elements
|
||||
\newenvironment{sphinxlegend}{\par\small}{\par}
|
||||
|
||||
% Declare Unicode characters used by linux tree command to pdflatex utf8/utf8x
|
||||
\def\spx@bd#1#2{%
|
||||
\leavevmode
|
||||
\begingroup
|
||||
\ifx\spx@bd@height \@undefined\def\spx@bd@height{\baselineskip}\fi
|
||||
\ifx\spx@bd@width \@undefined\setbox0\hbox{0}\def\spx@bd@width{\wd0 }\fi
|
||||
\ifx\spx@bd@thickness\@undefined\def\spx@bd@thickness{.6\p@}\fi
|
||||
\ifx\spx@bd@lower \@undefined\def\spx@bd@lower{\dp\strutbox}\fi
|
||||
\lower\spx@bd@lower#1{#2}%
|
||||
\endgroup
|
||||
}%
|
||||
\@namedef{sphinx@u2500}% BOX DRAWINGS LIGHT HORIZONTAL
|
||||
{\spx@bd{\vbox to\spx@bd@height}
|
||||
{\vss\hrule\@height\spx@bd@thickness
|
||||
\@width\spx@bd@width\vss}}%
|
||||
\@namedef{sphinx@u2502}% BOX DRAWINGS LIGHT VERTICAL
|
||||
{\spx@bd{\hb@xt@\spx@bd@width}
|
||||
{\hss\vrule\@height\spx@bd@height
|
||||
\@width \spx@bd@thickness\hss}}%
|
||||
\@namedef{sphinx@u2514}% BOX DRAWINGS LIGHT UP AND RIGHT
|
||||
{\spx@bd{\hb@xt@\spx@bd@width}
|
||||
{\hss\raise.5\spx@bd@height
|
||||
\hb@xt@\z@{\hss\vrule\@height.5\spx@bd@height
|
||||
\@width \spx@bd@thickness\hss}%
|
||||
\vbox to\spx@bd@height{\vss\hrule\@height\spx@bd@thickness
|
||||
\@width.5\spx@bd@width\vss}}}%
|
||||
\@namedef{sphinx@u251C}% BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||
{\spx@bd{\hb@xt@\spx@bd@width}
|
||||
{\hss
|
||||
\hb@xt@\z@{\hss\vrule\@height\spx@bd@height
|
||||
\@width \spx@bd@thickness\hss}%
|
||||
\vbox to\spx@bd@height{\vss\hrule\@height\spx@bd@thickness
|
||||
\@width.5\spx@bd@width\vss}}}%
|
||||
\protected\def\sphinxunichar#1{\@nameuse{sphinx@u#1}}%
|
||||
|
||||
% Tell TeX about pathological hyphenation cases:
|
||||
\hyphenation{Base-HTTP-Re-quest-Hand-ler}
|
||||
\endinput
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -235,7 +235,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
|
||||
@@ -262,8 +262,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
|
||||
@@ -278,11 +278,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)
|
||||
|
||||
@@ -19,7 +19,7 @@ from sphinx import addnodes
|
||||
from sphinx.locale import _
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.i18n import format_date
|
||||
from sphinx.util.nodes import apply_source_workaround
|
||||
from sphinx.util.nodes import apply_source_workaround, is_smartquotable
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@@ -346,21 +346,5 @@ class SphinxSmartQuotes(SmartQuotes):
|
||||
texttype = {True: 'literal', # "literal" text is not changed:
|
||||
False: 'plain'}
|
||||
for txtnode in txtnodes:
|
||||
nodetype = texttype[isinstance(txtnode.parent,
|
||||
(nodes.literal,
|
||||
addnodes.literal_emphasis,
|
||||
addnodes.literal_strong,
|
||||
addnodes.desc_addname,
|
||||
addnodes.desc_annotation,
|
||||
addnodes.desc_name,
|
||||
addnodes.desc_optional,
|
||||
addnodes.desc_parameter,
|
||||
addnodes.desc_parameterlist,
|
||||
addnodes.desc_signature_line,
|
||||
addnodes.desc_type,
|
||||
addnodes.production,
|
||||
nodes.math,
|
||||
nodes.image,
|
||||
nodes.raw,
|
||||
nodes.problematic))]
|
||||
yield (nodetype, txtnode.astext())
|
||||
smartquotable = not is_smartquotable(txtnode)
|
||||
yield (texttype[smartquotable], txtnode.astext())
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ from sphinx.transforms import SphinxTransform
|
||||
from sphinx.util import logging, requests
|
||||
from sphinx.util import epoch_to_rfc1123, rfc1123_to_epoch
|
||||
from sphinx.util.images import guess_mimetype, get_image_extension, parse_data_uri
|
||||
from sphinx.util.osutil import ensuredir
|
||||
from sphinx.util.osutil import ensuredir, movefile
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@@ -57,7 +57,9 @@ class ImageDownloader(BaseImageConverter):
|
||||
|
||||
def match(self, node):
|
||||
# type: (nodes.Node) -> bool
|
||||
if self.app.builder.supported_remote_images:
|
||||
if self.app.builder.supported_image_types == []:
|
||||
return False
|
||||
elif self.app.builder.supported_remote_images:
|
||||
return False
|
||||
else:
|
||||
return '://' in node['uri']
|
||||
@@ -67,6 +69,8 @@ class ImageDownloader(BaseImageConverter):
|
||||
basename = os.path.basename(node['uri'])
|
||||
if '?' in basename:
|
||||
basename = basename.split('?')[0]
|
||||
if basename == '':
|
||||
basename = sha1(node['uri']).hexdigest()
|
||||
dirname = node['uri'].replace('://', '/').translate({ord("?"): u"/",
|
||||
ord("&"): u"/"})
|
||||
ensuredir(os.path.join(self.imagedir, dirname))
|
||||
@@ -94,6 +98,14 @@ class ImageDownloader(BaseImageConverter):
|
||||
os.utime(path, (timestamp, timestamp))
|
||||
|
||||
mimetype = guess_mimetype(path, default='*')
|
||||
if mimetype != '*' and os.path.splitext(basename)[1] == '':
|
||||
# append a suffix if URI does not contain suffix
|
||||
ext = get_image_extension(mimetype)
|
||||
newpath = os.path.join(self.imagedir, dirname, basename + ext)
|
||||
movefile(path, newpath)
|
||||
self.app.env.original_image_uri.pop(path)
|
||||
self.app.env.original_image_uri[newpath] = node['uri']
|
||||
path = newpath
|
||||
node['candidates'].pop('?')
|
||||
node['candidates'][mimetype] = path
|
||||
node['uri'] = path
|
||||
@@ -108,7 +120,9 @@ class DataURIExtractor(BaseImageConverter):
|
||||
|
||||
def match(self, node):
|
||||
# type: (nodes.Node) -> bool
|
||||
if self.app.builder.supported_data_uri_images:
|
||||
if self.app.builder.supported_remote_images == []:
|
||||
return False
|
||||
elif self.app.builder.supported_data_uri_images is True:
|
||||
return False
|
||||
else:
|
||||
return 'data:' in node['uri']
|
||||
|
||||
@@ -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))
|
||||
|
||||
48
sphinx/util/compat.py
Normal file
48
sphinx/util/compat.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.util.compat
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Stuff for docutils compatibility.
|
||||
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import sys
|
||||
import warnings
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
from docutils.parsers.rst import Directive # noqa
|
||||
from docutils import __version__ as _du_version
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx17Warning
|
||||
|
||||
docutils_version = tuple(LooseVersion(_du_version).version)[:2]
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict # NOQA
|
||||
|
||||
|
||||
class _DeprecationWrapper(object):
|
||||
def __init__(self, mod, deprecated):
|
||||
# type: (Any, Dict) -> None
|
||||
self._mod = mod
|
||||
self._deprecated = deprecated
|
||||
|
||||
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 docutils' instead." % attr,
|
||||
RemovedInSphinx17Warning)
|
||||
return self._deprecated[attr]
|
||||
return getattr(self._mod, attr)
|
||||
|
||||
|
||||
sys.modules[__name__] = _DeprecationWrapper(sys.modules[__name__], dict( # type: ignore
|
||||
docutils_version = docutils_version,
|
||||
Directive = Directive,
|
||||
))
|
||||
@@ -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
|
||||
|
||||
@@ -120,3 +120,17 @@ def parse_data_uri(uri):
|
||||
|
||||
image_data = base64.b64decode(data)
|
||||
return DataURI(mimetype, charset, image_data)
|
||||
|
||||
|
||||
def test_svg(h, f):
|
||||
"""An additional imghdr library helper; test the header is SVG's or not."""
|
||||
try:
|
||||
if '<svg' in h.decode('utf-8').lower():
|
||||
return 'svg+xml'
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
|
||||
|
||||
# install test_svg() to imghdr
|
||||
# refs: https://docs.python.org/3.6/library/imghdr.html#imghdr.tests
|
||||
imghdr.tests.append(test_svg)
|
||||
|
||||
@@ -338,6 +338,28 @@ def set_role_source_info(inliner, lineno, node):
|
||||
node.source, node.line = inliner.reporter.get_source_and_line(lineno)
|
||||
|
||||
|
||||
NON_SMARTQUOTABLE_PARENT_NODES = (
|
||||
nodes.FixedTextElement,
|
||||
nodes.literal,
|
||||
nodes.math,
|
||||
nodes.image,
|
||||
nodes.raw,
|
||||
nodes.problematic,
|
||||
addnodes.not_smartquotable,
|
||||
)
|
||||
|
||||
|
||||
def is_smartquotable(node):
|
||||
# type: (nodes.Node) -> bool
|
||||
"""Check the node is smart-quotable or not."""
|
||||
if isinstance(node.parent, NON_SMARTQUOTABLE_PARENT_NODES):
|
||||
return False
|
||||
elif getattr(node, 'support_smartquotes', None) is False:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
# monkey-patch Element.copy to copy the rawsource and line
|
||||
|
||||
def _new_copy(self):
|
||||
|
||||
@@ -40,12 +40,9 @@ tex_replacements = [
|
||||
# used to separate -- in options
|
||||
('', r'{}'),
|
||||
# map some special Unicode characters to similar ASCII ones
|
||||
('─', r'-'),
|
||||
('⎽', r'\_'),
|
||||
('╲', r'\textbackslash{}'),
|
||||
('–', r'\textendash{}'),
|
||||
('|', r'\textbar{}'),
|
||||
('│', r'\textbar{}'),
|
||||
('ℯ', r'e'),
|
||||
('ⅈ', r'i'),
|
||||
('⁰', r'\(\sp{\text{0}}\)'),
|
||||
|
||||
@@ -105,9 +105,22 @@ ADDITIONAL_SETTINGS = {
|
||||
'pdflatex': {
|
||||
'inputenc': '\\usepackage[utf8]{inputenc}',
|
||||
'utf8extra': ('\\ifdefined\\DeclareUnicodeCharacter\n'
|
||||
' \\ifdefined\\DeclareUnicodeCharacterAsOptional\\else\n'
|
||||
' \\ifdefined\\DeclareUnicodeCharacterAsOptional\n'
|
||||
' \\DeclareUnicodeCharacter{"00A0}{\\nobreakspace}\n'
|
||||
' \\DeclareUnicodeCharacter{"2500}{\\sphinxunichar{2500}}\n'
|
||||
' \\DeclareUnicodeCharacter{"2502}{\\sphinxunichar{2502}}\n'
|
||||
' \\DeclareUnicodeCharacter{"2514}{\\sphinxunichar{2514}}\n'
|
||||
' \\DeclareUnicodeCharacter{"251C}{\\sphinxunichar{251C}}\n'
|
||||
' \\DeclareUnicodeCharacter{"2572}{\\textbackslash}\n'
|
||||
' \\else\n'
|
||||
' \\DeclareUnicodeCharacter{00A0}{\\nobreakspace}\n'
|
||||
'\\fi\\fi'),
|
||||
' \\DeclareUnicodeCharacter{2500}{\\sphinxunichar{2500}}\n'
|
||||
' \\DeclareUnicodeCharacter{2502}{\\sphinxunichar{2502}}\n'
|
||||
' \\DeclareUnicodeCharacter{2514}{\\sphinxunichar{2514}}\n'
|
||||
' \\DeclareUnicodeCharacter{251C}{\\sphinxunichar{251C}}\n'
|
||||
' \\DeclareUnicodeCharacter{2572}{\\textbackslash}\n'
|
||||
' \\fi\n'
|
||||
'\\fi'),
|
||||
},
|
||||
'xelatex': {
|
||||
'latex_engine': 'xelatex',
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from os import *
|
||||
|
||||
|
||||
class Foo:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def bar(self):
|
||||
pass
|
||||
9
tests/roots/test-ext-autosummary/conf.py
Normal file
9
tests/roots/test-ext-autosummary/conf.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import sys, os
|
||||
|
||||
sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
extensions = ['sphinx.ext.autosummary']
|
||||
autosummary_generate = True
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
6
tests/roots/test-ext-autosummary/contents.rst
Normal file
6
tests/roots/test-ext-autosummary/contents.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
|
||||
autosummary_dummy_module
|
||||
autosummary_dummy_module.Foo
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -126,3 +126,22 @@ def test_escaping(app, status, warning):
|
||||
title = etree_parse(docpage).find('section/title')
|
||||
|
||||
assert str_content(title) == 'underscore_module_'
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary')
|
||||
def test_autosummary_generate(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').text()
|
||||
assert (' .. autosummary::\n'
|
||||
' \n'
|
||||
' Foo\n'
|
||||
' \n' in module)
|
||||
|
||||
Foo = (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.rst').text()
|
||||
assert '.. automethod:: __init__' in Foo
|
||||
assert (' .. autosummary::\n'
|
||||
' \n'
|
||||
' ~Foo.__init__\n'
|
||||
' ~Foo.bar\n'
|
||||
' \n' in Foo)
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user