File: test_exceptiongroup_tb.py

package info (click to toggle)
ipython 8.35.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,696 kB
  • sloc: python: 42,461; sh: 376; makefile: 243
file content (112 lines) | stat: -rw-r--r-- 3,599 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import unittest
import re
from IPython.utils.capture import capture_output
import sys
import pytest
from tempfile import TemporaryDirectory
from IPython.testing import tools as tt


def _exceptiongroup_common(
    outer_chain: str,
    inner_chain: str,
    native: bool,
) -> None:
    pre_raise = "exceptiongroup." if not native else ""
    pre_catch = pre_raise if sys.version_info < (3, 11) else ""
    filestr = f"""
    {"import exceptiongroup" if not native else ""}
    import pytest

    def f(): raise ValueError("From f()")
    def g(): raise BaseException("From g()")

    def inner(inner_chain):
        excs = []
        for callback in [f, g]:
            try:
                callback()
            except BaseException as err:
                excs.append(err)
        if excs:
            if inner_chain == "none":
                raise {pre_raise}BaseExceptionGroup("Oops", excs)
            try:
                raise SyntaxError()
            except SyntaxError as e:
                if inner_chain == "from":
                    raise {pre_raise}BaseExceptionGroup("Oops", excs) from e
                else:
                    raise {pre_raise}BaseExceptionGroup("Oops", excs)

    def outer(outer_chain, inner_chain):
        try:
            inner(inner_chain)
        except {pre_catch}BaseExceptionGroup as e:
            if outer_chain == "none":
                raise
            if outer_chain == "from":
                raise IndexError() from e
            else:
                raise IndexError


    outer("{outer_chain}", "{inner_chain}")
    """
    with capture_output() as cap:
        ip.run_cell(filestr)

    match_lines = []
    if inner_chain == "another":
        match_lines += [
            "During handling of the above exception, another exception occurred:",
        ]
    elif inner_chain == "from":
        match_lines += [
            "The above exception was the direct cause of the following exception:",
        ]

    match_lines += [
        "  + Exception Group Traceback (most recent call last):",
        f"  | {pre_catch}BaseExceptionGroup: Oops (2 sub-exceptions)",
        "    | ValueError: From f()",
        "    | BaseException: From g()",
    ]

    if outer_chain == "another":
        match_lines += [
            "During handling of the above exception, another exception occurred:",
            "IndexError",
        ]
    elif outer_chain == "from":
        match_lines += [
            "The above exception was the direct cause of the following exception:",
            "IndexError",
        ]

    error_lines = cap.stderr.split("\n")

    err_index = match_index = 0
    for expected in match_lines:
        for i, actual in enumerate(error_lines):
            if actual == expected:
                error_lines = error_lines[i + 1 :]
                break
        else:
            assert False, f"{expected} not found in cap.stderr"


@pytest.mark.skipif(
    sys.version_info < (3, 11), reason="Native ExceptionGroup not implemented"
)
@pytest.mark.parametrize("outer_chain", ["none", "from", "another"])
@pytest.mark.parametrize("inner_chain", ["none", "from", "another"])
def test_native_exceptiongroup(outer_chain, inner_chain) -> None:
    _exceptiongroup_common(outer_chain, inner_chain, native=True)


@pytest.mark.parametrize("outer_chain", ["none", "from", "another"])
@pytest.mark.parametrize("inner_chain", ["none", "from", "another"])
def test_native_exceptiongroup(outer_chain, inner_chain) -> None:
    pytest.importorskip("exceptiongroup")
    _exceptiongroup_common(outer_chain, inner_chain, native=False)