From 761ec2a762b2a68996b9baf954b761eaa42d0395 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Thu, 13 Jul 2023 14:22:43 +0200
Subject: [PATCH 1/6] Remove special handling due to IPython lacking support
for exception groups
---
trio/_core/_multierror.py | 35 +----------------------------------
1 file changed, 1 insertion(+), 34 deletions(-)
diff --git a/trio/_core/_multierror.py b/trio/_core/_multierror.py
index d55e89554..9b8e40fa6 100644
--- a/trio/_core/_multierror.py
+++ b/trio/_core/_multierror.py
@@ -11,9 +11,7 @@
from trio._deprecate import warn_deprecated
if sys.version_info < (3, 11):
- from exceptiongroup import BaseExceptionGroup, ExceptionGroup, print_exception
-else:
- from traceback import print_exception
+ from exceptiongroup import BaseExceptionGroup, ExceptionGroup
if TYPE_CHECKING:
from typing_extensions import Self
@@ -461,37 +459,6 @@ def concat_tb(
return current_head
-# Remove when IPython gains support for exception groups
-# (https://github.com/ipython/ipython/issues/13753)
-if "IPython" in sys.modules:
- import IPython
-
- ip = IPython.get_ipython()
- if ip is not None:
- if ip.custom_exceptions != ():
- warnings.warn(
- "IPython detected, but you already have a custom exception "
- "handler installed. I'll skip installing Trio's custom "
- "handler, but this means exception groups will not show full "
- "tracebacks.",
- category=RuntimeWarning,
- )
- else:
-
- def trio_show_traceback(
- self: IPython.core.interactiveshell.InteractiveShell,
- etype: type[BaseException],
- value: BaseException,
- tb: TracebackType,
- tb_offset: int | None = None,
- ) -> None:
- # XX it would be better to integrate with IPython's fancy
- # exception formatting stuff (and not ignore tb_offset)
- print_exception(value)
-
- ip.set_custom_exc((BaseExceptionGroup,), trio_show_traceback)
-
-
# Ubuntu's system Python has a sitecustomize.py file that import
# apport_python_hook and replaces sys.excepthook.
#
From 25dacf3c55a597a1d92a1de8ac4749c68f833a3a Mon Sep 17 00:00:00 2001
From: Spencer Brown
Date: Tue, 5 Sep 2023 12:25:26 +1000
Subject: [PATCH 2/6] Remove unused import
---
trio/_core/_multierror.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/trio/_core/_multierror.py b/trio/_core/_multierror.py
index 9b8e40fa6..45d725f2c 100644
--- a/trio/_core/_multierror.py
+++ b/trio/_core/_multierror.py
@@ -1,7 +1,6 @@
from __future__ import annotations
import sys
-import warnings
from collections.abc import Callable, Sequence
from types import TracebackType
from typing import TYPE_CHECKING, Any, cast, overload
From 31b58c939b63bf074dca12e6ab509161cb653059 Mon Sep 17 00:00:00 2001
From: Spencer Brown
Date: Tue, 5 Sep 2023 12:58:54 +1000
Subject: [PATCH 3/6] Remove IPython-related exception group traceback tests
---
test-requirements.in | 1 -
test-requirements.txt | 45 ++----------
trio/_core/_tests/test_multierror.py | 68 +------------------
.../ipython_custom_exc.py | 36 ----------
.../simple_excepthook_IPython.py | 6 --
5 files changed, 9 insertions(+), 147 deletions(-)
delete mode 100644 trio/_core/_tests/test_multierror_scripts/ipython_custom_exc.py
delete mode 100644 trio/_core/_tests/test_multierror_scripts/simple_excepthook_IPython.py
diff --git a/test-requirements.in b/test-requirements.in
index 1911b1bf1..7461a1e4e 100644
--- a/test-requirements.in
+++ b/test-requirements.in
@@ -3,7 +3,6 @@ pytest >= 5.0 # for faulthandler in core
coverage >= 7.2.5
async_generator >= 1.9
pyright
-ipython # for the IPython traceback integration tests
pyOpenSSL >= 22.0.0 # for the ssl + DTLS tests
trustme # for the ssl + DTLS tests
pylint # for pylint finding all symbols tests
diff --git a/test-requirements.txt b/test-requirements.txt
index 86a8f14ae..aad46dc9f 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -8,16 +8,12 @@ astor==0.8.1
# via -r test-requirements.in
astroid==2.15.6
# via pylint
-asttokens==2.2.1
- # via stack-data
async-generator==1.10
# via -r test-requirements.in
attrs==23.1.0
# via
# -r test-requirements.in
# outcome
-backcall==0.2.0
- # via ipython
black==23.7.0 ; implementation_name == "cpython"
# via -r test-requirements.in
build==0.10.0
@@ -30,6 +26,12 @@ click==8.1.7
# pip-tools
codespell==2.2.5
# via -r test-requirements.in
+colorama==0.4.6
+ # via
+ # build
+ # click
+ # pylint
+ # pytest
coverage==7.3.0
# via -r test-requirements.in
cryptography==41.0.3
@@ -38,16 +40,12 @@ cryptography==41.0.3
# pyopenssl
# trustme
# types-pyopenssl
-decorator==5.1.1
- # via ipython
dill==0.3.7
# via pylint
exceptiongroup==1.1.3 ; python_version < "3.11"
# via
# -r test-requirements.in
# pytest
-executing==1.2.0
- # via stack-data
flake8==6.1.0
# via
# -r test-requirements.in
@@ -60,18 +58,12 @@ idna==3.4
# trustme
iniconfig==2.0.0
# via pytest
-ipython==8.12.2
- # via -r test-requirements.in
isort==5.12.0
# via pylint
jedi==0.19.0
- # via
- # -r test-requirements.in
- # ipython
+ # via -r test-requirements.in
lazy-object-proxy==1.9.0
# via astroid
-matplotlib-inline==0.1.6
- # via ipython
mccabe==0.7.0
# via
# flake8
@@ -96,10 +88,6 @@ parso==0.8.3
# via jedi
pathspec==0.11.2
# via black
-pexpect==4.8.0
- # via ipython
-pickleshare==0.7.5
- # via ipython
pip-tools==7.3.0
# via -r test-requirements.in
platformdirs==3.10.0
@@ -108,20 +96,12 @@ platformdirs==3.10.0
# pylint
pluggy==1.3.0
# via pytest
-prompt-toolkit==3.0.39
- # via ipython
-ptyprocess==0.7.0
- # via pexpect
-pure-eval==0.2.2
- # via stack-data
pycodestyle==2.11.0
# via flake8
pycparser==2.21
# via cffi
pyflakes==3.1.0
# via flake8
-pygments==2.16.1
- # via ipython
pylint==2.17.5
# via -r test-requirements.in
pyopenssl==23.2.0
@@ -132,14 +112,10 @@ pyright==1.1.325
# via -r test-requirements.in
pytest==7.4.0
# via -r test-requirements.in
-six==1.16.0
- # via asttokens
sniffio==1.3.0
# via -r test-requirements.in
sortedcontainers==2.4.0
# via -r test-requirements.in
-stack-data==0.6.2
- # via ipython
tomli==2.0.1
# via
# black
@@ -152,10 +128,6 @@ tomli==2.0.1
# pytest
tomlkit==0.12.1
# via pylint
-traitlets==5.9.0
- # via
- # ipython
- # matplotlib-inline
trustme==1.1.0
# via -r test-requirements.in
types-pyopenssl==23.2.0.2 ; implementation_name == "cpython"
@@ -165,11 +137,8 @@ typing-extensions==4.7.1
# -r test-requirements.in
# astroid
# black
- # ipython
# mypy
# pylint
-wcwidth==0.2.6
- # via prompt-toolkit
wheel==0.41.2
# via pip-tools
wrapt==1.15.0
diff --git a/trio/_core/_tests/test_multierror.py b/trio/_core/_tests/test_multierror.py
index 6990a7b75..6122e637c 100644
--- a/trio/_core/_tests/test_multierror.py
+++ b/trio/_core/_tests/test_multierror.py
@@ -430,7 +430,7 @@ def test_non_base_multierror():
assert isinstance(exc, ExceptionGroup)
-def run_script(name, use_ipython=False):
+def run_script(name: str) -> subprocess.CompletedProcess[bytes]:
import trio
trio_path = Path(trio.__file__).parent.parent
@@ -447,24 +447,7 @@ def run_script(name, use_ipython=False):
env["PYTHONPATH"] = os.pathsep.join(pp)
print("subprocess PYTHONPATH:", env.get("PYTHONPATH"))
- if use_ipython:
- lines = [
- "import runpy",
- f"runpy.run_path(r'{script_path}', run_name='trio.fake')",
- "exit()",
- ]
-
- cmd = [
- sys.executable,
- "-u",
- "-m",
- "IPython",
- # no startup files
- "--quick",
- "--TerminalIPythonApp.code_to_run=" + "\n".join(lines),
- ]
- else:
- cmd = [sys.executable, "-u", str(script_path)]
+ cmd = [sys.executable, "-u", str(script_path)]
print("running:", cmd)
completed = subprocess.run(
cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
@@ -490,53 +473,6 @@ def check_simple_excepthook(completed):
)
-try:
- import IPython # noqa: F401
-except ImportError: # pragma: no cover
- have_ipython = False
-else:
- have_ipython = True
-
-need_ipython = pytest.mark.skipif(not have_ipython, reason="need IPython")
-
-
-@slow
-@need_ipython
-def test_ipython_exc_handler():
- completed = run_script("simple_excepthook.py", use_ipython=True)
- check_simple_excepthook(completed)
-
-
-@slow
-@need_ipython
-def test_ipython_imported_but_unused():
- completed = run_script("simple_excepthook_IPython.py")
- check_simple_excepthook(completed)
-
-
-@slow
-@need_ipython
-def test_ipython_custom_exc_handler():
- # Check we get a nice warning (but only one!) if the user is using IPython
- # and already has some other set_custom_exc handler installed.
- completed = run_script("ipython_custom_exc.py", use_ipython=True)
- assert_match_in_seq(
- [
- # The warning
- "RuntimeWarning",
- "IPython detected",
- "skip installing Trio",
- # The MultiError
- "MultiError",
- "ValueError",
- "KeyError",
- ],
- completed.stdout.decode("utf-8"),
- )
- # Make sure our other warning doesn't show up
- assert "custom sys.excepthook" not in completed.stdout.decode("utf-8")
-
-
@slow
@pytest.mark.skipif(
not Path("/usr/lib/python3/dist-packages/apport_python_hook.py").exists(),
diff --git a/trio/_core/_tests/test_multierror_scripts/ipython_custom_exc.py b/trio/_core/_tests/test_multierror_scripts/ipython_custom_exc.py
deleted file mode 100644
index 7ccb341dc..000000000
--- a/trio/_core/_tests/test_multierror_scripts/ipython_custom_exc.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Override the regular excepthook too -- it doesn't change anything either way
-# because ipython doesn't use it, but we want to make sure Trio doesn't warn
-# about it.
-import sys
-
-import _common # isort: split
-
-
-def custom_excepthook(*args):
- print("custom running!")
- return sys.__excepthook__(*args)
-
-
-sys.excepthook = custom_excepthook
-
-import IPython
-
-ip = IPython.get_ipython()
-
-
-# Set this to some random nonsense
-class SomeError(Exception):
- pass
-
-
-def custom_exc_hook(etype, value, tb, tb_offset=None):
- ip.showtraceback()
-
-
-ip.set_custom_exc((SomeError,), custom_exc_hook)
-
-from trio._core._multierror import MultiError # Bypass deprecation warnings.
-
-# The custom excepthook should run, because Trio was polite and didn't
-# override it
-raise MultiError([ValueError(), KeyError()])
diff --git a/trio/_core/_tests/test_multierror_scripts/simple_excepthook_IPython.py b/trio/_core/_tests/test_multierror_scripts/simple_excepthook_IPython.py
deleted file mode 100644
index 51a88c96c..000000000
--- a/trio/_core/_tests/test_multierror_scripts/simple_excepthook_IPython.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import _common
-
-# To tickle the "is IPython loaded?" logic, make sure that Trio tolerates
-# IPython loaded but not actually in use
-import IPython
-import simple_excepthook
From ff069157b778a0a5557f7d133e71423e1e06fe00 Mon Sep 17 00:00:00 2001
From: Spencer Brown
Date: Tue, 5 Sep 2023 13:11:08 +1000
Subject: [PATCH 4/6] colorama is Windows-only.
---
test-requirements.txt | 6 ------
1 file changed, 6 deletions(-)
diff --git a/test-requirements.txt b/test-requirements.txt
index aad46dc9f..2c86c7439 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -26,12 +26,6 @@ click==8.1.7
# pip-tools
codespell==2.2.5
# via -r test-requirements.in
-colorama==0.4.6
- # via
- # build
- # click
- # pylint
- # pytest
coverage==7.3.0
# via -r test-requirements.in
cryptography==41.0.3
From ded143149042be2453a6e613a73886c7e201ea24 Mon Sep 17 00:00:00 2001
From: Spencer Brown
Date: Tue, 5 Sep 2023 16:07:22 +1000
Subject: [PATCH 5/6] Remove unused helper function
---
trio/_core/_tests/test_multierror.py | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/trio/_core/_tests/test_multierror.py b/trio/_core/_tests/test_multierror.py
index 6122e637c..6d9fd2a56 100644
--- a/trio/_core/_tests/test_multierror.py
+++ b/trio/_core/_tests/test_multierror.py
@@ -457,22 +457,6 @@ def run_script(name: str) -> subprocess.CompletedProcess[bytes]:
return completed
-def check_simple_excepthook(completed):
- assert_match_in_seq(
- [
- "in ",
- "MultiError",
- "--- 1 ---",
- "in exc1_fn",
- "ValueError",
- "--- 2 ---",
- "in exc2_fn",
- "KeyError",
- ],
- completed.stdout.decode("utf-8"),
- )
-
-
@slow
@pytest.mark.skipif(
not Path("/usr/lib/python3/dist-packages/apport_python_hook.py").exists(),
From 51db60114ef40d9e65a05c79c63e50f27e6de968 Mon Sep 17 00:00:00 2001
From: Spencer Brown
Date: Tue, 5 Sep 2023 20:15:06 +1000
Subject: [PATCH 6/6] Add changelog entry
---
newsfragments/2702.removal.rst | 1 +
1 file changed, 1 insertion(+)
create mode 100644 newsfragments/2702.removal.rst
diff --git a/newsfragments/2702.removal.rst b/newsfragments/2702.removal.rst
new file mode 100644
index 000000000..900da0449
--- /dev/null
+++ b/newsfragments/2702.removal.rst
@@ -0,0 +1 @@
+Removed special ``MultiError`` traceback handling for IPython. As of `version 8.15 `_ `ExceptionGroup` is handled natively.