mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '2.0'
This commit is contained in:
commit
cad1f86dd8
6
CHANGES
6
CHANGES
@ -61,9 +61,7 @@ Deprecated
|
||||
* ``sphinx.roles.Index``
|
||||
* ``sphinx.util.detect_encoding()``
|
||||
* ``sphinx.util.get_module_source()``
|
||||
* ``sphinx.util.inspect.Signature.format_annotation()``
|
||||
* ``sphinx.util.inspect.Signature.format_annotation_new()``
|
||||
* ``sphinx.util.inspect.Signature.format_annotation_old()``
|
||||
* ``sphinx.util.inspect.Signature``
|
||||
|
||||
Features added
|
||||
--------------
|
||||
@ -75,6 +73,7 @@ Features added
|
||||
* #6966: graphviz: Support ``:class:`` option
|
||||
* #6696: html: ``:scale:`` option of image/figure directive not working for SVG
|
||||
images (imagesize-1.2.0 or above is required)
|
||||
* #6994: imgconverter: Support illustrator file (.ai) to .png conversion
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
@ -84,6 +83,7 @@ Bugs fixed
|
||||
* #6961: latex: warning for babel shown twice
|
||||
* #6559: Wrong node-ids are generated in glossary directive
|
||||
* #6986: apidoc: misdetects module name for .so file inside module
|
||||
* #6999: napoleon: fails to parse tilde in :exc: role
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
@ -86,20 +86,11 @@ The following is a list of deprecated interfaces.
|
||||
- 4.0
|
||||
- N/A
|
||||
|
||||
* - ``sphinx.util.inspect.Signature.format_annotation()``
|
||||
* - ``sphinx.util.inspect.Signature``
|
||||
- 2.4
|
||||
- 4.0
|
||||
- ``sphinx.util.typing.stringify()``
|
||||
|
||||
* - ``sphinx.util.inspect.Signature.format_annotation_new()``
|
||||
- 2.4
|
||||
- 4.0
|
||||
- ``sphinx.util.typing.stringify()``
|
||||
|
||||
* - ``sphinx.util.inspect.Signature.format_annotation_old()``
|
||||
- 2.4
|
||||
- 4.0
|
||||
- ``sphinx.util.typing.stringify()``
|
||||
- ``sphinx.util.inspect.signature`` and
|
||||
``sphinx.util.inspect.stringify_signature()``
|
||||
|
||||
* - ``sphinx.builders.gettext.POHEADER``
|
||||
- 2.3
|
||||
|
@ -189,8 +189,8 @@ Referencing downloadable files
|
||||
|
||||
When you use this role, the referenced file is automatically marked for
|
||||
inclusion in the output when building (obviously, for HTML output only).
|
||||
All downloadable files are put into the ``_downloads`` subdirectory of the
|
||||
output directory; duplicate filenames are handled.
|
||||
All downloadable files are put into a ``_downloads/<unique hash>/``
|
||||
subdirectory of the output directory; duplicate filenames are handled.
|
||||
|
||||
An example::
|
||||
|
||||
|
@ -509,7 +509,7 @@ class Sphinx:
|
||||
self.registry.add_translator(name, translator_class, override=override)
|
||||
|
||||
def add_node(self, node: "Type[Element]", override: bool = False,
|
||||
**kwds: Tuple[Callable, Callable]) -> None:
|
||||
**kwargs: Tuple[Callable, Callable]) -> None:
|
||||
"""Register a Docutils node class.
|
||||
|
||||
This is necessary for Docutils internals. It may also be used in the
|
||||
@ -539,17 +539,17 @@ class Sphinx:
|
||||
.. versionchanged:: 0.5
|
||||
Added the support for keyword arguments giving visit functions.
|
||||
"""
|
||||
logger.debug('[app] adding node: %r', (node, kwds))
|
||||
logger.debug('[app] adding node: %r', (node, kwargs))
|
||||
if not override and docutils.is_node_registered(node):
|
||||
logger.warning(__('node class %r is already registered, '
|
||||
'its visitors will be overridden'),
|
||||
node.__name__, type='app', subtype='add_node')
|
||||
docutils.register_node(node)
|
||||
self.registry.add_translation_handlers(node, **kwds)
|
||||
self.registry.add_translation_handlers(node, **kwargs)
|
||||
|
||||
def add_enumerable_node(self, node: "Type[Element]", figtype: str,
|
||||
title_getter: TitleGetter = None, override: bool = False,
|
||||
**kwds: Tuple[Callable, Callable]) -> None:
|
||||
**kwargs: Tuple[Callable, Callable]) -> None:
|
||||
"""Register a Docutils node class as a numfig target.
|
||||
|
||||
Sphinx numbers the node automatically. And then the users can refer it
|
||||
@ -574,7 +574,7 @@ class Sphinx:
|
||||
.. versionadded:: 1.4
|
||||
"""
|
||||
self.registry.add_enumerable_node(node, figtype, title_getter, override=override)
|
||||
self.add_node(node, override=override, **kwds)
|
||||
self.add_node(node, override=override, **kwargs)
|
||||
|
||||
def add_directive(self, name: str, cls: "Type[Directive]", override: bool = False) -> None:
|
||||
"""Register a Docutils directive.
|
||||
|
@ -198,8 +198,8 @@ if source_date_epoch is not None:
|
||||
|
||||
|
||||
class LocalTimeZone(tzinfo):
|
||||
def __init__(self, *args: Any, **kw: Any) -> None:
|
||||
super().__init__(*args, **kw) # type: ignore
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs) # type: ignore
|
||||
self.tzdelta = tzdelta
|
||||
|
||||
def utcoffset(self, dt: datetime) -> timedelta:
|
||||
|
@ -858,11 +858,11 @@ class StandaloneHTMLBuilder(Builder):
|
||||
indexer_name, indexer_name),
|
||||
RemovedInSphinx40Warning)
|
||||
|
||||
def _get_local_toctree(self, docname: str, collapse: bool = True, **kwds: Any) -> str:
|
||||
if 'includehidden' not in kwds:
|
||||
kwds['includehidden'] = False
|
||||
def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str:
|
||||
if 'includehidden' not in kwargs:
|
||||
kwargs['includehidden'] = False
|
||||
return self.render_partial(TocTree(self.env).get_toctree_for(
|
||||
docname, self, collapse, **kwds))['fragment']
|
||||
docname, self, collapse, **kwargs))['fragment']
|
||||
|
||||
def get_outfilename(self, pagename: str) -> str:
|
||||
return path.join(self.outdir, os_path(pagename) + self.out_suffix)
|
||||
@ -971,7 +971,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
return False
|
||||
ctx['hasdoc'] = hasdoc
|
||||
|
||||
ctx['toctree'] = lambda **kw: self._get_local_toctree(pagename, **kw)
|
||||
ctx['toctree'] = lambda **kwargs: self._get_local_toctree(pagename, **kwargs)
|
||||
self.add_sidebars(pagename, ctx)
|
||||
ctx.update(addctx)
|
||||
|
||||
|
@ -67,10 +67,10 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
if hashindex >= 0:
|
||||
refnode['refuri'] = fname + refuri[hashindex:]
|
||||
|
||||
def _get_local_toctree(self, docname: str, collapse: bool = True, **kwds: Any) -> str:
|
||||
if 'includehidden' not in kwds:
|
||||
kwds['includehidden'] = False
|
||||
toctree = TocTree(self.env).get_toctree_for(docname, self, collapse, **kwds)
|
||||
def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str:
|
||||
if 'includehidden' not in kwargs:
|
||||
kwargs['includehidden'] = False
|
||||
toctree = TocTree(self.env).get_toctree_for(docname, self, collapse, **kwargs)
|
||||
if toctree is not None:
|
||||
self.fix_refuris(toctree)
|
||||
return self.render_partial(toctree)['fragment']
|
||||
|
@ -128,7 +128,7 @@ class Target(SphinxDirective):
|
||||
targetname = '%s-%s' % (self.name, fullname)
|
||||
node = nodes.target('', '', ids=[targetname])
|
||||
self.state.document.note_explicit_target(node)
|
||||
ret = [node] # type: List[nodes.Node]
|
||||
ret = [node] # type: List[Node]
|
||||
if self.indextemplate:
|
||||
indexentry = self.indextemplate % (fullname,)
|
||||
indextype = 'single'
|
||||
@ -254,7 +254,7 @@ def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index
|
||||
|
||||
if node_id:
|
||||
# node_id is given from outside (mainly i18n module), use it forcedly
|
||||
pass
|
||||
term['ids'].append(node_id)
|
||||
elif document:
|
||||
node_id = make_id(env, document, 'term', termtext)
|
||||
term['ids'].append(node_id)
|
||||
@ -313,7 +313,7 @@ class Glossary(SphinxDirective):
|
||||
in_definition = True
|
||||
in_comment = False
|
||||
was_empty = True
|
||||
messages = [] # type: List[nodes.Node]
|
||||
messages = [] # type: List[Node]
|
||||
for line, (source, lineno) in zip(self.content, self.content.items):
|
||||
# empty line -> add to last definition
|
||||
if not line:
|
||||
@ -369,8 +369,8 @@ class Glossary(SphinxDirective):
|
||||
items = []
|
||||
for terms, definition in entries:
|
||||
termtexts = [] # type: List[str]
|
||||
termnodes = [] # type: List[nodes.Node]
|
||||
system_messages = [] # type: List[nodes.Node]
|
||||
termnodes = [] # type: List[Node]
|
||||
system_messages = [] # type: List[Node]
|
||||
for line, source, lineno in terms:
|
||||
parts = split_term_classifiers(line)
|
||||
# parse the term with inline markup
|
||||
@ -407,7 +407,7 @@ class Glossary(SphinxDirective):
|
||||
|
||||
|
||||
def token_xrefs(text: str) -> List[Node]:
|
||||
retnodes = [] # type: List[nodes.Node]
|
||||
retnodes = [] # type: List[Node]
|
||||
pos = 0
|
||||
for m in token_re.finditer(text):
|
||||
if m.start() > pos:
|
||||
@ -436,7 +436,7 @@ class ProductionList(SphinxDirective):
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
domain = cast(StandardDomain, self.env.get_domain('std'))
|
||||
node = addnodes.productionlist() # type: nodes.Element
|
||||
node = addnodes.productionlist() # type: Element
|
||||
i = 0
|
||||
|
||||
for rule in self.arguments[0].split('\n'):
|
||||
@ -538,7 +538,7 @@ class StandardDomain(Domain):
|
||||
nodes.figure: ('figure', None),
|
||||
nodes.table: ('table', None),
|
||||
nodes.container: ('code-block', None),
|
||||
} # type: Dict[Type[nodes.Node], Tuple[str, Callable]]
|
||||
} # type: Dict[Type[Node], Tuple[str, Callable]]
|
||||
|
||||
def __init__(self, env: "BuildEnvironment") -> None:
|
||||
super().__init__(env)
|
||||
@ -847,7 +847,7 @@ class StandardDomain(Domain):
|
||||
def resolve_any_xref(self, env: "BuildEnvironment", fromdocname: str,
|
||||
builder: "Builder", target: str, node: pending_xref,
|
||||
contnode: Element) -> List[Tuple[str, Element]]:
|
||||
results = [] # type: List[Tuple[str, nodes.Element]]
|
||||
results = [] # type: List[Tuple[str, Element]]
|
||||
ltarget = target.lower() # :ref: lowercases its target automatically
|
||||
for role in ('ref', 'option'): # do not try "keyword"
|
||||
res = self.resolve_xref(env, fromdocname, builder, role,
|
||||
@ -898,7 +898,7 @@ class StandardDomain(Domain):
|
||||
def get_numfig_title(self, node: Node) -> str:
|
||||
"""Get the title of enumerable nodes to refer them using its title"""
|
||||
if self.is_enumerable_node(node):
|
||||
elem = cast(nodes.Element, node)
|
||||
elem = cast(Element, node)
|
||||
_, title_getter = self.enumerable_nodes.get(elem.__class__, (None, None))
|
||||
if title_getter:
|
||||
return title_getter(elem)
|
||||
|
@ -315,17 +315,17 @@ class TocTree:
|
||||
return toc
|
||||
|
||||
def get_toctree_for(self, docname: str, builder: "Builder", collapse: bool,
|
||||
**kwds: Any) -> Element:
|
||||
**kwargs: Any) -> Element:
|
||||
"""Return the global TOC nodetree."""
|
||||
doctree = self.env.get_doctree(self.env.config.master_doc)
|
||||
toctrees = [] # type: List[Element]
|
||||
if 'includehidden' not in kwds:
|
||||
kwds['includehidden'] = True
|
||||
if 'maxdepth' not in kwds:
|
||||
kwds['maxdepth'] = 0
|
||||
kwds['collapse'] = collapse
|
||||
if 'includehidden' not in kwargs:
|
||||
kwargs['includehidden'] = True
|
||||
if 'maxdepth' not in kwargs:
|
||||
kwargs['maxdepth'] = 0
|
||||
kwargs['collapse'] = collapse
|
||||
for toctreenode in doctree.traverse(addnodes.toctree):
|
||||
toctree = self.resolve(docname, builder, toctreenode, prune=True, **kwds)
|
||||
toctree = self.resolve(docname, builder, toctreenode, prune=True, **kwargs)
|
||||
if toctree:
|
||||
toctrees.append(toctree)
|
||||
if not toctrees:
|
||||
|
@ -31,7 +31,7 @@ from sphinx.util import logging
|
||||
from sphinx.util import rpartition
|
||||
from sphinx.util.docstrings import prepare_docstring
|
||||
from sphinx.util.inspect import (
|
||||
Signature, getdoc, object_description, safe_getattr, safe_getmembers
|
||||
getdoc, object_description, safe_getattr, safe_getmembers, stringify_signature
|
||||
)
|
||||
|
||||
if False:
|
||||
@ -1006,9 +1006,10 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
||||
not inspect.isbuiltin(self.object) and
|
||||
not inspect.isclass(self.object) and
|
||||
hasattr(self.object, '__call__')):
|
||||
args = Signature(self.object.__call__).format_args(**kwargs)
|
||||
sig = inspect.signature(self.object.__call__)
|
||||
else:
|
||||
args = Signature(self.object).format_args(**kwargs)
|
||||
sig = inspect.signature(self.object)
|
||||
args = stringify_signature(sig, **kwargs)
|
||||
except TypeError:
|
||||
if (inspect.is_builtin_class_method(self.object, '__new__') and
|
||||
inspect.is_builtin_class_method(self.object, '__init__')):
|
||||
@ -1018,11 +1019,11 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
||||
# typing) we try to use the constructor signature as function
|
||||
# signature without the first argument.
|
||||
try:
|
||||
sig = Signature(self.object.__new__, bound_method=True, has_retval=False)
|
||||
args = sig.format_args(**kwargs)
|
||||
sig = inspect.signature(self.object.__new__, bound_method=True)
|
||||
args = stringify_signature(sig, show_return_annotation=False, **kwargs)
|
||||
except TypeError:
|
||||
sig = Signature(self.object.__init__, bound_method=True, has_retval=False)
|
||||
args = sig.format_args(**kwargs)
|
||||
sig = inspect.signature(self.object.__init__, bound_method=True)
|
||||
args = stringify_signature(sig, show_return_annotation=False, **kwargs)
|
||||
|
||||
# escape backslashes for reST
|
||||
args = args.replace('\\', '\\\\')
|
||||
@ -1103,8 +1104,8 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
||||
not(inspect.ismethod(initmeth) or inspect.isfunction(initmeth)):
|
||||
return None
|
||||
try:
|
||||
sig = Signature(initmeth, bound_method=True, has_retval=False)
|
||||
return sig.format_args(**kwargs)
|
||||
sig = inspect.signature(initmeth, bound_method=True)
|
||||
return stringify_signature(sig, show_return_annotation=False, **kwargs)
|
||||
except TypeError:
|
||||
# still not possible: happens e.g. for old-style classes
|
||||
# with __init__ in C
|
||||
@ -1306,9 +1307,11 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
||||
# can never get arguments of a C function or method
|
||||
return None
|
||||
if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name):
|
||||
args = Signature(self.object, bound_method=False).format_args(**kwargs)
|
||||
sig = inspect.signature(self.object, bound_method=False)
|
||||
else:
|
||||
args = Signature(self.object, bound_method=True).format_args(**kwargs)
|
||||
sig = inspect.signature(self.object, bound_method=True)
|
||||
args = stringify_signature(sig, **kwargs)
|
||||
|
||||
# escape backslashes for reST
|
||||
args = args.replace('\\', '\\\\')
|
||||
return args
|
||||
|
@ -57,7 +57,7 @@ class _MockObject:
|
||||
def __getattr__(self, key: str) -> "_MockObject":
|
||||
return _make_subclass(key, self.__display_name__, self.__class__)()
|
||||
|
||||
def __call__(self, *args: Any, **kw: Any) -> Any:
|
||||
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
||||
if args and type(args[0]) in [type, FunctionType, MethodType]:
|
||||
# Appears to be a decorator, pass through unchanged
|
||||
return args[0]
|
||||
|
@ -27,6 +27,7 @@ class ImagemagickConverter(ImageConverter):
|
||||
('image/svg+xml', 'image/png'),
|
||||
('image/gif', 'image/png'),
|
||||
('application/pdf', 'image/png'),
|
||||
('application/illustrator', 'image/png'),
|
||||
]
|
||||
|
||||
def is_available(self) -> bool:
|
||||
|
@ -101,8 +101,8 @@ class GoogleDocstring:
|
||||
|
||||
"""
|
||||
|
||||
_name_rgx = re.compile(r"^\s*((?::(?P<role>\S+):)?`(?P<name>[a-zA-Z0-9_.-]+)`|"
|
||||
r" (?P<name2>[a-zA-Z0-9_.-]+))\s*", re.X)
|
||||
_name_rgx = re.compile(r"^\s*((?::(?P<role>\S+):)?`(?P<name>~?[a-zA-Z0-9_.-]+)`|"
|
||||
r" (?P<name2>~?[a-zA-Z0-9_.-]+))\s*", re.X)
|
||||
|
||||
def __init__(self, docstring: Union[str, List[str]], config: SphinxConfig = None,
|
||||
app: Sphinx = None, what: str = '', name: str = '',
|
||||
|
@ -92,8 +92,8 @@ def etree_parse(path: str) -> Any:
|
||||
|
||||
|
||||
class Struct:
|
||||
def __init__(self, **kwds: Any) -> None:
|
||||
self.__dict__.update(kwds)
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
self.__dict__.update(kwargs)
|
||||
|
||||
|
||||
class SphinxTestApp(application.Sphinx):
|
||||
@ -165,10 +165,10 @@ class SphinxTestAppWrapperForSkipBuilding:
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
return getattr(self.app, name)
|
||||
|
||||
def build(self, *args: Any, **kw: Any) -> None:
|
||||
def build(self, *args: Any, **kwargs: Any) -> None:
|
||||
if not self.app.outdir.listdir(): # type: ignore
|
||||
# if listdir is empty, do build.
|
||||
self.app.build(*args, **kw)
|
||||
self.app.build(*args, **kwargs)
|
||||
# otherwise, we can use built cache
|
||||
|
||||
|
||||
|
@ -222,7 +222,6 @@ class ImageConverter(BaseImageConverter):
|
||||
if '?' in node['candidates']:
|
||||
return []
|
||||
elif '*' in node['candidates']:
|
||||
from sphinx.util.images import guess_mimetype
|
||||
return [guess_mimetype(node['uri'])]
|
||||
else:
|
||||
return node['candidates'].keys()
|
||||
|
@ -28,6 +28,7 @@ mime_suffixes = OrderedDict([
|
||||
('.pdf', 'application/pdf'),
|
||||
('.svg', 'image/svg+xml'),
|
||||
('.svgz', 'image/svg+xml'),
|
||||
('.ai', 'application/illustrator'),
|
||||
])
|
||||
|
||||
DataURI = NamedTuple('DataURI', [('mimetype', str),
|
||||
|
@ -315,6 +315,112 @@ def is_builtin_class_method(obj: Any, attr_name: str) -> bool:
|
||||
return getattr(builtins, safe_getattr(cls, '__name__', '')) is cls
|
||||
|
||||
|
||||
def signature(subject: Callable, bound_method: bool = False) -> inspect.Signature:
|
||||
"""Return a Signature object for the given *subject*.
|
||||
|
||||
:param bound_method: Specify *subject* is a bound method or not
|
||||
"""
|
||||
# check subject is not a built-in class (ex. int, str)
|
||||
if (isinstance(subject, type) and
|
||||
is_builtin_class_method(subject, "__new__") and
|
||||
is_builtin_class_method(subject, "__init__")):
|
||||
raise TypeError("can't compute signature for built-in type {}".format(subject))
|
||||
|
||||
try:
|
||||
signature = inspect.signature(subject)
|
||||
parameters = list(signature.parameters.values())
|
||||
return_annotation = signature.return_annotation
|
||||
except IndexError:
|
||||
# Until python 3.6.4, cpython has been crashed on inspection for
|
||||
# partialmethods not having any arguments.
|
||||
# https://bugs.python.org/issue33009
|
||||
if hasattr(subject, '_partialmethod'):
|
||||
parameters = []
|
||||
return_annotation = inspect.Parameter.empty
|
||||
else:
|
||||
raise
|
||||
|
||||
try:
|
||||
# Update unresolved annotations using ``get_type_hints()``.
|
||||
annotations = typing.get_type_hints(subject)
|
||||
for i, param in enumerate(parameters):
|
||||
if isinstance(param.annotation, str) and param.name in annotations:
|
||||
parameters[i] = param.replace(annotation=annotations[param.name])
|
||||
if 'return' in annotations:
|
||||
return_annotation = annotations['return']
|
||||
except Exception:
|
||||
# ``get_type_hints()`` does not support some kind of objects like partial,
|
||||
# ForwardRef and so on.
|
||||
pass
|
||||
|
||||
if bound_method:
|
||||
if inspect.ismethod(subject):
|
||||
# ``inspect.signature()`` considers the subject is a bound method and removes
|
||||
# first argument from signature. Therefore no skips are needed here.
|
||||
pass
|
||||
else:
|
||||
if len(parameters) > 0:
|
||||
parameters.pop(0)
|
||||
|
||||
return inspect.Signature(parameters, return_annotation=return_annotation)
|
||||
|
||||
|
||||
def stringify_signature(sig: inspect.Signature, show_annotation: bool = True,
|
||||
show_return_annotation: bool = True) -> str:
|
||||
"""Stringify a Signature object.
|
||||
|
||||
:param show_annotation: Show annotation in result
|
||||
"""
|
||||
args = []
|
||||
last_kind = None
|
||||
for param in sig.parameters.values():
|
||||
# insert '*' between POSITIONAL args and KEYWORD_ONLY args::
|
||||
# func(a, b, *, c, d):
|
||||
if param.kind == param.KEYWORD_ONLY and last_kind in (param.POSITIONAL_OR_KEYWORD,
|
||||
param.POSITIONAL_ONLY,
|
||||
None):
|
||||
args.append('*')
|
||||
|
||||
arg = StringIO()
|
||||
if param.kind in (param.POSITIONAL_ONLY,
|
||||
param.POSITIONAL_OR_KEYWORD,
|
||||
param.KEYWORD_ONLY):
|
||||
arg.write(param.name)
|
||||
if show_annotation and param.annotation is not param.empty:
|
||||
arg.write(': ')
|
||||
arg.write(stringify_annotation(param.annotation))
|
||||
if param.default is not param.empty:
|
||||
if show_annotation and param.annotation is not param.empty:
|
||||
arg.write(' = ')
|
||||
arg.write(object_description(param.default))
|
||||
else:
|
||||
arg.write('=')
|
||||
arg.write(object_description(param.default))
|
||||
elif param.kind == param.VAR_POSITIONAL:
|
||||
arg.write('*')
|
||||
arg.write(param.name)
|
||||
if show_annotation and param.annotation is not param.empty:
|
||||
arg.write(': ')
|
||||
arg.write(stringify_annotation(param.annotation))
|
||||
elif param.kind == param.VAR_KEYWORD:
|
||||
arg.write('**')
|
||||
arg.write(param.name)
|
||||
if show_annotation and param.annotation is not param.empty:
|
||||
arg.write(': ')
|
||||
arg.write(stringify_annotation(param.annotation))
|
||||
|
||||
args.append(arg.getvalue())
|
||||
last_kind = param.kind
|
||||
|
||||
if (sig.return_annotation is inspect.Parameter.empty or
|
||||
show_annotation is False or
|
||||
show_return_annotation is False):
|
||||
return '(%s)' % ', '.join(args)
|
||||
else:
|
||||
annotation = stringify_annotation(sig.return_annotation)
|
||||
return '(%s) -> %s' % (', '.join(args), annotation)
|
||||
|
||||
|
||||
class Signature:
|
||||
"""The Signature object represents the call signature of a callable object and
|
||||
its return annotation.
|
||||
@ -322,6 +428,9 @@ class Signature:
|
||||
|
||||
def __init__(self, subject: Callable, bound_method: bool = False,
|
||||
has_retval: bool = True) -> None:
|
||||
warnings.warn('sphinx.util.inspect.Signature() is deprecated',
|
||||
RemovedInSphinx40Warning)
|
||||
|
||||
# check subject is not a built-in class (ex. int, str)
|
||||
if (isinstance(subject, type) and
|
||||
is_builtin_class_method(subject, "__new__") and
|
||||
@ -447,20 +556,14 @@ class Signature:
|
||||
|
||||
def format_annotation(self, annotation: Any) -> str:
|
||||
"""Return formatted representation of a type annotation."""
|
||||
warnings.warn('format_annotation() is deprecated',
|
||||
RemovedInSphinx40Warning)
|
||||
return stringify_annotation(annotation)
|
||||
|
||||
def format_annotation_new(self, annotation: Any) -> str:
|
||||
"""format_annotation() for py37+"""
|
||||
warnings.warn('format_annotation_new() is deprecated',
|
||||
RemovedInSphinx40Warning)
|
||||
return stringify_annotation(annotation)
|
||||
|
||||
def format_annotation_old(self, annotation: Any) -> str:
|
||||
"""format_annotation() for py36 or below"""
|
||||
warnings.warn('format_annotation_old() is deprecated',
|
||||
RemovedInSphinx40Warning)
|
||||
return stringify_annotation(annotation)
|
||||
|
||||
|
||||
|
@ -28,19 +28,19 @@ class SphinxJSONEncoder(json.JSONEncoder):
|
||||
return super().default(obj)
|
||||
|
||||
|
||||
def dump(obj: Any, fp: IO, *args: Any, **kwds: Any) -> None:
|
||||
kwds['cls'] = SphinxJSONEncoder
|
||||
json.dump(obj, fp, *args, **kwds)
|
||||
def dump(obj: Any, fp: IO, *args: Any, **kwargs: Any) -> None:
|
||||
kwargs['cls'] = SphinxJSONEncoder
|
||||
json.dump(obj, fp, *args, **kwargs)
|
||||
|
||||
|
||||
def dumps(obj: Any, *args: Any, **kwds: Any) -> str:
|
||||
kwds['cls'] = SphinxJSONEncoder
|
||||
return json.dumps(obj, *args, **kwds)
|
||||
def dumps(obj: Any, *args: Any, **kwargs: Any) -> str:
|
||||
kwargs['cls'] = SphinxJSONEncoder
|
||||
return json.dumps(obj, *args, **kwargs)
|
||||
|
||||
|
||||
def load(*args: Any, **kwds: Any) -> Any:
|
||||
return json.load(*args, **kwds)
|
||||
def load(*args: Any, **kwargs: Any) -> Any:
|
||||
return json.load(*args, **kwargs)
|
||||
|
||||
|
||||
def loads(*args: Any, **kwds: Any) -> Any:
|
||||
return json.loads(*args, **kwds)
|
||||
def loads(*args: Any, **kwargs: Any) -> Any:
|
||||
return json.loads(*args, **kwargs)
|
||||
|
@ -1342,13 +1342,13 @@ def test_partialmethod(app):
|
||||
' refs: https://docs.python.jp/3/library/functools.html#functools.partialmethod',
|
||||
' ',
|
||||
' ',
|
||||
' .. py:method:: Cell.set_alive() -> None',
|
||||
' .. py:method:: Cell.set_alive()',
|
||||
' :module: target.partialmethod',
|
||||
' ',
|
||||
' Make a cell alive.',
|
||||
' ',
|
||||
' ',
|
||||
' .. py:method:: Cell.set_dead() -> None',
|
||||
' .. py:method:: Cell.set_dead()',
|
||||
' :module: target.partialmethod',
|
||||
' ',
|
||||
' Make a cell dead.',
|
||||
@ -1360,11 +1360,6 @@ def test_partialmethod(app):
|
||||
' Update state of cell to *state*.',
|
||||
' ',
|
||||
]
|
||||
if (sys.version_info < (3, 5, 4) or
|
||||
(3, 6, 5) <= sys.version_info < (3, 7) or
|
||||
(3, 7, 0, 'beta', 3) <= sys.version_info):
|
||||
# TODO: this condition should be updated after 3.7-final release.
|
||||
expected = '\n'.join(expected).replace(' -> None', '').split('\n')
|
||||
|
||||
options = {"members": None}
|
||||
actual = do_autodoc(app, 'class', 'target.partialmethod.Cell', options)
|
||||
|
@ -479,6 +479,8 @@ Raises:
|
||||
If the dimensions couldn't be parsed.
|
||||
`InvalidArgumentsError`
|
||||
If the arguments are invalid.
|
||||
:exc:`~ValueError`
|
||||
If the arguments are wrong.
|
||||
|
||||
""", """
|
||||
Example Function
|
||||
@ -488,6 +490,7 @@ Example Function
|
||||
:raises AttributeError: errors for missing attributes.
|
||||
:raises ~InvalidDimensionsError: If the dimensions couldn't be parsed.
|
||||
:raises InvalidArgumentsError: If the arguments are invalid.
|
||||
:raises ~ValueError: If the arguments are wrong.
|
||||
"""),
|
||||
################################
|
||||
("""
|
||||
|
@ -17,6 +17,7 @@ import types
|
||||
import pytest
|
||||
|
||||
from sphinx.util import inspect
|
||||
from sphinx.util.inspect import stringify_signature
|
||||
|
||||
|
||||
def test_getargspec():
|
||||
@ -89,39 +90,39 @@ def test_getargspec_bound_methods():
|
||||
assert expected_bound == inspect.getargspec(wrapped_bound_method)
|
||||
|
||||
|
||||
def test_Signature():
|
||||
def test_signature():
|
||||
# literals
|
||||
with pytest.raises(TypeError):
|
||||
inspect.Signature(1)
|
||||
inspect.signature(1)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
inspect.Signature('')
|
||||
inspect.signature('')
|
||||
|
||||
# builitin classes
|
||||
with pytest.raises(TypeError):
|
||||
inspect.Signature(int)
|
||||
inspect.signature(int)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
inspect.Signature(str)
|
||||
inspect.signature(str)
|
||||
|
||||
# normal function
|
||||
def func(a, b, c=1, d=2, *e, **f):
|
||||
pass
|
||||
|
||||
sig = inspect.Signature(func).format_args()
|
||||
sig = inspect.stringify_signature(inspect.signature(func))
|
||||
assert sig == '(a, b, c=1, d=2, *e, **f)'
|
||||
|
||||
|
||||
def test_Signature_partial():
|
||||
def test_signature_partial():
|
||||
def fun(a, b, c=1, d=2):
|
||||
pass
|
||||
p = functools.partial(fun, 10, c=11)
|
||||
|
||||
sig = inspect.Signature(p).format_args()
|
||||
assert sig == '(b, *, c=11, d=2)'
|
||||
sig = inspect.signature(p)
|
||||
assert stringify_signature(sig) == '(b, *, c=11, d=2)'
|
||||
|
||||
|
||||
def test_Signature_methods():
|
||||
def test_signature_methods():
|
||||
class Foo:
|
||||
def meth1(self, arg1, **kwargs):
|
||||
pass
|
||||
@ -139,36 +140,36 @@ def test_Signature_methods():
|
||||
pass
|
||||
|
||||
# unbound method
|
||||
sig = inspect.Signature(Foo.meth1).format_args()
|
||||
assert sig == '(self, arg1, **kwargs)'
|
||||
sig = inspect.signature(Foo.meth1)
|
||||
assert stringify_signature(sig) == '(self, arg1, **kwargs)'
|
||||
|
||||
sig = inspect.Signature(Foo.meth1, bound_method=True).format_args()
|
||||
assert sig == '(arg1, **kwargs)'
|
||||
sig = inspect.signature(Foo.meth1, bound_method=True)
|
||||
assert stringify_signature(sig) == '(arg1, **kwargs)'
|
||||
|
||||
# bound method
|
||||
sig = inspect.Signature(Foo().meth1).format_args()
|
||||
assert sig == '(arg1, **kwargs)'
|
||||
sig = inspect.signature(Foo().meth1)
|
||||
assert stringify_signature(sig) == '(arg1, **kwargs)'
|
||||
|
||||
# class method
|
||||
sig = inspect.Signature(Foo.meth2).format_args()
|
||||
assert sig == '(arg1, *args, **kwargs)'
|
||||
sig = inspect.signature(Foo.meth2)
|
||||
assert stringify_signature(sig) == '(arg1, *args, **kwargs)'
|
||||
|
||||
sig = inspect.Signature(Foo().meth2).format_args()
|
||||
assert sig == '(arg1, *args, **kwargs)'
|
||||
sig = inspect.signature(Foo().meth2)
|
||||
assert stringify_signature(sig) == '(arg1, *args, **kwargs)'
|
||||
|
||||
# static method
|
||||
sig = inspect.Signature(Foo.meth3).format_args()
|
||||
assert sig == '(arg1, *args, **kwargs)'
|
||||
sig = inspect.signature(Foo.meth3)
|
||||
assert stringify_signature(sig) == '(arg1, *args, **kwargs)'
|
||||
|
||||
sig = inspect.Signature(Foo().meth3).format_args()
|
||||
assert sig == '(arg1, *args, **kwargs)'
|
||||
sig = inspect.signature(Foo().meth3)
|
||||
assert stringify_signature(sig) == '(arg1, *args, **kwargs)'
|
||||
|
||||
# wrapped bound method
|
||||
sig = inspect.Signature(wrapped_bound_method).format_args()
|
||||
assert sig == '(arg1, **kwargs)'
|
||||
sig = inspect.signature(wrapped_bound_method)
|
||||
assert stringify_signature(sig) == '(arg1, **kwargs)'
|
||||
|
||||
|
||||
def test_Signature_partialmethod():
|
||||
def test_signature_partialmethod():
|
||||
from functools import partialmethod
|
||||
|
||||
class Foo:
|
||||
@ -183,116 +184,115 @@ def test_Signature_partialmethod():
|
||||
baz = partialmethod(meth2, 1, 2)
|
||||
|
||||
subject = Foo()
|
||||
sig = inspect.Signature(subject.foo).format_args()
|
||||
assert sig == '(arg3=None, arg4=None)'
|
||||
sig = inspect.signature(subject.foo)
|
||||
assert stringify_signature(sig) == '(arg3=None, arg4=None)'
|
||||
|
||||
sig = inspect.Signature(subject.bar).format_args()
|
||||
assert sig == '(arg2, *, arg3=3, arg4=None)'
|
||||
sig = inspect.signature(subject.bar)
|
||||
assert stringify_signature(sig) == '(arg2, *, arg3=3, arg4=None)'
|
||||
|
||||
sig = inspect.Signature(subject.baz).format_args()
|
||||
assert sig == '()'
|
||||
sig = inspect.signature(subject.baz)
|
||||
assert stringify_signature(sig) == '()'
|
||||
|
||||
|
||||
def test_Signature_annotations():
|
||||
def test_signature_annotations():
|
||||
from typing_test_data import (f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10,
|
||||
f11, f12, f13, f14, f15, f16, f17, f18, f19, Node)
|
||||
|
||||
# Class annotations
|
||||
sig = inspect.Signature(f0).format_args()
|
||||
assert sig == '(x: int, y: numbers.Integral) -> None'
|
||||
sig = inspect.signature(f0)
|
||||
assert stringify_signature(sig) == '(x: int, y: numbers.Integral) -> None'
|
||||
|
||||
# Generic types with concrete parameters
|
||||
sig = inspect.Signature(f1).format_args()
|
||||
assert sig == '(x: List[int]) -> List[int]'
|
||||
sig = inspect.signature(f1)
|
||||
assert stringify_signature(sig) == '(x: List[int]) -> List[int]'
|
||||
|
||||
# TypeVars and generic types with TypeVars
|
||||
sig = inspect.Signature(f2).format_args()
|
||||
assert sig == '(x: List[T], y: List[T_co], z: T) -> List[T_contra]'
|
||||
sig = inspect.signature(f2)
|
||||
assert stringify_signature(sig) == '(x: List[T], y: List[T_co], z: T) -> List[T_contra]'
|
||||
|
||||
# Union types
|
||||
sig = inspect.Signature(f3).format_args()
|
||||
assert sig == '(x: Union[str, numbers.Integral]) -> None'
|
||||
sig = inspect.signature(f3)
|
||||
assert stringify_signature(sig) == '(x: Union[str, numbers.Integral]) -> None'
|
||||
|
||||
# Quoted annotations
|
||||
sig = inspect.Signature(f4).format_args()
|
||||
assert sig == '(x: str, y: str) -> None'
|
||||
sig = inspect.signature(f4)
|
||||
assert stringify_signature(sig) == '(x: str, y: str) -> None'
|
||||
|
||||
# Keyword-only arguments
|
||||
sig = inspect.Signature(f5).format_args()
|
||||
assert sig == '(x: int, *, y: str, z: str) -> None'
|
||||
sig = inspect.signature(f5)
|
||||
assert stringify_signature(sig) == '(x: int, *, y: str, z: str) -> None'
|
||||
|
||||
# Keyword-only arguments with varargs
|
||||
sig = inspect.Signature(f6).format_args()
|
||||
assert sig == '(x: int, *args, y: str, z: str) -> None'
|
||||
sig = inspect.signature(f6)
|
||||
assert stringify_signature(sig) == '(x: int, *args, y: str, z: str) -> None'
|
||||
|
||||
# Space around '=' for defaults
|
||||
sig = inspect.Signature(f7).format_args()
|
||||
assert sig == '(x: int = None, y: dict = {}) -> None'
|
||||
sig = inspect.signature(f7)
|
||||
assert stringify_signature(sig) == '(x: int = None, y: dict = {}) -> None'
|
||||
|
||||
# Callable types
|
||||
sig = inspect.Signature(f8).format_args()
|
||||
assert sig == '(x: Callable[[int, str], int]) -> None'
|
||||
sig = inspect.signature(f8)
|
||||
assert stringify_signature(sig) == '(x: Callable[[int, str], int]) -> None'
|
||||
|
||||
sig = inspect.Signature(f9).format_args()
|
||||
assert sig == '(x: Callable) -> None'
|
||||
sig = inspect.signature(f9)
|
||||
assert stringify_signature(sig) == '(x: Callable) -> None'
|
||||
|
||||
# Tuple types
|
||||
sig = inspect.Signature(f10).format_args()
|
||||
assert sig == '(x: Tuple[int, str], y: Tuple[int, ...]) -> None'
|
||||
sig = inspect.signature(f10)
|
||||
assert stringify_signature(sig) == '(x: Tuple[int, str], y: Tuple[int, ...]) -> None'
|
||||
|
||||
# Instance annotations
|
||||
sig = inspect.Signature(f11).format_args()
|
||||
assert sig == '(x: CustomAnnotation, y: 123) -> None'
|
||||
|
||||
# has_retval=False
|
||||
sig = inspect.Signature(f11, has_retval=False).format_args()
|
||||
assert sig == '(x: CustomAnnotation, y: 123)'
|
||||
sig = inspect.signature(f11)
|
||||
assert stringify_signature(sig) == '(x: CustomAnnotation, y: 123) -> None'
|
||||
|
||||
# tuple with more than two items
|
||||
sig = inspect.Signature(f12).format_args()
|
||||
assert sig == '() -> Tuple[int, str, int]'
|
||||
sig = inspect.signature(f12)
|
||||
assert stringify_signature(sig) == '() -> Tuple[int, str, int]'
|
||||
|
||||
# optional
|
||||
sig = inspect.Signature(f13).format_args()
|
||||
assert sig == '() -> Optional[str]'
|
||||
sig = inspect.signature(f13)
|
||||
assert stringify_signature(sig) == '() -> Optional[str]'
|
||||
|
||||
# Any
|
||||
sig = inspect.Signature(f14).format_args()
|
||||
assert sig == '() -> Any'
|
||||
sig = inspect.signature(f14)
|
||||
assert stringify_signature(sig) == '() -> Any'
|
||||
|
||||
# ForwardRef
|
||||
sig = inspect.Signature(f15).format_args()
|
||||
assert sig == '(x: Unknown, y: int) -> Any'
|
||||
sig = inspect.signature(f15)
|
||||
assert stringify_signature(sig) == '(x: Unknown, y: int) -> Any'
|
||||
|
||||
# keyword only arguments (1)
|
||||
sig = inspect.Signature(f16).format_args()
|
||||
assert sig == '(arg1, arg2, *, arg3=None, arg4=None)'
|
||||
sig = inspect.signature(f16)
|
||||
assert stringify_signature(sig) == '(arg1, arg2, *, arg3=None, arg4=None)'
|
||||
|
||||
# keyword only arguments (2)
|
||||
sig = inspect.Signature(f17).format_args()
|
||||
assert sig == '(*, arg3, arg4)'
|
||||
sig = inspect.signature(f17)
|
||||
assert stringify_signature(sig) == '(*, arg3, arg4)'
|
||||
|
||||
sig = inspect.Signature(f18).format_args()
|
||||
assert sig == '(self, arg1: Union[int, Tuple] = 10) -> List[Dict]'
|
||||
sig = inspect.signature(f18)
|
||||
assert stringify_signature(sig) == '(self, arg1: Union[int, Tuple] = 10) -> List[Dict]'
|
||||
|
||||
# annotations for variadic and keyword parameters
|
||||
sig = inspect.Signature(f19).format_args()
|
||||
assert sig == '(*args: int, **kwargs: str)'
|
||||
sig = inspect.signature(f19)
|
||||
assert stringify_signature(sig) == '(*args: int, **kwargs: str)'
|
||||
|
||||
# type hints by string
|
||||
sig = inspect.Signature(Node.children).format_args()
|
||||
sig = inspect.signature(Node.children)
|
||||
if (3, 5, 0) <= sys.version_info < (3, 5, 3):
|
||||
assert sig == '(self) -> List[Node]'
|
||||
assert stringify_signature(sig) == '(self) -> List[Node]'
|
||||
else:
|
||||
assert sig == '(self) -> List[typing_test_data.Node]'
|
||||
assert stringify_signature(sig) == '(self) -> List[typing_test_data.Node]'
|
||||
|
||||
sig = inspect.Signature(Node.__init__).format_args()
|
||||
assert sig == '(self, parent: Optional[Node]) -> None'
|
||||
sig = inspect.signature(Node.__init__)
|
||||
assert stringify_signature(sig) == '(self, parent: Optional[Node]) -> None'
|
||||
|
||||
# show_annotation is False
|
||||
sig = inspect.Signature(f7).format_args(show_annotation=False)
|
||||
assert sig == '(x=None, y={})'
|
||||
sig = inspect.signature(f7)
|
||||
assert stringify_signature(sig, show_annotation=False) == '(x=None, y={})'
|
||||
|
||||
# show_return_annotation is False
|
||||
sig = inspect.signature(f7)
|
||||
assert stringify_signature(sig, show_return_annotation=False) == '(x: int = None, y: dict = {})'
|
||||
|
||||
def test_safe_getattr_with_default():
|
||||
class Foo:
|
||||
|
Loading…
Reference in New Issue
Block a user