cutter/src/python/cutter_jupyter.py

125 lines
3.6 KiB
Python
Raw Normal View History

2018-02-23 15:24:19 +00:00
import signal
import time
from jupyter_client.ioloop import IOLoopKernelManager
2018-02-09 15:48:02 +00:00
from notebook.notebookapp import *
2018-02-23 12:04:53 +00:00
import cutter_internal
class IPyKernelInterfaceJupyter:
2018-02-22 21:08:06 +00:00
def __init__(self, id):
self._id = id
2018-02-23 12:04:53 +00:00
def send_signal(self, signum):
2018-02-23 15:24:19 +00:00
print("sending signal " + str(signum) + " to kernel")
2018-02-23 12:04:53 +00:00
cutter_internal.kernel_interface_send_signal(self._id, signum)
2018-02-22 21:08:06 +00:00
def kill(self):
2018-02-23 12:04:53 +00:00
self.send_signal(signal.SIGKILL)
def terminate(self):
self.send_signal(signal.SIGTERM)
2018-02-22 21:08:06 +00:00
def poll(self):
2018-02-23 12:04:53 +00:00
return cutter_internal.kernel_interface_poll(self._id)
def wait(self, timeout=None):
2018-02-23 15:24:19 +00:00
if timeout is not None:
start_time = time.process_time()
else:
start_time = None
while timeout is None or time.process_time() - start_time < timeout:
if self.poll() is not None:
return
time.sleep(0.1)
2018-02-23 12:04:53 +00:00
pass
class CutterInternalIPyKernelManager(IOLoopKernelManager):
def start_kernel(self, **kw):
self.write_connection_file()
self._launch_args = kw.copy()
2018-02-23 15:24:19 +00:00
extra_arguments = kw.pop('extra_arguments', [])
kernel_cmd = self.format_kernel_cmd(extra_arguments=extra_arguments)
env = kw.pop('env', os.environ).copy()
# Don't allow PYTHONEXECUTABLE to be passed to kernel process.
# If set, it can bork all the things.
env.pop('PYTHONEXECUTABLE', None)
if not self.kernel_cmd:
# If kernel_cmd has been set manually, don't refer to a kernel spec
# Environment variables from kernel spec are added to os.environ
env.update(self.kernel_spec.env or {})
# launch the kernel subprocess
2018-02-22 21:08:06 +00:00
id = cutter_internal.launch_ipykernel(kernel_cmd, env=env, **kw)
self.kernel = IPyKernelInterfaceJupyter(id)
2018-02-23 12:04:53 +00:00
# self._launch_kernel(kernel_cmd, env=env, **kw)
self.start_restarter()
self._connect_control_socket()
2018-02-23 12:04:53 +00:00
def signal_kernel(self, signum):
self.kernel.send_signal(signum)
def kernel_manager_factory(kernel_name, **kwargs):
if kernel_name in {"python", "python2", "python3"}:
return CutterInternalIPyKernelManager(kernel_name=kernel_name, **kwargs)
else:
return IOLoopKernelManager(kernel_name=kernel_name, **kwargs)
2018-02-09 15:48:02 +00:00
class CutterNotebookApp(NotebookApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.thread = None
def start(self):
""" see NotebookApp.start() """
self.kernel_manager.kernel_manager_factory = kernel_manager_factory
2018-02-09 15:48:02 +00:00
super(NotebookApp, self).start()
self.write_server_info_file()
self.thread = threading.Thread(target=self.run)
2018-02-09 15:48:02 +00:00
self.thread.start()
def run(self):
self.io_loop = ioloop.IOLoop.current()
if sys.platform.startswith('win'):
# add no-op to wake every 5s
# to handle signals that may be ignored by the inner loop
pc = ioloop.PeriodicCallback(lambda: None, 5000)
pc.start()
try:
self.io_loop.start()
except KeyboardInterrupt:
self.log.info(_("Interrupted..."))
finally:
self.remove_server_info_file()
self.cleanup_kernels()
def stop(self):
super().stop()
self.thread.join()
@property
def url_with_token(self):
return url_concat(self.connection_url, {'token': self.token})
def start_jupyter():
app = CutterNotebookApp()
app.initialize()
app.start()
return app
if __name__ == "__main__":
app = start_jupyter()
print("Started " + app.url_with_token)