Skip to content

Commit

Permalink
Patch sys.unraisablehook to format exception groups
Browse files Browse the repository at this point in the history
Fixes #18.
  • Loading branch information
agronholm committed Aug 18, 2022
1 parent d8a89ae commit 2aaa1cb
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ Version history

This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.

**UNRELEASED**

- Patch ``sys.unraisablehook`` to properly format exceptiongroups

**1.0.0rc8**

- Don't monkey patch anything if ``sys.excepthook`` has been altered
Expand Down
15 changes: 15 additions & 0 deletions src/exceptiongroup/_formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,17 @@ def exceptiongroup_excepthook(
sys.stderr.write("".join(traceback.format_exception(etype, value, tb)))


def exceptiongroup_unraisablehook(__unraisable: sys.UnraisableHookArgs) -> None:
err_msg = __unraisable.err_msg or "Exception ignored in"
formatted_tb = "".join(traceback.format_tb(__unraisable.exc_traceback))
formatted_tb += "".join(
traceback.format_exception(
__unraisable.exc_type, __unraisable.exc_value, __unraisable.exc_traceback
)
)
sys.stderr.write(f"{err_msg}: {__unraisable.object!r}\n{formatted_tb}")


if sys.excepthook is sys.__excepthook__:
traceback_exception_original_init = traceback.TracebackException.__init__
traceback.TracebackException.__init__ = ( # type: ignore[assignment]
Expand All @@ -271,3 +282,7 @@ def exceptiongroup_excepthook(
traceback.TracebackException, "_format_syntax_error", None
)
sys.excepthook = exceptiongroup_excepthook

# Patch sys.unraisablehook if it's untouched
if sys.version_info >= (3, 8) and sys.unraisablehook is sys.__unraisablehook__:
sys.unraisablehook = exceptiongroup_unraisablehook
37 changes: 37 additions & 0 deletions tests/test_formatting.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import gc
import sys

import pytest

from exceptiongroup import ExceptionGroup
from exceptiongroup._formatting import exceptiongroup_unraisablehook


def test_formatting(capsys):
Expand Down Expand Up @@ -119,3 +123,36 @@ def test_formatting_syntax_error(capsys):
SyntaxError: invalid syntax
"""
)


@pytest.mark.skipif(
sys.version_info < (3, 8), reason="sys.unraisablehook was added in Python 3.8"
)
def test_unraisablehook(capsys, monkeypatch):
# Pytest overrides sys.unraisablehook so we temporarily override that here
monkeypatch.setattr(sys, "unraisablehook", exceptiongroup_unraisablehook)

class Foo:
def __del__(self):
raise ExceptionGroup("the bad", [Exception("critical debug information")])

Foo()
gc.collect()

lineno = Foo.__del__.__code__.co_firstlineno
module_prefix = "" if sys.version_info >= (3, 11) else "exceptiongroup."
output = capsys.readouterr().err
assert output == (
f"""\
Exception ignored in: {Foo.__del__!r}
File "{__file__}", line {lineno + 1}, in __del__
raise ExceptionGroup("the bad", [Exception("critical debug information")])
+ Exception Group Traceback (most recent call last):
| File "{__file__}", line {lineno + 1}, in __del__
| raise ExceptionGroup("the bad", [Exception("critical debug information")])
| {module_prefix}ExceptionGroup: the bad (1 sub-exception)
+-+---------------- 1 ----------------
| Exception: critical debug information
+------------------------------------
"""
)

0 comments on commit 2aaa1cb

Please sign in to comment.