kernelapp.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import os
  2. import signal
  3. import uuid
  4. from jupyter_core.application import JupyterApp, base_flags
  5. from tornado.ioloop import IOLoop
  6. from traitlets import Unicode
  7. from . import __version__
  8. from .kernelspec import KernelSpecManager, NATIVE_KERNEL_NAME
  9. from .manager import KernelManager
  10. class KernelApp(JupyterApp):
  11. """Launch a kernel by name in a local subprocess.
  12. """
  13. version = __version__
  14. description = "Run a kernel locally in a subprocess"
  15. classes = [KernelManager, KernelSpecManager]
  16. aliases = {
  17. 'kernel': 'KernelApp.kernel_name',
  18. 'ip': 'KernelManager.ip',
  19. }
  20. flags = {'debug': base_flags['debug']}
  21. kernel_name = Unicode(NATIVE_KERNEL_NAME,
  22. help = 'The name of a kernel type to start'
  23. ).tag(config=True)
  24. def initialize(self, argv=None):
  25. super(KernelApp, self).initialize(argv)
  26. self.km = KernelManager(kernel_name=self.kernel_name,
  27. config=self.config)
  28. cf_basename = 'kernel-%s.json' % uuid.uuid4()
  29. self.km.connection_file = os.path.join(self.runtime_dir, cf_basename)
  30. self.loop = IOLoop.current()
  31. self.loop.add_callback(self._record_started)
  32. def setup_signals(self):
  33. """Shutdown on SIGTERM or SIGINT (Ctrl-C)"""
  34. if os.name == 'nt':
  35. return
  36. def shutdown_handler(signo, frame):
  37. self.loop.add_callback_from_signal(self.shutdown, signo)
  38. for sig in [signal.SIGTERM, signal.SIGINT]:
  39. signal.signal(sig, shutdown_handler)
  40. def shutdown(self, signo):
  41. self.log.info('Shutting down on signal %d' % signo)
  42. self.km.shutdown_kernel()
  43. self.loop.stop()
  44. def log_connection_info(self):
  45. cf = self.km.connection_file
  46. self.log.info('Connection file: %s', cf)
  47. self.log.info("To connect a client: --existing %s", os.path.basename(cf))
  48. def _record_started(self):
  49. """For tests, create a file to indicate that we've started
  50. Do not rely on this except in our own tests!
  51. """
  52. fn = os.environ.get('JUPYTER_CLIENT_TEST_RECORD_STARTUP_PRIVATE')
  53. if fn is not None:
  54. with open(fn, 'wb'):
  55. pass
  56. def start(self):
  57. self.log.info('Starting kernel %r', self.kernel_name)
  58. try:
  59. self.km.start_kernel()
  60. self.log_connection_info()
  61. self.setup_signals()
  62. self.loop.start()
  63. finally:
  64. self.km.cleanup()
  65. main = KernelApp.launch_instance