Skip to content

Commit c555382

Browse files
committed
Merge pull request #92 from minrk/faulthandler
patch faulthandler defaults to underlying stderr. This redirects faulthandler to a real file descriptor instead of a zmq socket, so that in the event of a hard C-level crash, traceback data can still get logged. Closes #91.
2 parents 78ca4b0 + 348a6ca commit c555382

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

ipykernel/kernelapp.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,32 @@ def init_io(self):
303303
if self.displayhook_class:
304304
displayhook_factory = import_item(str(self.displayhook_class))
305305
sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
306+
307+
self.patch_io()
308+
309+
def patch_io(self):
310+
"""Patch important libraries that can't handle sys.stdout forwarding"""
311+
try:
312+
import faulthandler
313+
except ImportError:
314+
pass
315+
else:
316+
faulthandler_enable = faulthandler.enable
317+
faulthandler_register = faulthandler.register
318+
# Warning: this is a monkeypatch of `faulthandler.enable`, watch for possible
319+
# updates to the upstream API and update accordingly (up-to-date as of Python 3.5):
320+
# https://docs.python.org/3/library/faulthandler.html#faulthandler.enable
321+
322+
# change default file to __stderr__ from forwarded stderr
323+
def enable(file=sys.__stderr__, all_threads=True, **kwargs):
324+
return faulthandler_enable(file=file, all_threads=all_threads, **kwargs)
306325

326+
def register(signum, file=sys.__stderr__, all_threads=True, chain=False, **kwargs):
327+
return faulthandler_register(signum, file=file, all_threads=all_threads, chain=chain, **kwargs)
328+
329+
faulthandler.enable = enable
330+
faulthandler.register = register
331+
307332
def init_signal(self):
308333
signal.signal(signal.SIGINT, signal.SIG_IGN)
309334

ipykernel/tests/test_kernel.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,20 @@ def test_save_history():
189189
nt.assert_in(u'a=1', content)
190190
nt.assert_in(u'b=u"abcþ"', content)
191191

192+
193+
@dec.skip_without('faulthandler')
194+
def test_smoke_faulthandler():
195+
with kernel() as kc:
196+
code = u'\n'.join([
197+
'import faulthandler, signal',
198+
'faulthandler.enable()',
199+
'faulthandler.register(signal.SIGTERM)',
200+
])
201+
_, reply = execute(code, kc=kc)
202+
print(_)
203+
nt.assert_equal(reply['status'], 'ok', reply.get('traceback', ''))
204+
205+
192206
def test_help_output():
193207
"""ipython kernel --help-all works"""
194208
tt.help_all_output_test('kernel')

0 commit comments

Comments
 (0)