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) |
@@ -1,19 +1,20 b'' | |||
|
1 | 1 | name: ipython_docs |
|
2 | 2 | channels: |
|
3 | 3 | - conda-forge |
|
4 | 4 | - defaults |
|
5 | 5 | dependencies: |
|
6 | 6 | - python=3.10 |
|
7 | 7 | - setuptools |
|
8 | 8 | - sphinx>=4.2 |
|
9 | 9 | - sphinx_rtd_theme |
|
10 | 10 | - numpy |
|
11 | - exceptiongroup | |
|
11 | 12 | - testpath |
|
12 | 13 | - matplotlib |
|
13 | 14 | - pip |
|
14 | 15 | - pip: |
|
15 | 16 | - docrepr |
|
16 | 17 | - prompt_toolkit |
|
17 | 18 | - ipykernel |
|
18 | 19 | - stack_data |
|
19 | 20 | - -e .. |
@@ -1,118 +1,118 b'' | |||
|
1 | 1 | [metadata] |
|
2 | 2 | name = ipython |
|
3 | 3 | version = attr: IPython.core.release.__version__ |
|
4 | 4 | url = https://ipython.org |
|
5 | 5 | description = IPython: Productive Interactive Computing |
|
6 | 6 | long_description_content_type = text/x-rst |
|
7 | 7 | long_description = file: long_description.rst |
|
8 | 8 | license_file = LICENSE |
|
9 | 9 | project_urls = |
|
10 | 10 | Documentation = https://ipython.readthedocs.io/ |
|
11 | 11 | Funding = https://numfocus.org/ |
|
12 | 12 | Source = https://github.com/ipython/ipython |
|
13 | 13 | Tracker = https://github.com/ipython/ipython/issues |
|
14 | 14 | keywords = Interactive, Interpreter, Shell, Embedding |
|
15 | 15 | platforms = Linux, Mac OSX, Windows |
|
16 | 16 | classifiers = |
|
17 | 17 | Framework :: IPython |
|
18 | 18 | Framework :: Jupyter |
|
19 | 19 | Intended Audience :: Developers |
|
20 | 20 | Intended Audience :: Science/Research |
|
21 | 21 | License :: OSI Approved :: BSD License |
|
22 | 22 | Programming Language :: Python |
|
23 | 23 | Programming Language :: Python :: 3 |
|
24 | 24 | Programming Language :: Python :: 3 :: Only |
|
25 | 25 | Topic :: System :: Shells |
|
26 | 26 | |
|
27 | 27 | [options] |
|
28 | 28 | packages = find: |
|
29 | 29 | python_requires = >=3.9 |
|
30 | 30 | zip_safe = False |
|
31 | 31 | install_requires = |
|
32 | 32 | appnope; sys_platform == "darwin" |
|
33 | 33 | backcall |
|
34 | 34 | colorama; sys_platform == "win32" |
|
35 | 35 | decorator |
|
36 |
exceptiongroup; python_version<'3.1 |
|
|
36 | exceptiongroup; python_version<'3.11' | |
|
37 | 37 | jedi>=0.16 |
|
38 | 38 | matplotlib-inline |
|
39 | 39 | pexpect>4.3; sys_platform != "win32" |
|
40 | 40 | pickleshare |
|
41 | 41 | prompt_toolkit>=3.0.30,<3.1.0,!=3.0.37 |
|
42 | 42 | pygments>=2.4.0 |
|
43 | 43 | stack_data |
|
44 | 44 | traitlets>=5 |
|
45 | 45 | typing_extensions ; python_version<'3.10' |
|
46 | 46 | |
|
47 | 47 | [options.extras_require] |
|
48 | 48 | black = |
|
49 | 49 | black |
|
50 | 50 | doc = |
|
51 | 51 | ipykernel |
|
52 | 52 | setuptools>=18.5 |
|
53 | 53 | sphinx>=1.3 |
|
54 | 54 | sphinx-rtd-theme |
|
55 | 55 | docrepr |
|
56 | 56 | matplotlib |
|
57 | 57 | stack_data |
|
58 | 58 | pytest<7 |
|
59 | 59 | typing_extensions |
|
60 | 60 | exceptiongroup |
|
61 | 61 | %(test)s |
|
62 | 62 | kernel = |
|
63 | 63 | ipykernel |
|
64 | 64 | nbconvert = |
|
65 | 65 | nbconvert |
|
66 | 66 | nbformat = |
|
67 | 67 | nbformat |
|
68 | 68 | notebook = |
|
69 | 69 | ipywidgets |
|
70 | 70 | notebook |
|
71 | 71 | parallel = |
|
72 | 72 | ipyparallel |
|
73 | 73 | qtconsole = |
|
74 | 74 | qtconsole |
|
75 | 75 | terminal = |
|
76 | 76 | test = |
|
77 | 77 | pytest<7.1 |
|
78 | 78 | pytest-asyncio |
|
79 | 79 | testpath |
|
80 | 80 | test_extra = |
|
81 | 81 | %(test)s |
|
82 | 82 | curio |
|
83 | 83 | matplotlib!=3.2.0 |
|
84 | 84 | nbformat |
|
85 | 85 | numpy>=1.21 |
|
86 | 86 | pandas |
|
87 | 87 | trio |
|
88 | 88 | all = |
|
89 | 89 | %(black)s |
|
90 | 90 | %(doc)s |
|
91 | 91 | %(kernel)s |
|
92 | 92 | %(nbconvert)s |
|
93 | 93 | %(nbformat)s |
|
94 | 94 | %(notebook)s |
|
95 | 95 | %(parallel)s |
|
96 | 96 | %(qtconsole)s |
|
97 | 97 | %(terminal)s |
|
98 | 98 | %(test_extra)s |
|
99 | 99 | %(test)s |
|
100 | 100 | |
|
101 | 101 | [options.packages.find] |
|
102 | 102 | exclude = |
|
103 | 103 | setupext |
|
104 | 104 | |
|
105 | 105 | [options.package_data] |
|
106 | 106 | IPython = py.typed |
|
107 | 107 | IPython.core = profile/README* |
|
108 | 108 | IPython.core.tests = *.png, *.jpg, daft_extension/*.py |
|
109 | 109 | IPython.lib.tests = *.wav |
|
110 | 110 | IPython.testing.plugin = *.txt |
|
111 | 111 | |
|
112 | 112 | [velin] |
|
113 | 113 | ignore_patterns = |
|
114 | 114 | IPython/core/tests |
|
115 | 115 | IPython/testing |
|
116 | 116 | |
|
117 | 117 | [tool.black] |
|
118 | 118 | exclude = 'timing\.py' |
General Comments 0
You need to be logged in to leave comments.
Login now