Merge branch 'stable'

This commit is contained in:
Takeshi KOMIYA 2017-11-02 00:49:10 +09:00
commit f46c91b652
10 changed files with 67 additions and 17 deletions

View File

@ -100,9 +100,13 @@ Deprecated
Features added
--------------
* #4181: autodoc: Sort dictionary keys when possible
Bugs fixed
----------
* #4206: latex: reST label between paragraphs loses paragraph break
Testing
--------

View File

@ -15,15 +15,12 @@ and output behavior.
An optional file `docutils.conf`_ can be added to the configuration
directory to adjust `Docutils`_ configuration if not otherwise overriden or
set by Sphinx; this applies in particular to the `Docutils smart_quotes
setting`_ (Note that Sphinx applies smart quotes transform by default.)
set by Sphinx.
.. _`docutils`: http://docutils.sourceforge.net/
.. _`docutils.conf`: http://docutils.sourceforge.net/docs/user/config.html
.. _`Docutils smart_quotes setting`: http://docutils.sourceforge.net/docs/user/config.html#smart-quotes
The configuration file is executed as Python code at build time (using
:func:`execfile`, and with the current directory set to its containing
directory), and therefore can execute arbitrarily complex code. Sphinx then

View File

@ -682,11 +682,13 @@ class BuildEnvironment(object):
self.settings['language_code'] = language
if 'smart_quotes' not in self.settings:
self.settings['smart_quotes'] = True
for tag in normalize_language_tag(language):
if tag in smartchars.quotes:
break
else:
self.settings['smart_quotes'] = False
# confirm selected language supports smart_quotes or not
for tag in normalize_language_tag(language):
if tag in smartchars.quotes:
break
else:
self.settings['smart_quotes'] = False
docutilsconf = path.join(self.srcdir, 'docutils.conf')
# read docutils.conf from source dir, not from current dir

View File

@ -204,6 +204,14 @@ def safe_getmembers(object, predicate=None, attr_getter=safe_getattr):
def object_description(object):
# type: (Any) -> unicode
"""A repr() implementation that returns text safe to use in reST context."""
if isinstance(object, dict):
try:
sorted_keys = sorted(object)
except TypeError:
pass # Cannot sort dict keys, fall back to generic repr
else:
items = ("%r: %r" % (key, object[key]) for key in sorted_keys)
return "{%s}" % ", ".join(items)
try:
s = repr(object)
except Exception:

View File

@ -29,6 +29,7 @@ if False:
from sphinx.application import Sphinx # NOQA
NAMESPACE = 'sphinx'
VERBOSE = 15
LEVEL_NAMES = defaultdict(lambda: logging.WARNING) # type: Dict[str, int]
@ -59,8 +60,18 @@ COLOR_MAP.update({
def getLogger(name):
# type: (str) -> SphinxLoggerAdapter
"""Get logger wrapped by SphinxLoggerAdapter."""
return SphinxLoggerAdapter(logging.getLogger(name), {})
"""Get logger wrapped by SphinxLoggerAdapter.
Sphinx logger always uses ``sphinx.*`` namesapce to be independent from
settings of root logger. It enables to log stably even if 3rd party
extension or imported application resets logger settings.
"""
# add sphinx prefix to name forcely
logger = logging.getLogger(NAMESPACE + '.' + name)
# Forcely enable logger
logger.disabled = False
# wrap logger by SphinxLoggerAdapter
return SphinxLoggerAdapter(logger, {})
def convert_serializable(records):
@ -203,7 +214,7 @@ class MemoryHandler(logging.handlers.BufferingHandler):
def pending_warnings():
# type: () -> Generator
"""contextmanager to pend logging warnings temporary."""
logger = logging.getLogger()
logger = logging.getLogger(NAMESPACE)
memhandler = MemoryHandler()
memhandler.setLevel(logging.WARNING)
@ -229,7 +240,7 @@ def pending_warnings():
def pending_logging():
# type: () -> Generator
"""contextmanager to pend logging all logs temporary."""
logger = logging.getLogger()
logger = logging.getLogger(NAMESPACE)
memhandler = MemoryHandler()
try:
@ -253,7 +264,7 @@ def pending_logging():
def skip_warningiserror(skip=True):
# type: (bool) -> Generator
"""contextmanager to skip WarningIsErrorFilter for a while."""
logger = logging.getLogger()
logger = logging.getLogger(NAMESPACE)
if skip is False:
yield
@ -469,8 +480,9 @@ class LastMessagesWriter(object):
def setup(app, status, warning):
# type: (Sphinx, IO, IO) -> None
"""Setup root logger for Sphinx"""
logger = logging.getLogger()
logger.setLevel(logging.NOTSET)
logger = logging.getLogger(NAMESPACE)
logger.setLevel(logging.DEBUG)
logger.propagate = False
# clear all handlers
for handler in logger.handlers[:]:

View File

@ -1917,6 +1917,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
# will be generated differently
if id.startswith('index-'):
return
# insert blank line, if the target follows a paragraph node
index = node.parent.index(node)
if index > 0 and isinstance(node.parent[index - 1], nodes.paragraph):
self.body.append('\n')
# do not generate \phantomsection in \section{}
anchor = not self.in_title
self.body.append(self.hypertarget(id, anchor=anchor))

View File

@ -14,7 +14,7 @@ from sphinx.ext.doctest import compare_version
cleanup_called = 0
@pytest.mark.sphinx('doctest', testroot='doctest')
@pytest.mark.sphinx('doctest', testroot='ext-doctest')
def test_build(app, status, warning):
global cleanup_called
cleanup_called = 0

View File

@ -113,6 +113,7 @@ def test_getargspec_bound_methods():
assert expected_bound == inspect.getargspec(wrapped_bound_method)
def test_Signature():
# literals
with pytest.raises(TypeError):
@ -310,3 +311,23 @@ def test_safe_getattr_with___dict___override():
assert exc.args[0] == 'bar'
else:
pytest.fail('AttributeError not raised')
def test_dictionary_sorting():
dictionary = {"c": 3, "a": 1, "d": 2, "b": 4}
description = inspect.object_description(dictionary)
assert description == "{'a': 1, 'b': 4, 'c': 3, 'd': 2}"
def test_dict_customtype():
class CustomType(object):
def __init__(self, value):
self._value = value
def __repr__(self):
return "<CustomType(%r)>" % self._value
dictionary = {CustomType(2): 2, CustomType(1): 1}
description = inspect.object_description(dictionary)
# Type is unsortable, just check that it does not crash
assert "<CustomType(2)>: 2" in description