mirror of
https://github.com/readthedocs/sphinx-autoapi
synced 2024-11-10 01:10:27 +00:00
Fixed type hints still showing when setting autodoc_typehints
Closes #273
This commit is contained in:
parent
565c43d99b
commit
bf8f50dc97
@ -14,12 +14,21 @@ Features
|
|||||||
* `#265 <https://github.com/readthedocs/sphinx-autoapi/issues/265>`
|
* `#265 <https://github.com/readthedocs/sphinx-autoapi/issues/265>`
|
||||||
Can resolve the qualified paths of parameters to generics.
|
Can resolve the qualified paths of parameters to generics.
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
^^^^^^^^^
|
||||||
|
|
||||||
|
* `#273 <https://github.com/readthedocs/sphinx-autoapi/issues/273>`
|
||||||
|
Fixed setting ``autodoc_typehints`` to ``none`` or ``description``
|
||||||
|
not turning off signature type hints.
|
||||||
|
``autodoc_typehints`` integration is consisidered experimental until
|
||||||
|
the extension properly supports overload functions.
|
||||||
|
|
||||||
Trivial/Internal Changes
|
Trivial/Internal Changes
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
* Fixed `DeprecationWarning` for invalid escape sequence `\s` in tests.
|
* Fixed ``DeprecationWarning`` for invalid escape sequence ``\s`` in tests.
|
||||||
* Fixed `FutureWarning` for `Node.traverse()` becoming an iterator instead of list.
|
* Fixed ``FutureWarning`` for ``Node.traverse()`` becoming an iterator instead of list.
|
||||||
* New example implementation of `autoapi-skip-member` Sphinx event.
|
* New example implementation of ``autoapi-skip-member`` Sphinx event.
|
||||||
* Can run tests with tox 4.
|
* Can run tests with tox 4.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import builtins
|
import builtins
|
||||||
import collections
|
|
||||||
import itertools
|
import itertools
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
@ -114,7 +113,7 @@ def get_full_basenames(node):
|
|||||||
:returns: The full names.
|
:returns: The full names.
|
||||||
:rtype: iterable(str)
|
:rtype: iterable(str)
|
||||||
"""
|
"""
|
||||||
for base, basename in zip(node.bases, node.basenames):
|
for base in node.bases:
|
||||||
yield _resolve_annotation(base)
|
yield _resolve_annotation(base)
|
||||||
|
|
||||||
|
|
||||||
@ -415,7 +414,9 @@ def _resolve_annotation(annotation):
|
|||||||
elif isinstance(annotation, astroid.Subscript):
|
elif isinstance(annotation, astroid.Subscript):
|
||||||
value = _resolve_annotation(annotation.value)
|
value = _resolve_annotation(annotation.value)
|
||||||
if isinstance(annotation.slice, astroid.Tuple):
|
if isinstance(annotation.slice, astroid.Tuple):
|
||||||
slice_ = ", ".join(_resolve_annotation(elt) for elt in annotation.slice.elts)
|
slice_ = ", ".join(
|
||||||
|
_resolve_annotation(elt) for elt in annotation.slice.elts
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
slice_ = _resolve_annotation(annotation.slice)
|
slice_ = _resolve_annotation(annotation.slice)
|
||||||
resolved = f"{value}[{slice_}]"
|
resolved = f"{value}[{slice_}]"
|
||||||
@ -471,7 +472,7 @@ def _iter_args(args, annotations, defaults):
|
|||||||
yield (name, format_annotation(annotation, arg.parent), default)
|
yield (name, format_annotation(annotation, arg.parent), default)
|
||||||
|
|
||||||
|
|
||||||
def _get_args_info(args_node): # pylint: disable=too-many-branches,too-many-statements
|
def get_args_info(args_node): # pylint: disable=too-many-branches,too-many-statements
|
||||||
result = []
|
result = []
|
||||||
positional_only_defaults = []
|
positional_only_defaults = []
|
||||||
positional_or_keyword_defaults = args_node.defaults
|
positional_or_keyword_defaults = args_node.defaults
|
||||||
@ -570,31 +571,18 @@ def _get_args_info(args_node): # pylint: disable=too-many-branches,too-many-sta
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def format_args(args_node):
|
def get_return_annotation(node):
|
||||||
result = []
|
"""Get the return annotation of a node.
|
||||||
|
:type node: astroid.nodes.FunctionDef
|
||||||
|
"""
|
||||||
|
return_annotation = None
|
||||||
|
|
||||||
args_info = _get_args_info(args_node)
|
if node.returns:
|
||||||
for prefix, name, annotation, default in args_info:
|
return_annotation = format_annotation(node.returns, node)
|
||||||
formatted = "{}{}{}{}".format(
|
elif node.type_comment_returns:
|
||||||
prefix or "",
|
return_annotation = format_annotation(node.type_comment_returns, node)
|
||||||
name or "",
|
|
||||||
": {}".format(annotation) if annotation else "",
|
|
||||||
(" = {}" if annotation else "={}").format(default) if default else "",
|
|
||||||
)
|
|
||||||
result.append(formatted)
|
|
||||||
|
|
||||||
return ", ".join(result)
|
return return_annotation
|
||||||
|
|
||||||
|
|
||||||
def get_annotations_dict(args_node):
|
|
||||||
result = collections.OrderedDict()
|
|
||||||
|
|
||||||
args_info = _get_args_info(args_node)
|
|
||||||
for _, name, annotation, __ in args_info:
|
|
||||||
if name and annotation:
|
|
||||||
result[name] = annotation
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_func_docstring(node):
|
def get_func_docstring(node):
|
||||||
|
@ -213,7 +213,7 @@ def _link_objs(value):
|
|||||||
else:
|
else:
|
||||||
result += "\\ "
|
result += "\\ "
|
||||||
elif sub_target:
|
elif sub_target:
|
||||||
result += f":py:obj:`{sub_target}`\ "
|
result += f":py:obj:`{sub_target}`\\ "
|
||||||
|
|
||||||
# Strip off the extra "\ "
|
# Strip off the extra "\ "
|
||||||
return result[:-2]
|
return result[:-2]
|
||||||
@ -367,7 +367,7 @@ class PythonSphinxMapper(SphinxMapperBase):
|
|||||||
options=self.app.config.autoapi_options,
|
options=self.app.config.autoapi_options,
|
||||||
jinja_env=self.jinja_env,
|
jinja_env=self.jinja_env,
|
||||||
app=self.app,
|
app=self.app,
|
||||||
**kwargs
|
**kwargs,
|
||||||
)
|
)
|
||||||
obj.url_root = self.url_root
|
obj.url_root = self.url_root
|
||||||
|
|
||||||
@ -395,5 +395,14 @@ class PythonSphinxMapper(SphinxMapperBase):
|
|||||||
|
|
||||||
def _record_typehints(self, obj):
|
def _record_typehints(self, obj):
|
||||||
if isinstance(obj, (PythonClass, PythonFunction, PythonMethod)):
|
if isinstance(obj, (PythonClass, PythonFunction, PythonMethod)):
|
||||||
|
obj_annotations = {}
|
||||||
|
for _, name, annotation, _ in obj.obj["args"]:
|
||||||
|
if name and annotation:
|
||||||
|
obj_annotations[name] = annotation
|
||||||
|
|
||||||
|
return_annotation = obj.obj.get("return_annotation")
|
||||||
|
if return_annotation:
|
||||||
|
obj_annotations["return"] = return_annotation
|
||||||
|
|
||||||
annotations = self.app.env.temp_data.setdefault("annotations", {})
|
annotations = self.app.env.temp_data.setdefault("annotations", {})
|
||||||
annotations[obj.id] = obj.obj["annotations"]
|
annotations[obj.id] = obj_annotations
|
||||||
|
@ -8,6 +8,21 @@ from ..base import PythonMapperBase
|
|||||||
LOGGER = sphinx.util.logging.getLogger(__name__)
|
LOGGER = sphinx.util.logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _format_args(args_info, include_annotations=True):
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for prefix, name, annotation, default in args_info:
|
||||||
|
formatted = "{}{}{}{}".format(
|
||||||
|
prefix or "",
|
||||||
|
name or "",
|
||||||
|
": {}".format(annotation) if annotation and include_annotations else "",
|
||||||
|
(" = {}" if annotation else "={}").format(default) if default else "",
|
||||||
|
)
|
||||||
|
result.append(formatted)
|
||||||
|
|
||||||
|
return ", ".join(result)
|
||||||
|
|
||||||
|
|
||||||
class PythonPythonMapper(PythonMapperBase):
|
class PythonPythonMapper(PythonMapperBase):
|
||||||
"""A base class for all types of representations of Python objects.
|
"""A base class for all types of representations of Python objects.
|
||||||
|
|
||||||
@ -31,7 +46,6 @@ class PythonPythonMapper(PythonMapperBase):
|
|||||||
|
|
||||||
# Optional
|
# Optional
|
||||||
self.children = []
|
self.children = []
|
||||||
self.args = obj.get("args")
|
|
||||||
self.docstring = obj["doc"]
|
self.docstring = obj["doc"]
|
||||||
self.imported = "original_path" in obj
|
self.imported = "original_path" in obj
|
||||||
self.inherited = obj.get("inherited", False)
|
self.inherited = obj.get("inherited", False)
|
||||||
@ -45,21 +59,6 @@ class PythonPythonMapper(PythonMapperBase):
|
|||||||
|
|
||||||
self._display_cache = None # type: Optional[bool]
|
self._display_cache = None # type: Optional[bool]
|
||||||
|
|
||||||
@property
|
|
||||||
def args(self):
|
|
||||||
"""The arguments to this object, formatted as a string.
|
|
||||||
|
|
||||||
This will only be set for a function, method, or class.
|
|
||||||
For classes, this does not include ``self``.
|
|
||||||
|
|
||||||
:type: str or None
|
|
||||||
"""
|
|
||||||
return self._args
|
|
||||||
|
|
||||||
@args.setter
|
|
||||||
def args(self, value):
|
|
||||||
self._args = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def docstring(self):
|
def docstring(self):
|
||||||
"""The docstring for this object.
|
"""The docstring for this object.
|
||||||
@ -170,7 +169,11 @@ class PythonFunction(PythonPythonMapper):
|
|||||||
def __init__(self, obj, **kwargs):
|
def __init__(self, obj, **kwargs):
|
||||||
super(PythonFunction, self).__init__(obj, **kwargs)
|
super(PythonFunction, self).__init__(obj, **kwargs)
|
||||||
|
|
||||||
self.return_annotation = obj["return_annotation"]
|
autodoc_typehints = getattr(self.app.config, "autodoc_typehints", "signature")
|
||||||
|
show_annotations = autodoc_typehints not in ("none", "description")
|
||||||
|
self.args = _format_args(obj["args"], show_annotations)
|
||||||
|
|
||||||
|
self.return_annotation = obj["return_annotation"] if show_annotations else None
|
||||||
"""The type annotation for the return type of this function.
|
"""The type annotation for the return type of this function.
|
||||||
|
|
||||||
This will be ``None`` if an annotation
|
This will be ``None`` if an annotation
|
||||||
@ -185,12 +188,31 @@ class PythonFunction(PythonPythonMapper):
|
|||||||
|
|
||||||
:type: list(str)
|
:type: list(str)
|
||||||
"""
|
"""
|
||||||
self.overloads = obj["overloads"]
|
self.overloads = (
|
||||||
|
[
|
||||||
|
(_format_args(args), return_annotation)
|
||||||
|
for args, return_annotation in obj["overloads"]
|
||||||
|
]
|
||||||
|
if show_annotations
|
||||||
|
else []
|
||||||
|
)
|
||||||
"""The list of overloaded signatures ``[(args, return_annotation), ...]`` of this function.
|
"""The list of overloaded signatures ``[(args, return_annotation), ...]`` of this function.
|
||||||
|
|
||||||
:type: list(tuple(str, str))
|
:type: list(tuple(str, str))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def args(self):
|
||||||
|
"""The arguments to this object, formatted as a string.
|
||||||
|
|
||||||
|
:type: str
|
||||||
|
"""
|
||||||
|
return self._args
|
||||||
|
|
||||||
|
@args.setter
|
||||||
|
def args(self, value):
|
||||||
|
self._args = value
|
||||||
|
|
||||||
|
|
||||||
class PythonMethod(PythonFunction):
|
class PythonMethod(PythonFunction):
|
||||||
"""The representation of a method."""
|
"""The representation of a method."""
|
||||||
@ -241,7 +263,7 @@ class PythonData(PythonPythonMapper):
|
|||||||
|
|
||||||
:type: str or None
|
:type: str or None
|
||||||
"""
|
"""
|
||||||
self.annotation = obj.get("annotation", obj.get("return_annotation"))
|
self.annotation = obj.get("annotation")
|
||||||
"""The type annotation of this attribute.
|
"""The type annotation of this attribute.
|
||||||
|
|
||||||
This will be ``None`` if an annotation
|
This will be ``None`` if an annotation
|
||||||
@ -323,6 +345,8 @@ class PythonClass(PythonPythonMapper):
|
|||||||
def __init__(self, obj, **kwargs):
|
def __init__(self, obj, **kwargs):
|
||||||
super(PythonClass, self).__init__(obj, **kwargs)
|
super(PythonClass, self).__init__(obj, **kwargs)
|
||||||
|
|
||||||
|
self.args = obj["args"]
|
||||||
|
|
||||||
self.bases = obj["bases"]
|
self.bases = obj["bases"]
|
||||||
"""The fully qualified names of all base classes.
|
"""The fully qualified names of all base classes.
|
||||||
|
|
||||||
@ -331,6 +355,10 @@ class PythonClass(PythonPythonMapper):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def args(self):
|
def args(self):
|
||||||
|
"""The arguments to this object, formatted as a string.
|
||||||
|
|
||||||
|
:type: str
|
||||||
|
"""
|
||||||
args = self._args
|
args = self._args
|
||||||
|
|
||||||
constructor = self.constructor
|
constructor = self.constructor
|
||||||
|
@ -86,16 +86,14 @@ class Parser(object):
|
|||||||
if astroid_utils.is_exception(node):
|
if astroid_utils.is_exception(node):
|
||||||
type_ = "exception"
|
type_ = "exception"
|
||||||
|
|
||||||
args = ""
|
args = []
|
||||||
annotations = {}
|
|
||||||
try:
|
try:
|
||||||
constructor = node.lookup("__init__")[1]
|
constructor = node.lookup("__init__")[1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if isinstance(constructor, astroid.nodes.FunctionDef):
|
if isinstance(constructor, astroid.nodes.FunctionDef):
|
||||||
args = astroid_utils.format_args(constructor.args)
|
args = astroid_utils.get_args_info(constructor.args)
|
||||||
annotations = astroid_utils.get_annotations_dict(constructor.args)
|
|
||||||
|
|
||||||
basenames = list(astroid_utils.get_full_basenames(node))
|
basenames = list(astroid_utils.get_full_basenames(node))
|
||||||
|
|
||||||
@ -104,7 +102,6 @@ class Parser(object):
|
|||||||
"name": node.name,
|
"name": node.name,
|
||||||
"full_name": self._get_full_name(node.name),
|
"full_name": self._get_full_name(node.name),
|
||||||
"args": args,
|
"args": args,
|
||||||
"annotations": annotations,
|
|
||||||
"bases": basenames,
|
"bases": basenames,
|
||||||
"doc": astroid_utils.get_class_docstring(node),
|
"doc": astroid_utils.get_class_docstring(node),
|
||||||
"from_line_no": node.fromlineno,
|
"from_line_no": node.fromlineno,
|
||||||
@ -170,29 +167,15 @@ class Parser(object):
|
|||||||
if isinstance(node, astroid.AsyncFunctionDef):
|
if isinstance(node, astroid.AsyncFunctionDef):
|
||||||
properties.append("async")
|
properties.append("async")
|
||||||
|
|
||||||
annotations = astroid_utils.get_annotations_dict(node.args)
|
|
||||||
return_annotation = None
|
|
||||||
if node.returns:
|
|
||||||
return_annotation = astroid_utils.format_annotation(node.returns, node)
|
|
||||||
annotations["return"] = return_annotation
|
|
||||||
elif node.type_comment_returns:
|
|
||||||
return_annotation = astroid_utils.format_annotation(
|
|
||||||
node.type_comment_returns, node
|
|
||||||
)
|
|
||||||
annotations["return"] = return_annotation
|
|
||||||
|
|
||||||
arg_string = astroid_utils.format_args(node.args)
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"type": type_,
|
"type": type_,
|
||||||
"name": node.name,
|
"name": node.name,
|
||||||
"full_name": self._get_full_name(node.name),
|
"full_name": self._get_full_name(node.name),
|
||||||
"args": arg_string,
|
"args": astroid_utils.get_args_info(node.args),
|
||||||
"annotations": annotations,
|
|
||||||
"doc": astroid_utils.get_func_docstring(node),
|
"doc": astroid_utils.get_func_docstring(node),
|
||||||
"from_line_no": node.fromlineno,
|
"from_line_no": node.fromlineno,
|
||||||
"to_line_no": node.tolineno,
|
"to_line_no": node.tolineno,
|
||||||
"return_annotation": return_annotation,
|
"return_annotation": astroid_utils.get_return_annotation(node),
|
||||||
"properties": properties,
|
"properties": properties,
|
||||||
"is_overload": astroid_utils.is_decorated_with_overload(node),
|
"is_overload": astroid_utils.is_decorated_with_overload(node),
|
||||||
"overloads": [],
|
"overloads": [],
|
||||||
|
@ -100,24 +100,30 @@ you can disable AutoAPI altogether from your project.
|
|||||||
How to Include Type Annotations as Types in Rendered Docstrings
|
How to Include Type Annotations as Types in Rendered Docstrings
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
This feature is experimental and may change or be removed in future versions.
|
||||||
|
|
||||||
Since v3.0, :mod:`sphinx` has included an :mod:`sphinx.ext.autodoc.typehints`
|
Since v3.0, :mod:`sphinx` has included an :mod:`sphinx.ext.autodoc.typehints`
|
||||||
extension that is capable of rendering type annotations as
|
extension that is capable of rendering type annotations as
|
||||||
parameter types and return types.
|
parameter types and return types.
|
||||||
|
|
||||||
For example the following ReST:
|
For example the following function:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
.. py:function:: _func(a: int, b: Optional[str]) -> bool
|
def _func(a: int, b: Optional[str]) -> bool
|
||||||
|
"""My function.
|
||||||
|
|
||||||
:param a: The first arg.
|
:param a: The first arg.
|
||||||
:param b: The second arg.
|
:param b: The second arg.
|
||||||
|
|
||||||
:returns: Something.
|
:returns: Something.
|
||||||
|
"""
|
||||||
|
|
||||||
would be rendered as:
|
would be rendered as:
|
||||||
|
|
||||||
.. py:function:: _func(a: int, b: Optional[str]) -> bool
|
.. py:function:: _func(a, b)
|
||||||
:noindex:
|
:noindex:
|
||||||
|
|
||||||
:param int a: The first arg.
|
:param int a: The first arg.
|
||||||
@ -134,3 +140,12 @@ and set :confval:`autodoc_typehints` to ``description`` as normal::
|
|||||||
|
|
||||||
extensions = ['sphinx.ext.autodoc', 'autoapi.extension']
|
extensions = ['sphinx.ext.autodoc', 'autoapi.extension']
|
||||||
autodoc_typehints = 'description'
|
autodoc_typehints = 'description'
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The :mod:`sphinx.ext.autodoc.typehints` extension does not support overload functions.
|
||||||
|
Overloads will not be output when :confval:`autodoc_typehints` is set to
|
||||||
|
anything other than ``signature``.
|
||||||
|
When a documented parameter names a parameter that is specified in only an overload,
|
||||||
|
not the final function definition, the type will not be included in the description
|
||||||
|
when :confval:`autodoc_typehints` is set to ``description``.
|
||||||
|
@ -159,8 +159,10 @@ class C:
|
|||||||
class D(C):
|
class D(C):
|
||||||
class Da:
|
class Da:
|
||||||
...
|
...
|
||||||
|
|
||||||
class DB(Da):
|
class DB(Da):
|
||||||
...
|
...
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,7 +74,17 @@ class PythonParserTests(unittest.TestCase):
|
|||||||
" return True\n"
|
" return True\n"
|
||||||
)
|
)
|
||||||
data = self.parse(source)[0]
|
data = self.parse(source)[0]
|
||||||
self.assertEqual(data["args"], "self, bar, baz=42, foo=True, *args, **kwargs")
|
self.assertEqual(
|
||||||
|
data["args"],
|
||||||
|
[
|
||||||
|
(None, "self", None, None),
|
||||||
|
(None, "bar", None, None),
|
||||||
|
(None, "baz", None, "42"),
|
||||||
|
(None, "foo", None, "True"),
|
||||||
|
("*", "args", None, None),
|
||||||
|
("**", "kwargs", None, None),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_advanced_arguments(self):
|
def test_advanced_arguments(self):
|
||||||
"""Advanced argument parsing"""
|
"""Advanced argument parsing"""
|
||||||
@ -88,23 +98,21 @@ class PythonParserTests(unittest.TestCase):
|
|||||||
data = self.parse(source)[0]
|
data = self.parse(source)[0]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
data["args"],
|
data["args"],
|
||||||
", ".join(
|
|
||||||
[
|
[
|
||||||
"self",
|
(None, "self", None, None),
|
||||||
"a",
|
(None, "a", None, None),
|
||||||
"b",
|
(None, "b", None, None),
|
||||||
"c=42",
|
(None, "c", None, "42"),
|
||||||
"d='string'",
|
(None, "d", None, "'string'"),
|
||||||
"e=(1, 2)",
|
(None, "e", None, "(1, 2)"),
|
||||||
"f={'a': True}",
|
(None, "f", None, "{'a': True}"),
|
||||||
"g=None",
|
(None, "g", None, "None"),
|
||||||
"h=[1, 2, 3, 4]",
|
(None, "h", None, "[1, 2, 3, 4]"),
|
||||||
"i=dict(a=True)",
|
(None, "i", None, "dict(a=True)"),
|
||||||
"j=False",
|
(None, "j", None, "False"),
|
||||||
"*args",
|
("*", "args", None, None),
|
||||||
"**kwargs",
|
("**", "kwargs", None, None),
|
||||||
]
|
],
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_dict_key_assignment(self):
|
def test_dict_key_assignment(self):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import astroid
|
import astroid
|
||||||
from autoapi.mappers.python import astroid_utils
|
from autoapi.mappers.python import astroid_utils, objects
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@ -105,24 +105,45 @@ class TestAstroidUtils(object):
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"signature,expected",
|
"signature,expected",
|
||||||
[
|
[
|
||||||
("a: bool, b: int = 5", {"a": "bool", "b": "int"}),
|
(
|
||||||
|
"a: bool, b: int = 5",
|
||||||
|
[(None, "a", "bool", None), (None, "b", "int", "5")],
|
||||||
|
),
|
||||||
pytest.param(
|
pytest.param(
|
||||||
"a: bool, /, b: int, *, c: str",
|
"a: bool, /, b: int, *, c: str",
|
||||||
{"a": "bool", "b": "int", "c": "str"},
|
[
|
||||||
|
(None, "a", "bool", None),
|
||||||
|
("/", None, None, None),
|
||||||
|
(None, "b", "int", None),
|
||||||
|
("*", None, None, None),
|
||||||
|
(None, "c", "str", None),
|
||||||
|
],
|
||||||
marks=pytest.mark.skipif(
|
marks=pytest.mark.skipif(
|
||||||
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
|
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
pytest.param(
|
pytest.param(
|
||||||
"a: bool, /, b: int, *args, c: str, **kwargs",
|
"a: bool, /, b: int, *args, c: str, **kwargs",
|
||||||
{"a": "bool", "b": "int", "c": "str"},
|
[
|
||||||
|
(None, "a", "bool", None),
|
||||||
|
("/", None, None, None),
|
||||||
|
(None, "b", "int", None),
|
||||||
|
("*", "args", None, None),
|
||||||
|
(None, "c", "str", None),
|
||||||
|
("**", "kwargs", None, None),
|
||||||
|
],
|
||||||
marks=pytest.mark.skipif(
|
marks=pytest.mark.skipif(
|
||||||
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
|
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
pytest.param(
|
pytest.param(
|
||||||
"a: int, *args, b: str, **kwargs",
|
"a: int, *args, b: str, **kwargs",
|
||||||
{"a": "int", "b": "str"},
|
[
|
||||||
|
(None, "a", "int", None),
|
||||||
|
("*", "args", None, None),
|
||||||
|
(None, "b", "str", None),
|
||||||
|
("**", "kwargs", None, None),
|
||||||
|
],
|
||||||
marks=pytest.mark.skipif(
|
marks=pytest.mark.skipif(
|
||||||
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
|
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
|
||||||
),
|
),
|
||||||
@ -139,7 +160,7 @@ class TestAstroidUtils(object):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
annotations = astroid_utils.get_annotations_dict(node.args)
|
annotations = astroid_utils.get_args_info(node.args)
|
||||||
assert annotations == expected
|
assert annotations == expected
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -174,5 +195,6 @@ class TestAstroidUtils(object):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
formatted = astroid_utils.format_args(node.args)
|
args_info = astroid_utils.get_args_info(node.args)
|
||||||
|
formatted = objects._format_args(args_info)
|
||||||
assert formatted == expected
|
assert formatted == expected
|
||||||
|
Loading…
Reference in New Issue
Block a user