# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt import textwrap import pytest from astroid import ( AssignName, ExceptHandler, For, Name, TryExcept, Uninferable, bases, extract_node, ) from astroid.const import PY311_PLUS from astroid.context import InferenceContext from astroid.nodes import Expr, Raise, TryStar @pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher") def test_group_exceptions() -> None: node = extract_node( textwrap.dedent( """ try: raise ExceptionGroup("group", [ValueError(654)]) except ExceptionGroup as eg: for err in eg.exceptions: if isinstance(err, ValueError): print("Handling ValueError") elif isinstance(err, TypeError): print("Handling TypeError")""" ) ) assert isinstance(node, TryExcept) handler = node.handlers[0] exception_group_block_range = (1, 4) assert node.block_range(lineno=1) == exception_group_block_range assert node.block_range(lineno=2) == (2, 2) assert node.block_range(lineno=5) == (5, 9) assert isinstance(handler, ExceptHandler) assert handler.type.name == "ExceptionGroup" children = list(handler.get_children()) assert len(children) == 3 exception_group, short_name, for_loop = children assert isinstance(exception_group, Name) assert exception_group.block_range(1) == exception_group_block_range assert isinstance(short_name, AssignName) assert isinstance(for_loop, For) @pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher") def test_star_exceptions() -> None: code = textwrap.dedent( """ try: raise ExceptionGroup("group", [ValueError(654)]) except* ValueError: print("Handling ValueError") except* TypeError: print("Handling TypeError") else: 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) assert node.block_range(3) == (3, 3) assert node.block_range(4) == (4, 4) assert node.block_range(5) == (5, 5) assert node.block_range(6) == (6, 6) assert node.block_range(7) == (7, 7) assert node.block_range(8) == (8, 8) assert node.block_range(9) == (9, 9) assert node.block_range(10) == (10, 10) assert node.block_range(11) == (11, 11) assert node.handlers handler = node.handlers[0] assert isinstance(handler, ExceptHandler) assert handler.type.name == "ValueError" orelse = node.orelse[0] assert isinstance(orelse, Expr) assert orelse.value.args[0].value == 127 final = node.finalbody[0] assert isinstance(final, Expr) assert final.value.args[0].value == 0 @pytest.mark.skipif(not PY311_PLUS, reason="Requires Python 3.11 or higher") def test_star_exceptions_infer_name() -> None: trystar = extract_node( """ try: 1/0 except* ValueError: pass""" ) name = "arbitraryName" context = InferenceContext() context.lookupname = name stmts = bases._infer_stmts([trystar], context) assert list(stmts) == [Uninferable] assert context.lookupname == name