Merge branch '3.x'

This commit is contained in:
Takeshi KOMIYA 2020-05-04 00:15:20 +09:00
commit 75203967d8
22 changed files with 195 additions and 52 deletions

View File

@ -8,4 +8,7 @@ jobs:
- checkout
- run: /python3.6/bin/pip install -U pip setuptools
- run: /python3.6/bin/pip install -U .[test]
- run: make test PYTHON=/python3.6/bin/python
- run: mkdir -p test-reports/pytest
- run: make test PYTHON=/python3.6/bin/python TEST=--junitxml=test-reports/pytest/results.xml
- store_test_results:
path: test-reports

View File

@ -47,6 +47,7 @@ Deprecated
been changed to Sphinx object
* ``sphinx.ext.autosummary.generate.AutosummaryRenderer`` takes an object type
as an argument
* The ``ignore`` argument of ``sphinx.ext.autodoc.Documenter.get_doc()``
* The ``template_dir`` argument of ``sphinx.ext.autosummary.generate.
AutosummaryRenderer``
* The ``module`` argument of ``sphinx.ext.autosummary.generate.
@ -55,6 +56,7 @@ Deprecated
generate_autosummary_docs()``
* The ``template_dir`` argument of ``sphinx.ext.autosummary.generate.
generate_autosummary_docs()``
* The ``ignore`` argument of ``sphinx.util.docstring.prepare_docstring()``
* ``sphinx.ext.autosummary.generate.AutosummaryRenderer.exists()``
Features added
@ -80,6 +82,7 @@ Features added
to generate stub files recursively
* #4030: autosummary: Add :confval:`autosummary_context` to add template
variables for custom templates
* #7530: html: Support nested <kbd> elements
* #7481: html theme: Add right margin to footnote/citation labels
* #7482: html theme: CSS spacing for code blocks with captions and line numbers
* #7443: html theme: Add new options :confval:`globaltoc_collapse` and
@ -98,6 +101,7 @@ Features added
* C++, parse trailing return types.
* #7143: py domain: Add ``:final:`` option to :rst:dir:`py:class:`,
:rst:dir:`py:exception:` and :rst:dir:`py:method:` directives
* #7582: napoleon: a type for attribute are represented like type annotation
Bugs fixed
----------
@ -108,6 +112,9 @@ Bugs fixed
* #7469: autodoc: The change of autodoc-process-docstring for variables is
cached unexpectedly
* #7559: autodoc: misdetects a sync function is async
* #6857: autodoc: failed to detect a classmethod on Enum class
* #7562: autodoc: a typehint contains spaces is wrongly rendered under
autodoc_typehints='description' mode
* #7535: sphinx-autogen: crashes when custom template uses inheritance
* #7536: sphinx-autogen: crashes when template uses i18n feature
* #2785: html: Bad alignment of equation links

View File

@ -69,6 +69,11 @@ The following is a list of deprecated interfaces.
- 5.0
- N/A
* - The ``ignore`` argument of ``sphinx.ext.autodoc.Documenter.get_doc()``
- 3.1
- 5.0
- N/A
* - The ``template_dir`` argument of
``sphinx.ext.autosummary.generate.AutosummaryRenderer``
- 3.1
@ -98,6 +103,11 @@ The following is a list of deprecated interfaces.
- 5.0
- N/A
* - The ``ignore`` argument of ``sphinx.util.docstring.prepare_docstring()``
- 3.1
- 5.0
- N/A
* - ``desc_signature['first']``
-
- 3.0

View File

@ -1227,6 +1227,9 @@ def setup(app: Sphinx) -> Dict[str, Any]:
# load default math renderer
app.setup_extension('sphinx.ext.mathjax')
# load transforms for HTML builder
app.setup_extension('sphinx.builders.html.transforms')
return {
'version': 'builtin',
'parallel_read_safe': True,

View File

@ -0,0 +1,69 @@
"""
sphinx.builders.html.transforms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Transforms for HTML builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import re
from typing import Any, Dict
from docutils import nodes
from sphinx.application import Sphinx
from sphinx.transforms.post_transforms import SphinxPostTransform
from sphinx.util.nodes import NodeMatcher
class KeyboardTransform(SphinxPostTransform):
"""Transform :kbd: role to more detailed form.
Before::
<literal class="kbd">
Control-x
After::
<literal class="kbd">
<literal class="kbd">
Control
-
<literal class="kbd">
x
"""
default_priority = 400
builders = ('html',)
pattern = re.compile(r'(-|\+|\^|\s+)')
def run(self, **kwargs: Any) -> None:
matcher = NodeMatcher(nodes.literal, classes=["kbd"])
for node in self.document.traverse(matcher): # type: nodes.literal
parts = self.pattern.split(node[-1].astext())
if len(parts) == 1:
continue
node.pop()
while parts:
key = parts.pop(0)
node += nodes.literal('', key, classes=["kbd"])
try:
# key separator (ex. -, +, ^)
sep = parts.pop(0)
node += nodes.Text(sep)
except IndexError:
pass
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_post_transform(KeyboardTransform)
return {
'version': 'builtin',
'parallel_read_safe': True,
'parallel_write_safe': True,
}

View File

@ -775,10 +775,11 @@ class PyDecoratorMixin:
if cls.__name__ != 'DirectiveAdapter':
warnings.warn('PyDecoratorMixin is deprecated. '
'Please check the implementation of %s' % cls,
RemovedInSphinx50Warning)
RemovedInSphinx50Warning, stacklevel=2)
break
else:
warnings.warn('PyDecoratorMixin is deprecated', RemovedInSphinx50Warning)
warnings.warn('PyDecoratorMixin is deprecated',
RemovedInSphinx50Warning, stacklevel=2)
ret = super().handle_signature(sig, signode) # type: ignore
signode.insert(0, addnodes.desc_addname('@', '@'))

View File

@ -645,7 +645,7 @@ class StandardDomain(Domain):
def add_object(self, objtype: str, name: str, docname: str, labelid: str) -> None:
warnings.warn('StandardDomain.add_object() is deprecated.',
RemovedInSphinx50Warning)
RemovedInSphinx50Warning, stacklevel=2)
self.objects[objtype, name] = (docname, labelid)
@property

View File

@ -395,9 +395,9 @@ class Documenter:
except TypeError:
# retry without arguments for old documenters
args = self.format_args()
except Exception as err:
logger.warning(__('error while formatting arguments for %s: %s') %
(self.fullname, err), type='autodoc')
except Exception:
logger.warning(__('error while formatting arguments for %s:') %
self.fullname, type='autodoc', exc_info=True)
args = None
retann = self.retann
@ -428,8 +428,12 @@ class Documenter:
# etc. don't support a prepended module name
self.add_line(' :module: %s' % self.modname, sourcename)
def get_doc(self, ignore: int = 1) -> List[List[str]]:
def get_doc(self, ignore: int = None) -> List[List[str]]:
"""Decode and return lines of the docstring(s) for the object."""
if ignore is not None:
warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated."
% self.__class__.__name__,
RemovedInSphinx50Warning, stacklevel=2)
docstring = getdoc(self.object, self.get_attr,
self.env.config.autodoc_inherit_docstrings,
self.parent, self.object_name)
@ -741,8 +745,8 @@ class Documenter:
# parse right now, to get PycodeErrors on parsing (results will
# be cached anyway)
self.analyzer.find_attr_docs()
except PycodeError as err:
logger.debug('[autodoc] module analyzer failed: %s', err)
except PycodeError:
logger.debug('[autodoc] module analyzer failed:', exc_info=True)
# no source file -- e.g. for builtin and C modules
self.analyzer = None
# at least add the module.__file__ as a dependency
@ -844,7 +848,7 @@ class ModuleDocumenter(Documenter):
if self.options.deprecated:
self.add_line(' :deprecated:', sourcename)
def get_object_members(self, want_all: bool) -> Tuple[bool, List[Tuple[str, object]]]:
def get_object_members(self, want_all: bool) -> Tuple[bool, List[Tuple[str, Any]]]:
if want_all:
if (self.options.ignore_module_all or not
hasattr(self.object, '__all__')):
@ -970,7 +974,7 @@ class DocstringSignatureMixin:
break
return result
def get_doc(self, ignore: int = 1) -> List[List[str]]:
def get_doc(self, ignore: int = None) -> List[List[str]]:
lines = getattr(self, '_new_docstrings', None)
if lines is not None:
return lines
@ -1226,7 +1230,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
self.add_line(' ' + _('Bases: %s') % ', '.join(bases),
sourcename)
def get_doc(self, ignore: int = 1) -> List[List[str]]:
def get_doc(self, ignore: int = None) -> List[List[str]]:
lines = getattr(self, '_new_docstrings', None)
if lines is not None:
return lines
@ -1719,8 +1723,12 @@ class SlotsAttributeDocumenter(AttributeDocumenter):
self.env.note_reread()
return False
def get_doc(self, ignore: int = 1) -> List[List[str]]:
def get_doc(self, ignore: int = None) -> List[List[str]]:
"""Decode and return lines of the docstring(s) for the object."""
if ignore is not None:
warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated."
% self.__class__.__name__,
RemovedInSphinx50Warning, stacklevel=2)
name = self.objpath[-1]
__slots__ = safe_getattr(self.parent, '__slots__', [])
if isinstance(__slots__, dict) and isinstance(__slots__.get(name), str):
@ -1732,7 +1740,7 @@ class SlotsAttributeDocumenter(AttributeDocumenter):
def get_documenters(app: Sphinx) -> Dict[str, Type[Documenter]]:
"""Returns registered Documenter classes"""
warnings.warn("get_documenters() is deprecated.", RemovedInSphinx50Warning)
warnings.warn("get_documenters() is deprecated.", RemovedInSphinx50Warning, stacklevel=2)
return app.registry.documenters

View File

@ -13,6 +13,7 @@ import traceback
import warnings
from typing import Any, Callable, Dict, List, Mapping, NamedTuple, Tuple
from sphinx.pycode import ModuleAnalyzer
from sphinx.util import logging
from sphinx.util.inspect import isclass, isenumclass, safe_getattr
@ -127,7 +128,7 @@ class Attribute(NamedTuple):
def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable,
analyzer: Any = None) -> Dict[str, Attribute]:
analyzer: ModuleAnalyzer = None) -> Dict[str, Attribute]:
"""Get members and attributes of target object."""
from sphinx.ext.autodoc import INSTANCEATTR
@ -143,8 +144,9 @@ def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable,
members[name] = Attribute(name, True, value)
superclass = subject.__mro__[1]
for name, value in obj_dict.items():
for name in obj_dict:
if name not in superclass.__dict__:
value = safe_getattr(subject, name)
members[name] = Attribute(name, True, value)
# members in __slots__

View File

@ -122,7 +122,7 @@ class AutosummaryRenderer:
RemovedInSphinx50Warning, stacklevel=2)
if template_dir:
warnings.warn('template_dir argument for AutosummaryRenderer is deprecated.',
RemovedInSphinx50Warning)
RemovedInSphinx50Warning, stacklevel=2)
system_templates_path = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')]
loader = SphinxTemplateLoader(app.srcdir, app.config.templates_path,
@ -274,11 +274,11 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
overwrite: bool = True) -> None:
if builder:
warnings.warn('builder argument for generate_autosummary_docs() is deprecated.',
RemovedInSphinx50Warning)
RemovedInSphinx50Warning, stacklevel=2)
if template_dir:
warnings.warn('template_dir argument for generate_autosummary_docs() is deprecated.',
RemovedInSphinx50Warning)
RemovedInSphinx50Warning, stacklevel=2)
showed_sources = list(sorted(sources))
if len(showed_sources) > 20:
@ -371,7 +371,7 @@ def find_autosummary_in_docstring(name: str, module: str = None, filename: str =
"""
if module:
warnings.warn('module argument for find_autosummary_in_docstring() is deprecated.',
RemovedInSphinx50Warning)
RemovedInSphinx50Warning, stacklevel=2)
try:
real_name, obj, parent, modname = import_by_name(name)

View File

@ -168,11 +168,10 @@ class Config:
**If False**::
.. attribute:: attr1
:type: int
Description of `attr1`
:type: int
napoleon_use_param : :obj:`bool` (Defaults to True)
True to use a ``:param:`` role for each function parameter. False to
use a single ``:parameters:`` role for all the parameters.

View File

@ -584,13 +584,12 @@ class GoogleDocstring:
lines.append('.. attribute:: ' + _name)
if self._opt and 'noindex' in self._opt:
lines.append(' :noindex:')
if _type:
lines.extend(self._indent([':type: %s' % _type], 3))
lines.append('')
fields = self._format_field('', '', _desc)
lines.extend(self._indent(fields, 3))
if _type:
lines.append('')
lines.extend(self._indent([':type: %s' % _type], 3))
lines.append('')
if self._config.napoleon_use_ivar:
lines.append('')

View File

@ -63,7 +63,7 @@ class Parser(docutils.parsers.Parser):
@property
def app(self) -> "Sphinx":
warnings.warn('parser.app is deprecated.', RemovedInSphinx50Warning)
warnings.warn('parser.app is deprecated.', RemovedInSphinx50Warning, stacklevel=2)
return self._app

View File

@ -10,10 +10,13 @@
import re
import sys
import warnings
from typing import Dict, List
from docutils.parsers.rst.states import Body
from sphinx.deprecation import RemovedInSphinx50Warning
field_list_item_re = re.compile(Body.patterns['field_marker'])
@ -42,7 +45,7 @@ def extract_metadata(s: str) -> Dict[str, str]:
return metadata
def prepare_docstring(s: str, ignore: int = 1, tabsize: int = 8) -> List[str]:
def prepare_docstring(s: str, ignore: int = None, tabsize: int = 8) -> List[str]:
"""Convert a docstring into lines of parseable reST. Remove common leading
indentation, where the indentation of a given number of lines (usually just
one) is ignored.
@ -51,6 +54,12 @@ def prepare_docstring(s: str, ignore: int = 1, tabsize: int = 8) -> List[str]:
ViewList (used as argument of nested_parse().) An empty line is added to
act as a separator between this docstring and following content.
"""
if ignore is None:
ignore = 1
else:
warnings.warn("The 'ignore' argument to parepare_docstring() is deprecated.",
RemovedInSphinx50Warning, stacklevel=2)
lines = s.expandtabs(tabsize).splitlines()
# Find minimum indentation of any non-blank lines after ignored lines.
margin = sys.maxsize

View File

@ -58,7 +58,7 @@ def getargspec(func: Callable) -> Any:
"""Like inspect.getfullargspec but supports bound methods, and wrapped
methods."""
warnings.warn('sphinx.ext.inspect.getargspec() is deprecated',
RemovedInSphinx50Warning)
RemovedInSphinx50Warning, stacklevel=2)
# On 3.5+, signature(int) or similar raises ValueError. On 3.4, it
# succeeds with a bogus signature. We want a TypeError uniformly, to
# match historical behavior.

View File

@ -411,9 +411,13 @@ class WarningIsErrorFilter(logging.Filter):
message = record.msg # use record.msg itself
if location:
raise SphinxWarning(location + ":" + str(message))
exc = SphinxWarning(location + ":" + str(message))
else:
raise SphinxWarning(message)
exc = SphinxWarning(message)
if record.exc_info is not None:
raise exc from record.exc_info[1]
else:
raise exc
else:
return True

View File

@ -58,8 +58,8 @@ class NodeMatcher:
# => [<reference ...>, <reference ...>, ...]
"""
def __init__(self, *classes: "Type[Node]", **attrs: Any) -> None:
self.classes = classes
def __init__(self, *node_classes: "Type[Node]", **attrs: Any) -> None:
self.classes = node_classes
self.attrs = attrs
def match(self, node: Node) -> bool:

View File

@ -93,7 +93,7 @@ class LaTeXWriter(writers.Writer):
visitor = self.builder.create_translator(self.document, self.builder, self.theme)
except TypeError:
warnings.warn('LaTeXTranslator now takes 3rd argument; "theme".',
RemovedInSphinx50Warning)
RemovedInSphinx50Warning, stacklevel=2)
visitor = self.builder.create_translator(self.document, self.builder)
self.document.walkabout(visitor)
@ -289,7 +289,7 @@ class LaTeXTranslator(SphinxTranslator):
if theme is None:
warnings.warn('LaTeXTranslator now takes 3rd argument; "theme".',
RemovedInSphinx50Warning)
RemovedInSphinx50Warning, stacklevel=2)
# flags
self.in_title = 0

View File

@ -16,3 +16,8 @@ class EnumCls(enum.Enum):
def say_hello(self):
"""a method says hello to you."""
pass
@classmethod
def say_goodbye(cls):
"""a classmethod says good-bye to you."""
pass

View File

@ -1112,8 +1112,7 @@ def test_slots(app):
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_enum_class(app):
options = {"members": None,
"undoc-members": True}
options = {"members": None}
actual = do_autodoc(app, 'class', 'target.enum.EnumCls', options)
assert list(actual) == [
'',
@ -1123,6 +1122,13 @@ def test_enum_class(app):
' this is enum class',
'',
'',
' .. py:method:: EnumCls.say_goodbye()',
' :module: target.enum',
' :classmethod:',
'',
' a classmethod says good-bye to you.',
'',
'',
' .. py:method:: EnumCls.say_hello()',
' :module: target.enum',
'',
@ -1149,11 +1155,6 @@ def test_enum_class(app):
'',
' doc for val3',
'',
'',
' .. py:attribute:: EnumCls.val4',
' :module: target.enum',
' :value: 34',
''
]
# checks for an attribute of EnumClass

View File

@ -53,22 +53,19 @@ class NamedtupleSubclassTest(BaseDocstringTest):
Sample namedtuple subclass
.. attribute:: attr1
:type: Arbitrary type
Quick description of attr1
:type: Arbitrary type
.. attribute:: attr2
:type: Another arbitrary type
Quick description of attr2
:type: Another arbitrary type
.. attribute:: attr3
:type: Type
Adds a newline after the type
:type: Type
"""
self.assertEqual(expected, actual)
@ -412,10 +409,9 @@ Attributes:
actual = str(GoogleDocstring(docstring))
expected = """\
.. attribute:: in_attr
:type: :class:`numpy.ndarray`
super-dooper attribute
:type: :class:`numpy.ndarray`
"""
self.assertEqual(expected, actual)
@ -427,10 +423,9 @@ Attributes:
actual = str(GoogleDocstring(docstring))
expected = """\
.. attribute:: in_attr
:type: numpy.ndarray
super-dooper attribute
:type: numpy.ndarray
"""
self.assertEqual(expected, actual)

View File

@ -16,6 +16,7 @@ from docutils.parsers.rst import Parser as RstParser
from docutils.transforms.universal import SmartQuotes
from sphinx import addnodes
from sphinx.builders.html.transforms import KeyboardTransform
from sphinx.builders.latex import LaTeXBuilder
from sphinx.roles import XRefRole
from sphinx.testing.util import Struct, assert_node
@ -94,6 +95,7 @@ class ForgivingLaTeXTranslator(LaTeXTranslator, ForgivingTranslator):
def verify_re_html(app, parse):
def verify(rst, html_expected):
document = parse(rst)
KeyboardTransform(document).apply()
html_translator = ForgivingHTMLTranslator(document, app.builder)
document.walkabout(html_translator)
html_translated = ''.join(html_translator.fragment).strip()
@ -237,6 +239,32 @@ def get_verifier(verify, verify_re):
'<p><kbd class="kbd docutils literal notranslate">space</kbd></p>',
'\\sphinxkeyboard{\\sphinxupquote{space}}',
),
(
# kbd role
'verify',
':kbd:`Control+X`',
('<p><kbd class="kbd docutils literal notranslate">'
'<kbd class="kbd docutils literal notranslate">Control</kbd>'
'+'
'<kbd class="kbd docutils literal notranslate">X</kbd>'
'</kbd></p>'),
'\\sphinxkeyboard{\\sphinxupquote{Control+X}}',
),
(
# kbd role
'verify',
':kbd:`M-x M-s`',
('<p><kbd class="kbd docutils literal notranslate">'
'<kbd class="kbd docutils literal notranslate">M</kbd>'
'-'
'<kbd class="kbd docutils literal notranslate">x</kbd>'
' '
'<kbd class="kbd docutils literal notranslate">M</kbd>'
'-'
'<kbd class="kbd docutils literal notranslate">s</kbd>'
'</kbd></p>'),
'\\sphinxkeyboard{\\sphinxupquote{M\\sphinxhyphen{}x M\\sphinxhyphen{}s}}',
),
(
# non-interpolation of dashes in option role
'verify_re',