Skip to content

bpo-1230540: Invoke custom sys.excepthook for threads in threading #8610

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
23 changes: 23 additions & 0 deletions Lib/test/test_threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,29 @@ def run(self):
# explicitly break the reference cycle to not leak a dangling thread
thread.exc = None

def test_excepthook(self):
script = r"""if True:
import sys
import threading

def f():
raise Exception()

def hook(*args):
# print('thread: %r' % (threading.current_thread(),))
print('custom hook: %r' % (args,))

sys.excepthook = hook

threading.Thread(target=f).start()
"""
rc, out, err = assert_python_ok("-c", script)
decoded_out = out.decode()
decoded_err = err.decode()
self.assertNotIn("Traceback", decoded_err)
self.assertIn("custom hook", decoded_out)


class TimerTests(BaseTestCase):

def setUp(self):
Expand Down
36 changes: 19 additions & 17 deletions Lib/threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,19 +918,21 @@ def _bootstrap_inner(self):
except SystemExit:
pass
except:
# If sys.stderr is no more (most likely from interpreter
# shutdown) use self._stderr. Otherwise still use sys (as in
# _sys) in case sys.stderr was redefined since the creation of
# self.
if _sys and _sys.stderr is not None:
print("Exception in thread %s:\n%s" %
(self.name, _format_exc()), file=_sys.stderr)
elif self._stderr is not None:
# Do the best job possible w/o a huge amt. of code to
# approximate a traceback (code ideas from
# Lib/traceback.py)
exc_type, exc_value, exc_tb = self._exc_info()
try:
exc_type, exc_value, exc_tb = self._exc_info()
try:
if _sys and _sys.excepthook != _sys.__excepthook__:
_sys.excepthook(exc_type, exc_value, exc_tb)
# If sys.stderr is no more (most likely from interpreter
# shutdown) use self._stderr. Otherwise still use sys (as in
# _sys) in case sys.stderr was redefined since the creation of
# self.
elif _sys and _sys.stderr is not None:
print("Exception in thread %s:\n%s" %
(self.name, _format_exc()), file=_sys.stderr)
elif self._stderr is not None:
# Do the best job possible w/o a huge amt. of code to
# approximate a traceback (code ideas from
# Lib/traceback.py)
print((
"Exception in thread " + self.name +
" (most likely raised during interpreter shutdown):"), file=self._stderr)
Expand All @@ -945,10 +947,10 @@ def _bootstrap_inner(self):
exc_tb = exc_tb.tb_next
print(("%s: %s" % (exc_type, exc_value)), file=self._stderr)
self._stderr.flush()
# Make sure that exc_tb gets deleted since it is a memory
# hog; deleting everything else is just for thoroughness
finally:
del exc_type, exc_value, exc_tb
# Make sure that exc_tb gets deleted since it is a memory
# hog; deleting everything else is just for thoroughness
finally:
del exc_type, exc_value, exc_tb
finally:
# Prevent a race in
# test_threading.test_no_refcycle_through_target when
Expand Down