@ -20,10 +20,13 @@ Authors:
import errno
import logging
import os
import re
import select
import signal
import socket
import sys
import threading
import time
import webbrowser
# Third party
@ -449,11 +452,73 @@ class NotebookApp(BaseIPythonApplication):
self . port = port
break
def init_signal ( self ) :
# FIXME: remove this check when pyzmq dependency is >= 2.1.11
# safely extract zmq version info:
try :
zmq_v = zmq . pyzmq_version_info ( )
except AttributeError :
zmq_v = [ int ( n ) for n in re . findall ( r ' \ d+ ' , zmq . __version__ ) ]
if ' dev ' in zmq . __version__ :
zmq_v . append ( 999 )
zmq_v = tuple ( zmq_v )
if zmq_v > = ( 2 , 1 , 9 ) :
# This won't work with 2.1.7 and
# 2.1.9-10 will log ugly 'Interrupted system call' messages,
# but it will work
signal . signal ( signal . SIGINT , self . _handle_sigint )
signal . signal ( signal . SIGTERM , self . _signal_stop )
def _handle_sigint ( self , sig , frame ) :
""" SIGINT handler spawns confirmation dialog """
# register more forceful signal handler for ^C^C case
signal . signal ( signal . SIGINT , self . _signal_stop )
# request confirmation dialog in bg thread, to avoid
# blocking the App
thread = threading . Thread ( target = self . _confirm_exit )
thread . daemon = True
thread . start ( )
def _restore_sigint_handler ( self ) :
""" callback for restoring original SIGINT handler """
signal . signal ( signal . SIGINT , self . _handle_sigint )
def _confirm_exit ( self ) :
""" confirm shutdown on ^C
A second ^ C , or answering ' y ' within 5 s will cause shutdown ,
otherwise original SIGINT handler will be restored .
"""
# FIXME: remove this delay when pyzmq dependency is >= 2.1.11
time . sleep ( 0.1 )
sys . stdout . write ( " Shutdown Notebook Server (y/[n])? " )
sys . stdout . flush ( )
r , w , x = select . select ( [ sys . stdin ] , [ ] , [ ] , 5 )
if r :
line = sys . stdin . readline ( )
if line . lower ( ) . startswith ( ' y ' ) :
self . log . critical ( " Shutdown confirmed " )
ioloop . IOLoop . instance ( ) . stop ( )
return
else :
print " No answer for 5s: " ,
print " resuming operation... "
# no answer, or answer is no:
# set it back to original SIGINT handler
# use IOLoop.add_callback because signal.signal must be called
# from main thread
ioloop . IOLoop . instance ( ) . add_callback ( self . _restore_sigint_handler )
def _signal_stop ( self , sig , frame ) :
self . log . critical ( " received signal %s , stopping " , sig )
ioloop . IOLoop . instance ( ) . stop ( )
@catch_config_error
def initialize ( self , argv = None ) :
super ( NotebookApp , self ) . initialize ( argv )
self . init_configurables ( )
self . init_webapp ( )
self . init_signal ( )
def cleanup_kernels ( self ) :
""" shutdown all kernels