summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAshley Whetter <ashley@awhetter.co.uk>2020-01-11 14:23:30 -0800
committerAshley Whetter <ashley@awhetter.co.uk>2020-01-11 14:23:30 -0800
commit061aaebea2be2d21831ef687cc4ba4a25d953c65 (patch)
treebca65f06791bb0075b794d1f975fef0bbc2a98d7
parent616c7cec3cb06161dba83710db7083c6bc62e116 (diff)
downloadastroid-git-061aaebea2be2d21831ef687cc4ba4a25d953c65.tar.gz
Can access positional only and keyword only argument type comments
-rw-r--r--ChangeLog6
-rw-r--r--astroid/node_classes.py32
-rw-r--r--astroid/rebuilder.py10
-rw-r--r--tests/unittest_nodes.py41
4 files changed, 89 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index c54d321a..3949fe26 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -106,6 +106,12 @@ Release Date: TBA
Close PyCQA/pylint#3274
+* Can access per argument type comments for positional only and keyword only arguments.
+
+ The comments are accessed through through the new
+ ``Arguments.type_comment_posonlyargs`` and
+ ``Arguments.type_comment_kwonlyargs`` attributes respectively.
+
What's New in astroid 2.3.2?
============================
Release Date: TBA
diff --git a/astroid/node_classes.py b/astroid/node_classes.py
index b1344723..c57f5686 100644
--- a/astroid/node_classes.py
+++ b/astroid/node_classes.py
@@ -1407,6 +1407,8 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
"kwargannotation",
"kwonlyargs_annotations",
"type_comment_args",
+ "type_comment_kwonlyargs",
+ "type_comment_posonlyargs",
)
varargannotation = None
"""The type annotation for the variable length arguments.
@@ -1502,6 +1504,24 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
:type: list(NodeNG or None)
"""
+ self.type_comment_kwonlyargs = []
+ """The type annotation, passed by a type comment, of each keyword only argument.
+
+ If an argument does not have a type comment,
+ the value for that argument will be None.
+
+ :type: list(NodeNG or None)
+ """
+
+ self.type_comment_posonlyargs = []
+ """The type annotation, passed by a type comment, of each positional argument.
+
+ If an argument does not have a type comment,
+ the value for that argument will be None.
+
+ :type: list(NodeNG or None)
+ """
+
# pylint: disable=too-many-arguments
def postinit(
self,
@@ -1516,6 +1536,8 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
varargannotation=None,
kwargannotation=None,
type_comment_args=None,
+ type_comment_kwonlyargs=None,
+ type_comment_posonlyargs=None,
):
"""Do some setup after initialisation.
@@ -1563,6 +1585,14 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
:param type_comment_args: The type annotation,
passed by a type comment, of each argument.
:type type_comment_args: list(NodeNG or None)
+
+ :param type_comment_args: The type annotation,
+ passed by a type comment, of each keyword only argument.
+ :type type_comment_args: list(NodeNG or None)
+
+ :param type_comment_args: The type annotation,
+ passed by a type comment, of each positional argument.
+ :type type_comment_args: list(NodeNG or None)
"""
self.args = args
self.defaults = defaults
@@ -1575,6 +1605,8 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
self.varargannotation = varargannotation
self.kwargannotation = kwargannotation
self.type_comment_args = type_comment_args
+ self.type_comment_kwonlyargs = type_comment_kwonlyargs
+ self.type_comment_posonlyargs = type_comment_posonlyargs
# pylint: disable=too-many-arguments
diff --git a/astroid/rebuilder.py b/astroid/rebuilder.py
index 10fd5900..6cb36f67 100644
--- a/astroid/rebuilder.py
+++ b/astroid/rebuilder.py
@@ -221,6 +221,14 @@ class TreeRebuilder:
type_comment_args = [
self.check_type_comment(child, parent=newnode) for child in node.args
]
+ type_comment_kwonlyargs = [
+ self.check_type_comment(child, parent=newnode) for child in node.kwonlyargs
+ ]
+ if PY38:
+ type_comment_posonlyargs = [
+ self.check_type_comment(child, parent=newnode)
+ for child in node.posonlyargs
+ ]
newnode.postinit(
args=args,
@@ -234,6 +242,8 @@ class TreeRebuilder:
varargannotation=varargannotation,
kwargannotation=kwargannotation,
type_comment_args=type_comment_args,
+ type_comment_kwonlyargs=type_comment_kwonlyargs,
+ type_comment_posonlyargs=type_comment_posonlyargs,
)
# save argument names in locals:
if vararg:
diff --git a/tests/unittest_nodes.py b/tests/unittest_nodes.py
index 5fbef628..78c8cfb2 100644
--- a/tests/unittest_nodes.py
+++ b/tests/unittest_nodes.py
@@ -1131,6 +1131,47 @@ def test_type_comments_arguments():
assert actual_arg.as_string() == expected_arg
+@pytest.mark.skipif(
+ not PY38, reason="needs to be able to parse positional only arguments"
+)
+def test_type_comments_posonly_arguments():
+ module = builder.parse(
+ """
+ def f_arg_comment(
+ a, # type: int
+ b, # type: int
+ /,
+ c, # type: Optional[int]
+ d, # type: Optional[int]
+ *,
+ e, # type: float
+ f, # type: float
+ ):
+ # type: (...) -> None
+ pass
+ """
+ )
+ expected_annotations = [
+ [["int", "int"], ["Optional[int]", "Optional[int]"], ["float", "float"]]
+ ]
+ for node, expected_types in zip(module.body, expected_annotations):
+ assert len(node.type_comment_args) == 1
+ if PY38:
+ assert isinstance(node.type_comment_args[0], astroid.Const)
+ assert node.type_comment_args[0].value == Ellipsis
+ else:
+ assert isinstance(node.type_comment_args[0], astroid.Ellipsis)
+ type_comments = [
+ node.args.type_comment_posonlyargs,
+ node.args.type_comment_args,
+ node.args.type_comment_kwonlyargs,
+ ]
+ for expected_args, actual_args in zip(expected_types, type_comments):
+ assert len(expected_args) == len(actual_args)
+ for expected_arg, actual_arg in zip(expected_args, actual_args):
+ assert actual_arg.as_string() == expected_arg
+
+
def test_is_generator_for_yield_assignments():
node = astroid.extract_node(
"""