Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove special handling due to IPython lacking support for exception groups #2702

Merged
merged 6 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion test-requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
39 changes: 1 addition & 38 deletions test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -38,16 +34,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
Expand All @@ -60,18 +52,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
Expand All @@ -96,10 +82,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
Expand All @@ -108,20 +90,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
Expand All @@ -132,14 +106,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
Expand All @@ -152,10 +122,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"
Expand All @@ -165,11 +131,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
Expand Down
36 changes: 1 addition & 35 deletions trio/_core/_multierror.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -11,9 +10,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
Expand Down Expand Up @@ -461,37 +458,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.
#
Expand Down
84 changes: 2 additions & 82 deletions trio/_core/_tests/test_multierror.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -474,69 +457,6 @@ def run_script(name, use_ipython=False):
return completed


def check_simple_excepthook(completed):
assert_match_in_seq(
[
"in <module>",
"MultiError",
"--- 1 ---",
"in exc1_fn",
"ValueError",
"--- 2 ---",
"in exc2_fn",
"KeyError",
],
completed.stdout.decode("utf-8"),
)


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(),
Expand Down
36 changes: 0 additions & 36 deletions trio/_core/_tests/test_multierror_scripts/ipython_custom_exc.py

This file was deleted.

This file was deleted.