mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '3.x'
This commit is contained in:
commit
75203967d8
@ -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
|
||||
|
7
CHANGES
7
CHANGES
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
69
sphinx/builders/html/transforms.py
Normal file
69
sphinx/builders/html/transforms.py
Normal 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,
|
||||
}
|
@ -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('@', '@'))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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__
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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('')
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user