From 73482936a4eabeb3e51425f3b5c56d1d9e0a9bb9 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Mon, 24 Apr 2023 07:23:59 +0200 Subject: [PATCH] Various TryStar fixes (#2142) --- ChangeLog | 4 ++++ astroid/__init__.py | 1 + astroid/node_classes.py | 1 + astroid/nodes/__init__.py | 2 ++ astroid/nodes/as_string.py | 22 +++++++++++++++++++--- astroid/nodes/node_ng.py | 2 +- astroid/rebuilder.py | 6 ++++++ doc/api/astroid.nodes.rst | 3 +++ tests/test_group_exceptions.py | 8 ++++---- 9 files changed, 41 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3ee8ee6035..1bb8299919 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,10 @@ What's New in astroid 2.15.4? ============================= Release date: TBA +* Add visitor function for ``TryStar`` to ``AsStringVisitor`` and + add ``TryStar`` to ``astroid.nodes.ALL_NODE_CLASSES``. + + Refs #2142 What's New in astroid 2.15.3? diff --git a/astroid/__init__.py b/astroid/__init__.py index 605a8b48b2..bcb0c2c27c 100644 --- a/astroid/__init__.py +++ b/astroid/__init__.py @@ -165,6 +165,7 @@ Subscript, TryExcept, TryFinally, + TryStar, Tuple, UnaryOp, Unknown, diff --git a/astroid/node_classes.py b/astroid/node_classes.py index 9ea1e8d267..64709632c4 100644 --- a/astroid/node_classes.py +++ b/astroid/node_classes.py @@ -76,6 +76,7 @@ Subscript, TryExcept, TryFinally, + TryStar, Tuple, UnaryOp, Unknown, diff --git a/astroid/nodes/__init__.py b/astroid/nodes/__init__.py index b527ff7c3f..157aa24271 100644 --- a/astroid/nodes/__init__.py +++ b/astroid/nodes/__init__.py @@ -197,6 +197,7 @@ Subscript, TryExcept, TryFinally, + TryStar, Tuple, UnaryOp, Unknown, @@ -291,6 +292,7 @@ "Subscript", "TryExcept", "TryFinally", + "TryStar", "Tuple", "UnaryOp", "Unknown", diff --git a/astroid/nodes/as_string.py b/astroid/nodes/as_string.py index cbd5ee1757..ae55ab8bea 100644 --- a/astroid/nodes/as_string.py +++ b/astroid/nodes/as_string.py @@ -9,6 +9,8 @@ from collections.abc import Iterator from typing import TYPE_CHECKING +from astroid import nodes + if TYPE_CHECKING: from astroid.nodes import Const from astroid.nodes.node_classes import ( @@ -254,13 +256,16 @@ def visit_emptynode(self, node) -> str: return "" def visit_excepthandler(self, node) -> str: + n = "except" + if isinstance(getattr(node, "parent", None), nodes.TryStar): + n = "except*" if node.type: if node.name: - excs = f"except {node.type.accept(self)} as {node.name.accept(self)}" + excs = f"{n} {node.type.accept(self)} as {node.name.accept(self)}" else: - excs = f"except {node.type.accept(self)}" + excs = f"{n} {node.type.accept(self)}" else: - excs = "except" + excs = f"{n}" return f"{excs}:\n{self._stmt_list(node.body)}" def visit_empty(self, node) -> str: @@ -495,6 +500,17 @@ def visit_tryfinally(self, node) -> str: self._stmt_list(node.body), self._stmt_list(node.finalbody) ) + def visit_trystar(self, node) -> str: + """return an astroid.TryStar node as string""" + trys = [f"try:\n{self._stmt_list(node.body)}"] + for handler in node.handlers: + trys.append(handler.accept(self)) + if node.orelse: + trys.append(f"else:\n{self._stmt_list(node.orelse)}") + if node.finalbody: + trys.append(f"finally:\n{self._stmt_list(node.finalbody)}") + return "\n".join(trys) + def visit_tuple(self, node) -> str: """return an astroid.Tuple node as string""" if len(node.elts) == 1: diff --git a/astroid/nodes/node_ng.py b/astroid/nodes/node_ng.py index 617f8ba4eb..3f8222e230 100644 --- a/astroid/nodes/node_ng.py +++ b/astroid/nodes/node_ng.py @@ -590,7 +590,7 @@ def _get_yield_nodes_skip_lambdas(self): yield from () def _infer_name(self, frame, name): - # overridden for ImportFrom, Import, Global, TryExcept and Arguments + # overridden for ImportFrom, Import, Global, TryExcept, TryStar and Arguments pass def _infer( diff --git a/astroid/rebuilder.py b/astroid/rebuilder.py index 6e996defdc..0d409c49c7 100644 --- a/astroid/rebuilder.py +++ b/astroid/rebuilder.py @@ -507,6 +507,12 @@ def visit( ) -> nodes.TryExcept | nodes.TryFinally: ... + if sys.version_info >= (3, 11): + + @overload + def visit(self, node: ast.TryStar, parent: NodeNG) -> nodes.TryStar: + ... + @overload def visit(self, node: ast.Tuple, parent: NodeNG) -> nodes.Tuple: ... diff --git a/doc/api/astroid.nodes.rst b/doc/api/astroid.nodes.rst index 7372cdd546..3e99e93be6 100644 --- a/doc/api/astroid.nodes.rst +++ b/doc/api/astroid.nodes.rst @@ -80,6 +80,7 @@ Nodes astroid.nodes.Subscript astroid.nodes.TryExcept astroid.nodes.TryFinally + astroid.nodes.TryStar astroid.nodes.Tuple astroid.nodes.UnaryOp astroid.nodes.Unknown @@ -230,6 +231,8 @@ Nodes .. autoclass:: astroid.nodes.TryFinally +.. autoclass:: astroid.nodes.TryStar + .. autoclass:: astroid.nodes.Tuple .. autoclass:: astroid.nodes.UnaryOp diff --git a/tests/test_group_exceptions.py b/tests/test_group_exceptions.py index 173c25ed00..11065aa4dd 100644 --- a/tests/test_group_exceptions.py +++ b/tests/test_group_exceptions.py @@ -54,9 +54,8 @@ def test_group_exceptions() -> None: @pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher") def test_star_exceptions() -> None: - node = extract_node( - textwrap.dedent( - """ + code = textwrap.dedent( + """ try: raise ExceptionGroup("group", [ValueError(654)]) except* ValueError: @@ -67,9 +66,10 @@ def test_star_exceptions() -> None: sys.exit(127) finally: sys.exit(0)""" - ) ) + node = extract_node(code) assert isinstance(node, TryStar) + assert node.as_string() == code.replace('"', "'").strip() assert isinstance(node.body[0], Raise) assert node.block_range(1) == (1, 11) assert node.block_range(2) == (2, 2)