diff options
author | Ashley Whetter <ashley@awhetter.co.uk> | 2020-01-11 14:23:30 -0800 |
---|---|---|
committer | Ashley Whetter <ashley@awhetter.co.uk> | 2020-01-11 14:23:30 -0800 |
commit | 061aaebea2be2d21831ef687cc4ba4a25d953c65 (patch) | |
tree | bca65f06791bb0075b794d1f975fef0bbc2a98d7 | |
parent | 616c7cec3cb06161dba83710db7083c6bc62e116 (diff) | |
download | astroid-git-061aaebea2be2d21831ef687cc4ba4a25d953c65.tar.gz |
Can access positional only and keyword only argument type comments
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | astroid/node_classes.py | 32 | ||||
-rw-r--r-- | astroid/rebuilder.py | 10 | ||||
-rw-r--r-- | tests/unittest_nodes.py | 41 |
4 files changed, 89 insertions, 0 deletions
@@ -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( """ |