From 1d918edebb8540263ffae5670a48a74a6b495ed6 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sat, 11 Oct 2025 17:51:36 +0200 Subject: [PATCH 1/2] Add helper to iterate over all annotation nodes of Arguments --- ChangeLog | 5 +++++ astroid/nodes/node_classes.py | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/ChangeLog b/ChangeLog index 4bdede78f..c63654b40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,11 @@ Release date: TBA Closes #2741 Closes pylint-dev/pylint#6094 +* Add helper to iterate over all annotations nodes of function arguments, + ``Arguments.get_annotations()``. + + Refs #2860 + What's New in astroid 4.0.2? ============================ diff --git a/astroid/nodes/node_classes.py b/astroid/nodes/node_classes.py index 5da788790..1d16b747a 100644 --- a/astroid/nodes/node_classes.py +++ b/astroid/nodes/node_classes.py @@ -1020,6 +1020,23 @@ def get_children(self): if elt is not None: yield elt + def get_annotations(self) -> Iterator[nodes.NodeNG]: + """Iterate over all annotations nodes.""" + for elt in self.posonlyargs_annotations: + if elt is not None: + yield elt + for elt in self.annotations: + if elt is not None: + yield elt + if self.varargannotation is not None: + yield self.varargannotation + + for elt in self.kwonlyargs_annotations: + if elt is not None: + yield elt + if self.kwargannotation is not None: + yield self.kwargannotation + @decorators.raise_if_nothing_inferred def _infer( self: nodes.Arguments, context: InferenceContext | None = None, **kwargs: Any From 4ba76f11da4a2d04d32bfcedc35cad4fef049ad1 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sat, 11 Oct 2025 18:14:14 +0200 Subject: [PATCH 2/2] Add test case --- tests/test_nodes.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_nodes.py b/tests/test_nodes.py index 8d2f4d546..939c58158 100644 --- a/tests/test_nodes.py +++ b/tests/test_nodes.py @@ -2314,6 +2314,19 @@ def test_arguments_default_value(): assert node.args.default_value("flavor").value == "good" +def test_arguments_annotations(): + node = extract_node( + "def fruit(eat: str, /, peel: bool, *args: int, trim: float, **kwargs: bytes): ..." + ) + assert isinstance(node.args, nodes.Arguments) + annotation_names = [ + ann.name for ann in node.args.get_annotations() if isinstance(ann, nodes.Name) + ] + assert all( + name in annotation_names for name in ("str", "bool", "int", "float", "bytes") + ) + + def test_deprecated_nodes_import_from_toplevel(): # pylint: disable=import-outside-toplevel,no-name-in-module with pytest.raises(