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
aa773cbc88
24
CHANGES
24
CHANGES
@ -70,11 +70,15 @@ Features added
|
||||
* #2044: autodoc: Suppress default value for instance attributes
|
||||
* #7473: autodoc: consider a member public if docstring contains
|
||||
``:meta public:`` in info-field-list
|
||||
* #7487: autodoc: Allow to generate docs for singledispatch functions by
|
||||
py:autofunction
|
||||
* #7466: autosummary: headings in generated documents are not translated
|
||||
* #7490: autosummary: Add ``:caption:`` option to autosummary directive to set a
|
||||
caption to the toctree
|
||||
* #248, #6040: autosummary: Add ``:recursive:`` option to autosummary directive
|
||||
to generate stub files recursively
|
||||
* #4030: autosummary: Add :confval:`autosummary_context` to add template
|
||||
variables for custom templates
|
||||
* #7535: sphinx-autogen: crashes when custom template uses inheritance
|
||||
* #7536: sphinx-autogen: crashes when template uses i18n feature
|
||||
* #7481: html theme: Add right margin to footnote/citation labels
|
||||
@ -88,6 +92,7 @@ Features added
|
||||
* #7533: html theme: Avoid whitespace at the beginning of genindex.html
|
||||
* #7541: html theme: Add a "clearer" at the end of the "body"
|
||||
* #7542: html theme: Make admonition/topic/sidebar scrollable
|
||||
* #7543: html theme: Add top and bottom margins to tables
|
||||
* C and C++: allow semicolon in the end of declarations.
|
||||
* C++, parse parameterized noexcept specifiers.
|
||||
|
||||
@ -95,11 +100,12 @@ Bugs fixed
|
||||
----------
|
||||
|
||||
* #6703: autodoc: incremental build does not work for imported objects
|
||||
* #7564: autodoc: annotations not to be shown for descriptors
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 3.0.3 (in development)
|
||||
Release 3.0.4 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
@ -117,9 +123,25 @@ Features added
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #7567: autodoc: parametrized types are shown twice for generic types
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 3.0.3 (released Apr 26, 2020)
|
||||
=====================================
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* C, parse array declarators with static, qualifiers, and VLA specification.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #7516: autodoc: crashes if target object raises an error on accessing
|
||||
its attributes
|
||||
|
||||
Release 3.0.2 (released Apr 19, 2020)
|
||||
=====================================
|
||||
|
||||
|
@ -151,6 +151,13 @@ Generating stub pages automatically
|
||||
If you do not want to create stub pages with :program:`sphinx-autogen`, you can
|
||||
also use these config values:
|
||||
|
||||
.. confval:: autosummary_context
|
||||
|
||||
A dictionary of values to pass into the template engine's context for
|
||||
autosummary stubs files.
|
||||
|
||||
.. versionadded:: 3.1
|
||||
|
||||
.. confval:: autosummary_generate
|
||||
|
||||
Boolean indicating whether to scan all found documents for autosummary
|
||||
|
@ -792,20 +792,60 @@ class ASTDeclSpecs(ASTBase):
|
||||
################################################################################
|
||||
|
||||
class ASTArray(ASTBase):
|
||||
def __init__(self, size: ASTExpression):
|
||||
def __init__(self, static: bool, const: bool, volatile: bool, restrict: bool,
|
||||
vla: bool, size: ASTExpression):
|
||||
self.static = static
|
||||
self.const = const
|
||||
self.volatile = volatile
|
||||
self.restrict = restrict
|
||||
self.vla = vla
|
||||
self.size = size
|
||||
if vla:
|
||||
assert size is None
|
||||
if size is not None:
|
||||
assert not vla
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
if self.size:
|
||||
return '[' + transform(self.size) + ']'
|
||||
else:
|
||||
return '[]'
|
||||
el = []
|
||||
if self.static:
|
||||
el.append('static')
|
||||
if self.restrict:
|
||||
el.append('restrict')
|
||||
if self.volatile:
|
||||
el.append('volatile')
|
||||
if self.const:
|
||||
el.append('const')
|
||||
if self.vla:
|
||||
return '[' + ' '.join(el) + '*]'
|
||||
elif self.size:
|
||||
el.append(transform(self.size))
|
||||
return '[' + ' '.join(el) + ']'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
verify_description_mode(mode)
|
||||
signode.append(nodes.Text("["))
|
||||
if self.size:
|
||||
addSpace = False
|
||||
|
||||
def _add(signode: TextElement, text: str) -> bool:
|
||||
if addSpace:
|
||||
signode += nodes.Text(' ')
|
||||
signode += addnodes.desc_annotation(text, text)
|
||||
return True
|
||||
|
||||
if self.static:
|
||||
addSpace = _add(signode, 'static')
|
||||
if self.restrict:
|
||||
addSpace = _add(signode, 'restrict')
|
||||
if self.volatile:
|
||||
addSpace = _add(signode, 'volatile')
|
||||
if self.const:
|
||||
addSpace = _add(signode, 'const')
|
||||
if self.vla:
|
||||
signode.append(nodes.Text('*'))
|
||||
elif self.size:
|
||||
if addSpace:
|
||||
signode += nodes.Text(' ')
|
||||
self.size.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text("]"))
|
||||
|
||||
@ -2595,18 +2635,45 @@ class DefinitionParser(BaseParser):
|
||||
self.skip_ws()
|
||||
if typed and self.skip_string('['):
|
||||
self.skip_ws()
|
||||
if self.skip_string(']'):
|
||||
arrayOps.append(ASTArray(None))
|
||||
continue
|
||||
static = False
|
||||
const = False
|
||||
volatile = False
|
||||
restrict = False
|
||||
while True:
|
||||
if not static:
|
||||
if self.skip_word_and_ws('static'):
|
||||
static = True
|
||||
continue
|
||||
if not const:
|
||||
if self.skip_word_and_ws('const'):
|
||||
const = True
|
||||
continue
|
||||
if not volatile:
|
||||
if self.skip_word_and_ws('volatile'):
|
||||
volatile = True
|
||||
continue
|
||||
if not restrict:
|
||||
if self.skip_word_and_ws('restrict'):
|
||||
restrict = True
|
||||
continue
|
||||
break
|
||||
vla = False if static else self.skip_string_and_ws('*')
|
||||
if vla:
|
||||
if not self.skip_string(']'):
|
||||
self.fail("Expected ']' in end of array operator.")
|
||||
size = None
|
||||
else:
|
||||
if self.skip_string(']'):
|
||||
size = None
|
||||
else:
|
||||
|
||||
def parser() -> ASTExpression:
|
||||
return self._parse_expression()
|
||||
|
||||
value = self._parse_expression_fallback([']'], parser)
|
||||
if not self.skip_string(']'):
|
||||
self.fail("Expected ']' in end of array operator.")
|
||||
arrayOps.append(ASTArray(value))
|
||||
continue
|
||||
def parser():
|
||||
return self._parse_expression()
|
||||
size = self._parse_expression_fallback([']'], parser)
|
||||
self.skip_ws()
|
||||
if not self.skip_string(']'):
|
||||
self.fail("Expected ']' in end of array operator.")
|
||||
arrayOps.append(ASTArray(static, const, volatile, restrict, vla, size))
|
||||
else:
|
||||
break
|
||||
param = self._parse_parameters(paramMode)
|
||||
|
@ -581,9 +581,9 @@ class Documenter:
|
||||
isprivate = membername.startswith('_')
|
||||
|
||||
keep = False
|
||||
if getattr(member, '__sphinx_mock__', False):
|
||||
if safe_getattr(member, '__sphinx_mock__', False):
|
||||
# mocked module or object
|
||||
keep = False
|
||||
pass
|
||||
elif want_all and membername.startswith('__') and \
|
||||
membername.endswith('__') and len(membername) > 4:
|
||||
# special __methods__
|
||||
@ -1077,30 +1077,15 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
sourcename = self.get_sourcename()
|
||||
super().add_directive_header(sig)
|
||||
if inspect.is_singledispatch_function(self.object):
|
||||
self.add_singledispatch_directive_header(sig)
|
||||
else:
|
||||
super().add_directive_header(sig)
|
||||
|
||||
if inspect.iscoroutinefunction(self.object):
|
||||
self.add_line(' :async:', sourcename)
|
||||
|
||||
|
||||
class SingledispatchFunctionDocumenter(FunctionDocumenter):
|
||||
"""
|
||||
Specialized Documenter subclass for singledispatch'ed functions.
|
||||
"""
|
||||
objtype = 'singledispatch_function'
|
||||
directivetype = 'function'
|
||||
member_order = 30
|
||||
|
||||
# before FunctionDocumenter
|
||||
priority = FunctionDocumenter.priority + 1
|
||||
|
||||
@classmethod
|
||||
def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
|
||||
) -> bool:
|
||||
return (super().can_document_member(member, membername, isattr, parent) and
|
||||
inspect.is_singledispatch_function(member))
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
def add_singledispatch_directive_header(self, sig: str) -> None:
|
||||
sourcename = self.get_sourcename()
|
||||
|
||||
# intercept generated directive headers
|
||||
@ -1140,6 +1125,14 @@ class SingledispatchFunctionDocumenter(FunctionDocumenter):
|
||||
func.__signature__ = sig.replace(parameters=params) # type: ignore
|
||||
|
||||
|
||||
class SingledispatchFunctionDocumenter(FunctionDocumenter):
|
||||
"""
|
||||
Used to be a specialized Documenter subclass for singledispatch'ed functions.
|
||||
|
||||
Retained for backwards compatibility, now does the same as the FunctionDocumenter
|
||||
"""
|
||||
|
||||
|
||||
class DecoratorDocumenter(FunctionDocumenter):
|
||||
"""
|
||||
Specialized Documenter subclass for decorator functions.
|
||||
@ -1474,7 +1467,11 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
||||
return args
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
super().add_directive_header(sig)
|
||||
meth = self.parent.__dict__.get(self.objpath[-1])
|
||||
if inspect.is_singledispatch_method(meth):
|
||||
self.add_singledispatch_directive_header(sig)
|
||||
else:
|
||||
super().add_directive_header(sig)
|
||||
|
||||
sourcename = self.get_sourcename()
|
||||
obj = self.parent.__dict__.get(self.object_name, self.object)
|
||||
@ -1490,28 +1487,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
||||
def document_members(self, all_members: bool = False) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class SingledispatchMethodDocumenter(MethodDocumenter):
|
||||
"""
|
||||
Specialized Documenter subclass for singledispatch'ed methods.
|
||||
"""
|
||||
objtype = 'singledispatch_method'
|
||||
directivetype = 'method'
|
||||
member_order = 50
|
||||
|
||||
# before MethodDocumenter
|
||||
priority = MethodDocumenter.priority + 1
|
||||
|
||||
@classmethod
|
||||
def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
|
||||
) -> bool:
|
||||
if super().can_document_member(member, membername, isattr, parent) and parent.object:
|
||||
meth = parent.object.__dict__.get(membername)
|
||||
return inspect.is_singledispatch_method(meth)
|
||||
else:
|
||||
return False
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
def add_singledispatch_directive_header(self, sig: str) -> None:
|
||||
sourcename = self.get_sourcename()
|
||||
|
||||
# intercept generated directive headers
|
||||
@ -1552,6 +1528,14 @@ class SingledispatchMethodDocumenter(MethodDocumenter):
|
||||
func.__signature__ = sig.replace(parameters=params) # type: ignore
|
||||
|
||||
|
||||
class SingledispatchMethodDocumenter(MethodDocumenter):
|
||||
"""
|
||||
Used to be a specialized Documenter subclass for singledispatch'ed methods.
|
||||
|
||||
Retained for backwards compatibility, now does the same as the MethodDocumenter
|
||||
"""
|
||||
|
||||
|
||||
class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore
|
||||
"""
|
||||
Specialized Documenter subclass for attributes.
|
||||
@ -1603,18 +1587,19 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
|
||||
super().add_directive_header(sig)
|
||||
sourcename = self.get_sourcename()
|
||||
if not self.options.annotation:
|
||||
if not self._datadescriptor:
|
||||
# obtain annotation for this attribute
|
||||
annotations = getattr(self.parent, '__annotations__', {})
|
||||
if annotations and self.objpath[-1] in annotations:
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]))
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
else:
|
||||
key = ('.'.join(self.objpath[:-1]), self.objpath[-1])
|
||||
if self.analyzer and key in self.analyzer.annotations:
|
||||
self.add_line(' :type: ' + self.analyzer.annotations[key],
|
||||
sourcename)
|
||||
# obtain type annotation for this attribute
|
||||
annotations = getattr(self.parent, '__annotations__', {})
|
||||
if annotations and self.objpath[-1] in annotations:
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]))
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
else:
|
||||
key = ('.'.join(self.objpath[:-1]), self.objpath[-1])
|
||||
if self.analyzer and key in self.analyzer.annotations:
|
||||
self.add_line(' :type: ' + self.analyzer.annotations[key],
|
||||
sourcename)
|
||||
|
||||
# data descriptors do not have useful values
|
||||
if not self._datadescriptor:
|
||||
try:
|
||||
if self.object is INSTANCEATTR:
|
||||
pass
|
||||
@ -1769,10 +1754,8 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_autodocumenter(DataDocumenter)
|
||||
app.add_autodocumenter(DataDeclarationDocumenter)
|
||||
app.add_autodocumenter(FunctionDocumenter)
|
||||
app.add_autodocumenter(SingledispatchFunctionDocumenter)
|
||||
app.add_autodocumenter(DecoratorDocumenter)
|
||||
app.add_autodocumenter(MethodDocumenter)
|
||||
app.add_autodocumenter(SingledispatchMethodDocumenter)
|
||||
app.add_autodocumenter(AttributeDocumenter)
|
||||
app.add_autodocumenter(PropertyDocumenter)
|
||||
app.add_autodocumenter(InstanceAttributeDocumenter)
|
||||
|
@ -771,6 +771,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_directive('autosummary', Autosummary)
|
||||
app.add_role('autolink', AutoLink())
|
||||
app.connect('builder-inited', process_generate_options)
|
||||
app.add_config_value('autosummary_context', {}, True)
|
||||
app.add_config_value('autosummary_generate', [], True, [bool])
|
||||
app.add_config_value('autosummary_generate_overwrite', True, False)
|
||||
app.add_config_value('autosummary_mock_imports',
|
||||
|
@ -66,6 +66,7 @@ class DummyApplication:
|
||||
self._warncount = 0
|
||||
self.warningiserror = False
|
||||
|
||||
self.config.add('autosummary_context', {}, True, None)
|
||||
self.config.init_values()
|
||||
|
||||
def emit_firstresult(self, *args: Any) -> None:
|
||||
@ -175,7 +176,7 @@ class AutosummaryRenderer:
|
||||
def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||
template: AutosummaryRenderer, template_name: str,
|
||||
imported_members: bool, app: Any,
|
||||
recursive: bool) -> str:
|
||||
recursive: bool, context: Dict) -> str:
|
||||
doc = get_documenter(app, obj, parent)
|
||||
|
||||
def skip_member(obj: Any, name: str, objtype: str) -> bool:
|
||||
@ -224,6 +225,7 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||
return public, items
|
||||
|
||||
ns = {} # type: Dict[str, Any]
|
||||
ns.update(context)
|
||||
|
||||
if doc.objtype == 'module':
|
||||
ns['members'] = dir(obj)
|
||||
@ -329,8 +331,12 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
||||
_warn(__('[autosummary] failed to import %r: %s') % (entry.name, e))
|
||||
continue
|
||||
|
||||
context = {}
|
||||
if app:
|
||||
context.update(app.config.autosummary_context)
|
||||
|
||||
content = generate_autosummary_content(name, obj, parent, template, entry.template,
|
||||
imported_members, app, entry.recursive)
|
||||
imported_members, app, entry.recursive, context)
|
||||
|
||||
filename = os.path.join(path, name + suffix)
|
||||
if os.path.isfile(filename):
|
||||
|
@ -14,7 +14,7 @@ import sys
|
||||
import tokenize
|
||||
from token import NAME, NEWLINE, INDENT, DEDENT, NUMBER, OP, STRING
|
||||
from tokenize import COMMENT, NL
|
||||
from typing import Any, Dict, List, Tuple
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from sphinx.pycode.ast import ast # for py37 or older
|
||||
from sphinx.pycode.ast import parse, unparse
|
||||
@ -233,41 +233,33 @@ class VariableCommentPicker(ast.NodeVisitor):
|
||||
self.deforders = {} # type: Dict[str, int]
|
||||
super().__init__()
|
||||
|
||||
def add_entry(self, name: str) -> None:
|
||||
def get_qualname_for(self, name: str) -> Optional[List[str]]:
|
||||
"""Get qualified name for given object as a list of string."""
|
||||
if self.current_function:
|
||||
if self.current_classes and self.context[-1] == "__init__":
|
||||
# store variable comments inside __init__ method of classes
|
||||
definition = self.context[:-1] + [name]
|
||||
return self.context[:-1] + [name]
|
||||
else:
|
||||
return
|
||||
return None
|
||||
else:
|
||||
definition = self.context + [name]
|
||||
return self.context + [name]
|
||||
|
||||
self.deforders[".".join(definition)] = next(self.counter)
|
||||
def add_entry(self, name: str) -> None:
|
||||
qualname = self.get_qualname_for(name)
|
||||
if qualname:
|
||||
self.deforders[".".join(qualname)] = next(self.counter)
|
||||
|
||||
def add_variable_comment(self, name: str, comment: str) -> None:
|
||||
if self.current_function:
|
||||
if self.current_classes and self.context[-1] == "__init__":
|
||||
# store variable comments inside __init__ method of classes
|
||||
context = ".".join(self.context[:-1])
|
||||
else:
|
||||
return
|
||||
else:
|
||||
context = ".".join(self.context)
|
||||
|
||||
self.comments[(context, name)] = comment
|
||||
qualname = self.get_qualname_for(name)
|
||||
if qualname:
|
||||
basename = ".".join(qualname[:-1])
|
||||
self.comments[(basename, name)] = comment
|
||||
|
||||
def add_variable_annotation(self, name: str, annotation: ast.AST) -> None:
|
||||
if self.current_function:
|
||||
if self.current_classes and self.context[-1] == "__init__":
|
||||
# store variable comments inside __init__ method of classes
|
||||
context = ".".join(self.context[:-1])
|
||||
else:
|
||||
return
|
||||
else:
|
||||
context = ".".join(self.context)
|
||||
|
||||
self.annotations[(context, name)] = unparse(annotation)
|
||||
qualname = self.get_qualname_for(name)
|
||||
if qualname:
|
||||
basename = ".".join(qualname[:-1])
|
||||
self.annotations[(basename, name)] = unparse(annotation)
|
||||
|
||||
def get_self(self) -> ast.arg:
|
||||
"""Returns the name of first argument if in function."""
|
||||
@ -288,18 +280,12 @@ class VariableCommentPicker(ast.NodeVisitor):
|
||||
def visit_Import(self, node: ast.Import) -> None:
|
||||
"""Handles Import node and record it to definition orders."""
|
||||
for name in node.names:
|
||||
if name.asname:
|
||||
self.add_entry(name.asname)
|
||||
else:
|
||||
self.add_entry(name.name)
|
||||
self.add_entry(name.asname or name.name)
|
||||
|
||||
def visit_ImportFrom(self, node: ast.Import) -> None:
|
||||
def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
|
||||
"""Handles Import node and record it to definition orders."""
|
||||
for name in node.names:
|
||||
if name.asname:
|
||||
self.add_entry(name.asname)
|
||||
else:
|
||||
self.add_entry(name.name)
|
||||
self.add_entry(name.asname or name.name)
|
||||
|
||||
def visit_Assign(self, node: ast.Assign) -> None:
|
||||
"""Handles Assign node and pick up a variable comment."""
|
||||
|
@ -377,6 +377,8 @@ div.body p.centered {
|
||||
/* -- tables ---------------------------------------------------------------- */
|
||||
|
||||
table.docutils {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
@ -75,8 +75,13 @@ def _stringify_py37(annotation: Any) -> str:
|
||||
qualname = stringify(annotation.__origin__) # ex. Union
|
||||
elif hasattr(annotation, '__qualname__'):
|
||||
qualname = '%s.%s' % (module, annotation.__qualname__)
|
||||
elif hasattr(annotation, '__origin__'):
|
||||
# instantiated generic provided by a user
|
||||
qualname = stringify(annotation.__origin__)
|
||||
else:
|
||||
qualname = repr(annotation)
|
||||
# we weren't able to extract the base type, appending arguments would
|
||||
# only make them appear twice
|
||||
return repr(annotation)
|
||||
|
||||
if getattr(annotation, '__args__', None):
|
||||
if qualname == 'Union':
|
||||
@ -91,7 +96,7 @@ def _stringify_py37(annotation: Any) -> str:
|
||||
return '%s[[%s], %s]' % (qualname, args, returns)
|
||||
elif str(annotation).startswith('typing.Annotated'): # for py39+
|
||||
return stringify(annotation.__args__[0])
|
||||
elif annotation._special:
|
||||
elif getattr(annotation, '_special', False):
|
||||
return qualname
|
||||
else:
|
||||
args = ', '.join(stringify(a) for a in annotation.__args__)
|
||||
|
@ -6,11 +6,20 @@ attr2: str
|
||||
attr3 = '' # type: str
|
||||
|
||||
|
||||
class _Descriptor:
|
||||
def __init__(self, name):
|
||||
self.__doc__ = "This is {}".format(name)
|
||||
def __get__(self):
|
||||
pass
|
||||
|
||||
|
||||
class Class:
|
||||
attr1: int = 0
|
||||
attr2: int
|
||||
attr3 = 0 # type: int
|
||||
|
||||
descr4: int = _Descriptor("descr4")
|
||||
|
||||
def __init__(self):
|
||||
self.attr4: int = 0 #: attr4
|
||||
self.attr5: int #: attr5
|
||||
|
@ -3,6 +3,7 @@
|
||||
{% block methods %}
|
||||
|
||||
.. note:: autosummary/class.rst method block overloading
|
||||
{{ sentence }}
|
||||
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
|
@ -1511,6 +1511,13 @@ def test_autodoc_typed_instance_variables(app):
|
||||
' attr6',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Class.descr4',
|
||||
' :module: target.typed_vars',
|
||||
' :type: int',
|
||||
'',
|
||||
' This is descr4',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: attr1',
|
||||
' :module: target.typed_vars',
|
||||
' :type: str',
|
||||
@ -1596,6 +1603,21 @@ def test_singledispatch():
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('setup_test')
|
||||
def test_singledispatch_autofunction():
|
||||
options = {}
|
||||
actual = do_autodoc(app, 'function', 'target.singledispatch.func', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:function:: func(arg, kwarg=None)',
|
||||
' func(arg: int, kwarg=None)',
|
||||
' func(arg: str, kwarg=None)',
|
||||
' :module: target.singledispatch',
|
||||
'',
|
||||
' A function for general use.',
|
||||
'',
|
||||
]
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8),
|
||||
reason='singledispatchmethod is available since python3.8')
|
||||
@pytest.mark.usefixtures('setup_test')
|
||||
@ -1623,6 +1645,23 @@ def test_singledispatchmethod():
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8),
|
||||
reason='singledispatchmethod is available since python3.8')
|
||||
@pytest.mark.usefixtures('setup_test')
|
||||
def test_singledispatchmethod_automethod():
|
||||
options = {}
|
||||
actual = do_autodoc(app, 'method', 'target.singledispatchmethod.Foo.meth', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:method:: Foo.meth(arg, kwarg=None)',
|
||||
' Foo.meth(arg: int, kwarg=None)',
|
||||
' Foo.meth(arg: str, kwarg=None)',
|
||||
' :module: target.singledispatchmethod',
|
||||
'',
|
||||
' A method for general use.',
|
||||
'',
|
||||
]
|
||||
|
||||
@pytest.mark.usefixtures('setup_test')
|
||||
@pytest.mark.skipif(pyximport is None, reason='cython is not installed')
|
||||
def test_cython():
|
||||
|
@ -362,6 +362,21 @@ def test_function_definitions():
|
||||
check('function', 'void f(enum E e)', {1: 'f'})
|
||||
check('function', 'void f(union E e)', {1: 'f'})
|
||||
|
||||
# array declarators
|
||||
check('function', 'void f(int arr[])', {1: 'f'})
|
||||
check('function', 'void f(int arr[*])', {1: 'f'})
|
||||
cvrs = ['', 'const', 'volatile', 'restrict', 'restrict volatile const']
|
||||
for cvr in cvrs:
|
||||
space = ' ' if len(cvr) != 0 else ''
|
||||
check('function', 'void f(int arr[{}*])'.format(cvr), {1: 'f'})
|
||||
check('function', 'void f(int arr[{}])'.format(cvr), {1: 'f'})
|
||||
check('function', 'void f(int arr[{}{}42])'.format(cvr, space), {1: 'f'})
|
||||
check('function', 'void f(int arr[static{}{} 42])'.format(space, cvr), {1: 'f'})
|
||||
check('function', 'void f(int arr[{}{}static 42])'.format(cvr, space), {1: 'f'},
|
||||
output='void f(int arr[static{}{} 42])'.format(space, cvr))
|
||||
check('function', 'void f(int arr[const static volatile 42])', {1: 'f'},
|
||||
output='void f(int arr[static volatile const 42])')
|
||||
|
||||
|
||||
def test_union_definitions():
|
||||
check('struct', 'A', {1: 'A'})
|
||||
|
@ -353,7 +353,8 @@ def test_autosummary_imported_members(app, status, warning):
|
||||
sys.modules.pop('autosummary_dummy_package', None)
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='ext-autodoc')
|
||||
@pytest.mark.sphinx(testroot='ext-autodoc',
|
||||
confoverrides={'extensions': ['sphinx.ext.autosummary']})
|
||||
def test_generate_autosummary_docs_property(app):
|
||||
with patch('sphinx.ext.autosummary.generate.find_autosummary_in_files') as mock:
|
||||
mock.return_value = [AutosummaryEntry('target.methods.Base.prop', 'prop', None, False)]
|
||||
|
@ -33,3 +33,17 @@ def test_autosummary_class_template_overloading(make_app, app_params):
|
||||
|
||||
result = (app.outdir / 'generated' / 'sphinx.application.TemplateBridge.html').read_text()
|
||||
assert 'autosummary/class.rst method block overloading' in result
|
||||
assert 'foobar' not in result
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='templating',
|
||||
confoverrides={'autosummary_context': {'sentence': 'foobar'}})
|
||||
def test_autosummary_context(make_app, app_params):
|
||||
args, kwargs = app_params
|
||||
app = make_app(*args, **kwargs)
|
||||
setup_documenters(app)
|
||||
app.builder.build_update()
|
||||
|
||||
result = (app.outdir / 'generated' / 'sphinx.application.TemplateBridge.html').read_text()
|
||||
assert 'autosummary/class.rst method block overloading' in result
|
||||
assert 'foobar' in result
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
import sys
|
||||
from numbers import Integral
|
||||
from typing import Any, Dict, List, TypeVar, Union, Callable, Tuple, Optional
|
||||
from typing import Any, Dict, List, TypeVar, Union, Callable, Tuple, Optional, Generic
|
||||
|
||||
import pytest
|
||||
|
||||
@ -24,6 +24,11 @@ class MyClass1:
|
||||
class MyClass2(MyClass1):
|
||||
__qualname__ = '<MyClass2>'
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
class MyList(List[T]):
|
||||
pass
|
||||
|
||||
|
||||
def test_stringify():
|
||||
assert stringify(int) == "int"
|
||||
@ -42,6 +47,7 @@ def test_stringify_type_hints_containers():
|
||||
assert stringify(Tuple[str, str, str]) == "Tuple[str, str, str]"
|
||||
assert stringify(Tuple[str, ...]) == "Tuple[str, ...]"
|
||||
assert stringify(List[Dict[str, Tuple]]) == "List[Dict[str, Tuple]]"
|
||||
assert stringify(MyList[Tuple[int, int]]) == "test_util_typing.MyList[Tuple[int, int]]"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 9), reason='python 3.9+ is required.')
|
||||
|
Loading…
Reference in New Issue
Block a user