Show More
@@ -0,0 +1,109 b'' | |||||
|
1 | import unittest | |||
|
2 | import re | |||
|
3 | from IPython.utils.capture import capture_output | |||
|
4 | import sys | |||
|
5 | import pytest | |||
|
6 | from tempfile import TemporaryDirectory | |||
|
7 | from IPython.testing import tools as tt | |||
|
8 | ||||
|
9 | def _exceptiongroup_common( | |||
|
10 | outer_chain: str, | |||
|
11 | inner_chain: str, | |||
|
12 | native: bool, | |||
|
13 | ) -> None: | |||
|
14 | pre_raise = "exceptiongroup." if not native else "" | |||
|
15 | pre_catch = pre_raise if sys.version_info < (3, 11) else "" | |||
|
16 | filestr = f""" | |||
|
17 | {"import exceptiongroup" if not native else ""} | |||
|
18 | import pytest | |||
|
19 | ||||
|
20 | def f(): raise ValueError("From f()") | |||
|
21 | def g(): raise BaseException("From g()") | |||
|
22 | ||||
|
23 | def inner(inner_chain): | |||
|
24 | excs = [] | |||
|
25 | for callback in [f, g]: | |||
|
26 | try: | |||
|
27 | callback() | |||
|
28 | except BaseException as err: | |||
|
29 | excs.append(err) | |||
|
30 | if excs: | |||
|
31 | if inner_chain == "none": | |||
|
32 | raise {pre_raise}BaseExceptionGroup("Oops", excs) | |||
|
33 | try: | |||
|
34 | raise SyntaxError() | |||
|
35 | except SyntaxError as e: | |||
|
36 | if inner_chain == "from": | |||
|
37 | raise {pre_raise}BaseExceptionGroup("Oops", excs) from e | |||
|
38 | else: | |||
|
39 | raise {pre_raise}BaseExceptionGroup("Oops", excs) | |||
|
40 | ||||
|
41 | def outer(outer_chain, inner_chain): | |||
|
42 | try: | |||
|
43 | inner(inner_chain) | |||
|
44 | except {pre_catch}BaseExceptionGroup as e: | |||
|
45 | if outer_chain == "none": | |||
|
46 | raise | |||
|
47 | if outer_chain == "from": | |||
|
48 | raise IndexError() from e | |||
|
49 | else: | |||
|
50 | raise IndexError | |||
|
51 | ||||
|
52 | ||||
|
53 | outer("{outer_chain}", "{inner_chain}") | |||
|
54 | """ | |||
|
55 | with capture_output() as cap: | |||
|
56 | ip.run_cell(filestr) | |||
|
57 | ||||
|
58 | match_lines = [] | |||
|
59 | if inner_chain == "another": | |||
|
60 | match_lines += [ | |||
|
61 | "During handling of the above exception, another exception occurred:", | |||
|
62 | ] | |||
|
63 | elif inner_chain == 'from': | |||
|
64 | match_lines += [ | |||
|
65 | "The above exception was the direct cause of the following exception:", | |||
|
66 | ] | |||
|
67 | ||||
|
68 | match_lines += [ | |||
|
69 | " + Exception Group Traceback (most recent call last):", | |||
|
70 | f" | {pre_catch}BaseExceptionGroup: Oops (2 sub-exceptions)", | |||
|
71 | " | ValueError: From f()", | |||
|
72 | " | BaseException: From g()", | |||
|
73 | ] | |||
|
74 | ||||
|
75 | if outer_chain == "another": | |||
|
76 | match_lines += [ | |||
|
77 | "During handling of the above exception, another exception occurred:", | |||
|
78 | "IndexError", | |||
|
79 | ] | |||
|
80 | elif outer_chain == "from": | |||
|
81 | match_lines += [ | |||
|
82 | "The above exception was the direct cause of the following exception:", | |||
|
83 | "IndexError", | |||
|
84 | ] | |||
|
85 | ||||
|
86 | error_lines = cap.stderr.split("\n") | |||
|
87 | ||||
|
88 | err_index = match_index = 0 | |||
|
89 | for expected in match_lines: | |||
|
90 | for i,actual in enumerate(error_lines): | |||
|
91 | if actual == expected: | |||
|
92 | error_lines = error_lines[i+1:] | |||
|
93 | break | |||
|
94 | else: | |||
|
95 | assert False, f'{expected} not found in cap.stderr' | |||
|
96 | ||||
|
97 | @pytest.mark.skipif( | |||
|
98 | sys.version_info < (3, 11), reason="Native ExceptionGroup not implemented" | |||
|
99 | ) | |||
|
100 | @pytest.mark.parametrize("outer_chain", ["none", "from", "another"]) | |||
|
101 | @pytest.mark.parametrize("inner_chain", ["none", "from", "another"]) | |||
|
102 | def test_native_exceptiongroup(outer_chain, inner_chain) -> None: | |||
|
103 | _exceptiongroup_common(outer_chain, inner_chain, native=True) | |||
|
104 | ||||
|
105 | @pytest.mark.parametrize("outer_chain", ["none", "from", "another"]) | |||
|
106 | @pytest.mark.parametrize("inner_chain", ["none", "from", "another"]) | |||
|
107 | def test_native_exceptiongroup(outer_chain, inner_chain) -> None: | |||
|
108 | pytest.importorskip("exceptiongroup") | |||
|
109 | _exceptiongroup_common(outer_chain, inner_chain, native=False) |
@@ -8,6 +8,7 b' dependencies:' | |||||
8 | - sphinx>=4.2 |
|
8 | - sphinx>=4.2 | |
9 | - sphinx_rtd_theme |
|
9 | - sphinx_rtd_theme | |
10 | - numpy |
|
10 | - numpy | |
|
11 | - exceptiongroup | |||
11 | - testpath |
|
12 | - testpath | |
12 | - matplotlib |
|
13 | - matplotlib | |
13 | - pip |
|
14 | - pip |
@@ -33,7 +33,7 b' install_requires =' | |||||
33 | backcall |
|
33 | backcall | |
34 | colorama; sys_platform == "win32" |
|
34 | colorama; sys_platform == "win32" | |
35 | decorator |
|
35 | decorator | |
36 |
exceptiongroup; python_version<'3.1 |
|
36 | exceptiongroup; python_version<'3.11' | |
37 | jedi>=0.16 |
|
37 | jedi>=0.16 | |
38 | matplotlib-inline |
|
38 | matplotlib-inline | |
39 | pexpect>4.3; sys_platform != "win32" |
|
39 | pexpect>4.3; sys_platform != "win32" |
General Comments 0
You need to be logged in to leave comments.
Login now