From 981760f114c4c8e658ae130bdf1797b3a3b39fd8 2023-07-10 13:45:28
From: jakkdl
Date: 2023-07-10 13:45:28
Subject: [PATCH] add tests, fix exceptiongroup dependency, add doc requirement in another place
---
diff --git a/IPython/core/tests/test_exceptiongroup_tb.py b/IPython/core/tests/test_exceptiongroup_tb.py
new file mode 100644
index 0000000..0dbd241
--- /dev/null
+++ b/IPython/core/tests/test_exceptiongroup_tb.py
@@ -0,0 +1,109 @@
+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)
diff --git a/docs/environment.yml b/docs/environment.yml
index 9fe7d4a..efc7e57 100644
--- a/docs/environment.yml
+++ b/docs/environment.yml
@@ -8,6 +8,7 @@ dependencies:
- sphinx>=4.2
- sphinx_rtd_theme
- numpy
+ - exceptiongroup
- testpath
- matplotlib
- pip
diff --git a/setup.cfg b/setup.cfg
index 319fe4f..0ec359a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -33,7 +33,7 @@ install_requires =
backcall
colorama; sys_platform == "win32"
decorator
- exceptiongroup; python_version<'3.10'
+ exceptiongroup; python_version<'3.11'
jedi>=0.16
matplotlib-inline
pexpect>4.3; sys_platform != "win32"