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:
commit
f46c91b652
4
CHANGES
4
CHANGES
@ -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
|
||||
--------
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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[:]:
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user