Skip to content

Commit bf204c4

Browse files
authored
Merge pull request #2702 from jakkdl/ipython_exceptiongroup_support
Remove special handling due to IPython lacking support for exception groups
2 parents 4ea1e6d + 51db601 commit bf204c4

7 files changed

Lines changed: 5 additions & 198 deletions

File tree

newsfragments/2702.removal.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Removed special ``MultiError`` traceback handling for IPython. As of `version 8.15 <https://ipython.readthedocs.io/en/stable/whatsnew/version8.html#ipython-8-15>`_ `ExceptionGroup` is handled natively.

test-requirements.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ pytest >= 5.0 # for faulthandler in core
33
coverage >= 7.2.5
44
async_generator >= 1.9
55
pyright
6-
ipython # for the IPython traceback integration tests
76
pyOpenSSL >= 22.0.0 # for the ssl + DTLS tests
87
trustme # for the ssl + DTLS tests
98
pylint # for pylint finding all symbols tests

test-requirements.txt

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,12 @@ astor==0.8.1
88
# via -r test-requirements.in
99
astroid==2.15.6
1010
# via pylint
11-
asttokens==2.2.1
12-
# via stack-data
1311
async-generator==1.10
1412
# via -r test-requirements.in
1513
attrs==23.1.0
1614
# via
1715
# -r test-requirements.in
1816
# outcome
19-
backcall==0.2.0
20-
# via ipython
2117
black==23.7.0 ; implementation_name == "cpython"
2218
# via -r test-requirements.in
2319
build==0.10.0
@@ -38,16 +34,12 @@ cryptography==41.0.3
3834
# pyopenssl
3935
# trustme
4036
# types-pyopenssl
41-
decorator==5.1.1
42-
# via ipython
4337
dill==0.3.7
4438
# via pylint
4539
exceptiongroup==1.1.3 ; python_version < "3.11"
4640
# via
4741
# -r test-requirements.in
4842
# pytest
49-
executing==1.2.0
50-
# via stack-data
5143
flake8==6.1.0
5244
# via
5345
# -r test-requirements.in
@@ -60,18 +52,12 @@ idna==3.4
6052
# trustme
6153
iniconfig==2.0.0
6254
# via pytest
63-
ipython==8.12.2
64-
# via -r test-requirements.in
6555
isort==5.12.0
6656
# via pylint
6757
jedi==0.19.0
68-
# via
69-
# -r test-requirements.in
70-
# ipython
58+
# via -r test-requirements.in
7159
lazy-object-proxy==1.9.0
7260
# via astroid
73-
matplotlib-inline==0.1.6
74-
# via ipython
7561
mccabe==0.7.0
7662
# via
7763
# flake8
@@ -96,10 +82,6 @@ parso==0.8.3
9682
# via jedi
9783
pathspec==0.11.2
9884
# via black
99-
pexpect==4.8.0
100-
# via ipython
101-
pickleshare==0.7.5
102-
# via ipython
10385
pip-tools==7.3.0
10486
# via -r test-requirements.in
10587
platformdirs==3.10.0
@@ -108,20 +90,12 @@ platformdirs==3.10.0
10890
# pylint
10991
pluggy==1.3.0
11092
# via pytest
111-
prompt-toolkit==3.0.39
112-
# via ipython
113-
ptyprocess==0.7.0
114-
# via pexpect
115-
pure-eval==0.2.2
116-
# via stack-data
11793
pycodestyle==2.11.0
11894
# via flake8
11995
pycparser==2.21
12096
# via cffi
12197
pyflakes==3.1.0
12298
# via flake8
123-
pygments==2.16.1
124-
# via ipython
12599
pylint==2.17.5
126100
# via -r test-requirements.in
127101
pyopenssl==23.2.0
@@ -132,14 +106,10 @@ pyright==1.1.325
132106
# via -r test-requirements.in
133107
pytest==7.4.0
134108
# via -r test-requirements.in
135-
six==1.16.0
136-
# via asttokens
137109
sniffio==1.3.0
138110
# via -r test-requirements.in
139111
sortedcontainers==2.4.0
140112
# via -r test-requirements.in
141-
stack-data==0.6.2
142-
# via ipython
143113
tomli==2.0.1
144114
# via
145115
# black
@@ -152,10 +122,6 @@ tomli==2.0.1
152122
# pytest
153123
tomlkit==0.12.1
154124
# via pylint
155-
traitlets==5.9.0
156-
# via
157-
# ipython
158-
# matplotlib-inline
159125
trustme==1.1.0
160126
# via -r test-requirements.in
161127
types-pyopenssl==23.2.0.2 ; implementation_name == "cpython"
@@ -165,11 +131,8 @@ typing-extensions==4.7.1
165131
# -r test-requirements.in
166132
# astroid
167133
# black
168-
# ipython
169134
# mypy
170135
# pylint
171-
wcwidth==0.2.6
172-
# via prompt-toolkit
173136
wheel==0.41.2
174137
# via pip-tools
175138
wrapt==1.15.0

trio/_core/_multierror.py

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import sys
4-
import warnings
54
from collections.abc import Callable, Sequence
65
from types import TracebackType
76
from typing import TYPE_CHECKING, Any, cast, overload
@@ -11,9 +10,7 @@
1110
from trio._deprecate import warn_deprecated
1211

1312
if sys.version_info < (3, 11):
14-
from exceptiongroup import BaseExceptionGroup, ExceptionGroup, print_exception
15-
else:
16-
from traceback import print_exception
13+
from exceptiongroup import BaseExceptionGroup, ExceptionGroup
1714

1815
if TYPE_CHECKING:
1916
from typing_extensions import Self
@@ -461,37 +458,6 @@ def concat_tb(
461458
return current_head
462459

463460

464-
# Remove when IPython gains support for exception groups
465-
# (https://github.com/ipython/ipython/issues/13753)
466-
if "IPython" in sys.modules:
467-
import IPython
468-
469-
ip = IPython.get_ipython()
470-
if ip is not None:
471-
if ip.custom_exceptions != ():
472-
warnings.warn(
473-
"IPython detected, but you already have a custom exception "
474-
"handler installed. I'll skip installing Trio's custom "
475-
"handler, but this means exception groups will not show full "
476-
"tracebacks.",
477-
category=RuntimeWarning,
478-
)
479-
else:
480-
481-
def trio_show_traceback(
482-
self: IPython.core.interactiveshell.InteractiveShell,
483-
etype: type[BaseException],
484-
value: BaseException,
485-
tb: TracebackType,
486-
tb_offset: int | None = None,
487-
) -> None:
488-
# XX it would be better to integrate with IPython's fancy
489-
# exception formatting stuff (and not ignore tb_offset)
490-
print_exception(value)
491-
492-
ip.set_custom_exc((BaseExceptionGroup,), trio_show_traceback)
493-
494-
495461
# Ubuntu's system Python has a sitecustomize.py file that import
496462
# apport_python_hook and replaces sys.excepthook.
497463
#

trio/_core/_tests/test_multierror.py

Lines changed: 2 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ def test_non_base_multierror():
430430
assert isinstance(exc, ExceptionGroup)
431431

432432

433-
def run_script(name, use_ipython=False):
433+
def run_script(name: str) -> subprocess.CompletedProcess[bytes]:
434434
import trio
435435

436436
trio_path = Path(trio.__file__).parent.parent
@@ -447,24 +447,7 @@ def run_script(name, use_ipython=False):
447447
env["PYTHONPATH"] = os.pathsep.join(pp)
448448
print("subprocess PYTHONPATH:", env.get("PYTHONPATH"))
449449

450-
if use_ipython:
451-
lines = [
452-
"import runpy",
453-
f"runpy.run_path(r'{script_path}', run_name='trio.fake')",
454-
"exit()",
455-
]
456-
457-
cmd = [
458-
sys.executable,
459-
"-u",
460-
"-m",
461-
"IPython",
462-
# no startup files
463-
"--quick",
464-
"--TerminalIPythonApp.code_to_run=" + "\n".join(lines),
465-
]
466-
else:
467-
cmd = [sys.executable, "-u", str(script_path)]
450+
cmd = [sys.executable, "-u", str(script_path)]
468451
print("running:", cmd)
469452
completed = subprocess.run(
470453
cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
@@ -474,69 +457,6 @@ def run_script(name, use_ipython=False):
474457
return completed
475458

476459

477-
def check_simple_excepthook(completed):
478-
assert_match_in_seq(
479-
[
480-
"in <module>",
481-
"MultiError",
482-
"--- 1 ---",
483-
"in exc1_fn",
484-
"ValueError",
485-
"--- 2 ---",
486-
"in exc2_fn",
487-
"KeyError",
488-
],
489-
completed.stdout.decode("utf-8"),
490-
)
491-
492-
493-
try:
494-
import IPython # noqa: F401
495-
except ImportError: # pragma: no cover
496-
have_ipython = False
497-
else:
498-
have_ipython = True
499-
500-
need_ipython = pytest.mark.skipif(not have_ipython, reason="need IPython")
501-
502-
503-
@slow
504-
@need_ipython
505-
def test_ipython_exc_handler():
506-
completed = run_script("simple_excepthook.py", use_ipython=True)
507-
check_simple_excepthook(completed)
508-
509-
510-
@slow
511-
@need_ipython
512-
def test_ipython_imported_but_unused():
513-
completed = run_script("simple_excepthook_IPython.py")
514-
check_simple_excepthook(completed)
515-
516-
517-
@slow
518-
@need_ipython
519-
def test_ipython_custom_exc_handler():
520-
# Check we get a nice warning (but only one!) if the user is using IPython
521-
# and already has some other set_custom_exc handler installed.
522-
completed = run_script("ipython_custom_exc.py", use_ipython=True)
523-
assert_match_in_seq(
524-
[
525-
# The warning
526-
"RuntimeWarning",
527-
"IPython detected",
528-
"skip installing Trio",
529-
# The MultiError
530-
"MultiError",
531-
"ValueError",
532-
"KeyError",
533-
],
534-
completed.stdout.decode("utf-8"),
535-
)
536-
# Make sure our other warning doesn't show up
537-
assert "custom sys.excepthook" not in completed.stdout.decode("utf-8")
538-
539-
540460
@slow
541461
@pytest.mark.skipif(
542462
not Path("/usr/lib/python3/dist-packages/apport_python_hook.py").exists(),

trio/_core/_tests/test_multierror_scripts/ipython_custom_exc.py

Lines changed: 0 additions & 36 deletions
This file was deleted.

trio/_core/_tests/test_multierror_scripts/simple_excepthook_IPython.py

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)