|
@@
-1,3
+1,9
b''
|
|
|
|
|
1
|
"""A tornado based IPython notebook server."""
|
|
|
|
|
2
|
|
|
|
|
|
3
|
#-----------------------------------------------------------------------------
|
|
|
|
|
4
|
# Imports
|
|
|
|
|
5
|
#-----------------------------------------------------------------------------
|
|
|
|
|
6
|
|
|
1
|
import logging
|
|
7
|
import logging
|
|
2
|
import os
|
|
8
|
import os
|
|
3
|
|
|
9
|
|
|
@@
-14,22
+20,30
b' from tornado import options'
|
|
14
|
from tornado import web
|
|
20
|
from tornado import web
|
|
15
|
|
|
21
|
|
|
16
|
from kernelmanager import KernelManager
|
|
22
|
from kernelmanager import KernelManager
|
|
|
|
|
23
|
from sessionmanager import SessionManager
|
|
17
|
from handlers import (
|
|
24
|
from handlers import (
|
|
18
|
MainHandler, KernelHandler, KernelActionHandler, ZMQStreamHandler,
|
|
25
|
MainHandler, KernelHandler, KernelActionHandler, ZMQStreamHandler,
|
|
19
|
NotebookRootHandler, NotebookHandler
|
|
26
|
NotebookRootHandler, NotebookHandler
|
|
20
|
)
|
|
27
|
)
|
|
21
|
from routers import IOPubStreamRouter, ShellStreamRouter
|
|
28
|
from routers import IOPubStreamRouter, ShellStreamRouter
|
|
22
|
|
|
29
|
|
|
23
|
options.define("port", default=8888, help="run on the given port", type=int)
|
|
30
|
from IPython.core.application import BaseIPythonApplication
|
|
|
|
|
31
|
from IPython.zmq.session import Session
|
|
|
|
|
32
|
|
|
|
|
|
33
|
#-----------------------------------------------------------------------------
|
|
|
|
|
34
|
# Module globals
|
|
|
|
|
35
|
#-----------------------------------------------------------------------------
|
|
24
|
|
|
36
|
|
|
25
|
_kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
|
|
37
|
_kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
|
|
26
|
_kernel_action_regex = r"(?P<action>restart|interrupt)"
|
|
38
|
_kernel_action_regex = r"(?P<action>restart|interrupt)"
|
|
27
|
|
|
39
|
|
|
28
|
|
|
40
|
#-----------------------------------------------------------------------------
|
|
|
|
|
41
|
# The Tornado web application
|
|
|
|
|
42
|
#-----------------------------------------------------------------------------
|
|
29
|
|
|
43
|
|
|
30
|
class NotebookWebApplication(web.Application):
|
|
44
|
class NotebookWebApplication(web.Application):
|
|
31
|
|
|
45
|
|
|
32
|
def __init__(self):
|
|
46
|
def __init__(self, kernel_manager, log):
|
|
33
|
handlers = [
|
|
47
|
handlers = [
|
|
34
|
(r"/", MainHandler),
|
|
48
|
(r"/", MainHandler),
|
|
35
|
(r"/kernels", KernelHandler),
|
|
49
|
(r"/kernels", KernelHandler),
|
|
@@
-45,9
+59,8
b' class NotebookWebApplication(web.Application):'
|
|
45
|
)
|
|
59
|
)
|
|
46
|
web.Application.__init__(self, handlers, **settings)
|
|
60
|
web.Application.__init__(self, handlers, **settings)
|
|
47
|
|
|
61
|
|
|
48
|
self.context = zmq.Context()
|
|
62
|
self.kernel_manager = kernel_manager
|
|
49
|
self.kernel_manager = KernelManager(self.context)
|
|
63
|
self.log = log
|
|
50
|
self._session_dict = {}
|
|
|
|
|
51
|
self._routers = {}
|
|
64
|
self._routers = {}
|
|
52
|
|
|
65
|
|
|
53
|
#-------------------------------------------------------------------------
|
|
66
|
#-------------------------------------------------------------------------
|
|
@@
-59,14
+72,32
b' class NotebookWebApplication(web.Application):'
|
|
59
|
return self.kernel_manager.kernel_ids
|
|
72
|
return self.kernel_manager.kernel_ids
|
|
60
|
|
|
73
|
|
|
61
|
def start_kernel(self):
|
|
74
|
def start_kernel(self):
|
|
|
|
|
75
|
# TODO: pass command line options to the kernel in start_kernel()
|
|
62
|
kernel_id = self.kernel_manager.start_kernel()
|
|
76
|
kernel_id = self.kernel_manager.start_kernel()
|
|
63
|
logging.info("Kernel started: %s" % kernel_id)
|
|
77
|
self.log.info("Kernel started: %s" % kernel_id)
|
|
64
|
self.start_session(kernel_id)
|
|
78
|
self.start_session_manager(kernel_id)
|
|
65
|
return kernel_id
|
|
79
|
return kernel_id
|
|
66
|
|
|
80
|
|
|
|
|
|
81
|
def start_session_manager(self, kernel_id):
|
|
|
|
|
82
|
sm = self.kernel_manager.create_session_manager(kernel_id)
|
|
|
|
|
83
|
self._session_dict[kernel_id] = sm
|
|
|
|
|
84
|
iopub_stream = sm.get_iopub_stream()
|
|
|
|
|
85
|
shell_stream = sm.get_shell_stream()
|
|
|
|
|
86
|
iopub_router = IOPubStreamRouter(iopub_stream)
|
|
|
|
|
87
|
shell_router = ShellStreamRouter(shell_stream)
|
|
|
|
|
88
|
self._routers[(kernel_id, 'iopub')] = iopub_router
|
|
|
|
|
89
|
self._routers[(kernel_id, 'shell')] = shell_router
|
|
|
|
|
90
|
self.log.debug("Session manager started for kernel: %s" % kernel_id)
|
|
|
|
|
91
|
|
|
|
|
|
92
|
def kill_kernel(self, kernel_id):
|
|
|
|
|
93
|
sm = self._session_dict.pop(kernel_id)
|
|
|
|
|
94
|
sm.stop()
|
|
|
|
|
95
|
self.kernel_manager.kill_kernel(kernel_id)
|
|
|
|
|
96
|
self.log.info("Kernel killed: %s" % kernel_id)
|
|
|
|
|
97
|
|
|
67
|
def interrupt_kernel(self, kernel_id):
|
|
98
|
def interrupt_kernel(self, kernel_id):
|
|
68
|
self.kernel_manager.interrupt_kernel(kernel_id)
|
|
99
|
self.kernel_manager.interrupt_kernel(kernel_id)
|
|
69
|
logging.info("Kernel interrupted: %s" % kernel_id)
|
|
100
|
self.log.debug("Kernel interrupted: %s" % kernel_id)
|
|
70
|
|
|
101
|
|
|
71
|
def restart_kernel(self, kernel_id):
|
|
102
|
def restart_kernel(self, kernel_id):
|
|
72
|
# Create the new kernel first so we can move the clients over.
|
|
103
|
# Create the new kernel first so we can move the clients over.
|
|
@@
-84,48
+115,106
b' class NotebookWebApplication(web.Application):'
|
|
84
|
# TODO: This causes a hard crash in ZMQStream.close, which sets
|
|
115
|
# TODO: This causes a hard crash in ZMQStream.close, which sets
|
|
85
|
# self.socket to None to hastily. We will need to fix this in PyZMQ
|
|
116
|
# self.socket to None to hastily. We will need to fix this in PyZMQ
|
|
86
|
# itself. For now, we just leave the old kernel running :(
|
|
117
|
# itself. For now, we just leave the old kernel running :(
|
|
87
|
# sm = self.kernel_manager.get_session_manager(kernel_id)
|
|
118
|
# self.kill_kernel(kernel_id)
|
|
88
|
# session_id = self._session_dict[kernel_id]
|
|
|
|
|
89
|
# sm.stop_session(session_id)
|
|
|
|
|
90
|
# self.kernel_manager.kill_kernel(kernel_id)
|
|
|
|
|
91
|
|
|
119
|
|
|
92
|
logging.info("Kernel restarted")
|
|
120
|
self.log.debug("Kernel restarted: %s -> %s" % (kernel_id, new_kernel_id))
|
|
93
|
return new_kernel_id
|
|
121
|
return new_kernel_id
|
|
94
|
|
|
122
|
|
|
95
|
def start_session(self, kernel_id):
|
|
|
|
|
96
|
sm = self.kernel_manager.get_session_manager(kernel_id)
|
|
|
|
|
97
|
session_id = sm.start_session()
|
|
|
|
|
98
|
self._session_dict[kernel_id] = session_id
|
|
|
|
|
99
|
iopub_stream = sm.get_iopub_stream(session_id)
|
|
|
|
|
100
|
shell_stream = sm.get_shell_stream(session_id)
|
|
|
|
|
101
|
iopub_router = IOPubStreamRouter(iopub_stream)
|
|
|
|
|
102
|
shell_router = ShellStreamRouter(shell_stream)
|
|
|
|
|
103
|
self._routers[(kernel_id, session_id, 'iopub')] = iopub_router
|
|
|
|
|
104
|
self._routers[(kernel_id, session_id, 'shell')] = shell_router
|
|
|
|
|
105
|
logging.info("Session started: %s, %s" % (kernel_id, session_id))
|
|
|
|
|
106
|
|
|
|
|
|
107
|
def stop_session(self, kernel_id):
|
|
|
|
|
108
|
# TODO: finish this!
|
|
|
|
|
109
|
sm = self.kernel_manager.get_session_manager(kernel_id)
|
|
|
|
|
110
|
session_id = self._session_dict[kernel_id]
|
|
|
|
|
111
|
|
|
|
|
|
112
|
def get_router(self, kernel_id, stream_name):
|
|
123
|
def get_router(self, kernel_id, stream_name):
|
|
113
|
session_id = self._session_dict[kernel_id]
|
|
124
|
router = self._routers[(kernel_id, stream_name)]
|
|
114
|
router = self._routers[(kernel_id, session_id, stream_name)]
|
|
|
|
|
115
|
return router
|
|
125
|
return router
|
|
116
|
|
|
126
|
|
|
|
|
|
127
|
#-----------------------------------------------------------------------------
|
|
|
|
|
128
|
# Aliases and Flags
|
|
|
|
|
129
|
#-----------------------------------------------------------------------------
|
|
|
|
|
130
|
|
|
|
|
|
131
|
flags = dict(ipkernel_flags)
|
|
|
|
|
132
|
|
|
|
|
|
133
|
# the flags that are specific to the frontend
|
|
|
|
|
134
|
# these must be scrubbed before being passed to the kernel,
|
|
|
|
|
135
|
# or it will raise an error on unrecognized flags
|
|
|
|
|
136
|
notebook_flags = []
|
|
|
|
|
137
|
|
|
|
|
|
138
|
aliases = dict(ipkernel_aliases)
|
|
|
|
|
139
|
|
|
|
|
|
140
|
aliases.update(dict(
|
|
|
|
|
141
|
ip = 'IPythonNotebookApp.ip',
|
|
|
|
|
142
|
port = 'IPythonNotebookApp.port'
|
|
|
|
|
143
|
colors = 'ZMQInteractiveShell.colors',
|
|
|
|
|
144
|
editor = 'IPythonWidget.editor',
|
|
|
|
|
145
|
))
|
|
|
|
|
146
|
|
|
|
|
|
147
|
#-----------------------------------------------------------------------------
|
|
|
|
|
148
|
# IPythonNotebookApp
|
|
|
|
|
149
|
#-----------------------------------------------------------------------------
|
|
|
|
|
150
|
|
|
|
|
|
151
|
class IPythonNotebookApp(BaseIPythonApplication):
|
|
|
|
|
152
|
name = 'ipython-notebook'
|
|
|
|
|
153
|
default_config_file_name='ipython_notebook_config.py'
|
|
|
|
|
154
|
|
|
|
|
|
155
|
description = """
|
|
|
|
|
156
|
The IPython HTML Notebook.
|
|
|
|
|
157
|
|
|
|
|
|
158
|
This launches a Tornado based HTML Notebook Server that serves up an
|
|
|
|
|
159
|
HTML5/Javascript Notebook client.
|
|
|
|
|
160
|
"""
|
|
|
|
|
161
|
|
|
|
|
|
162
|
classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
|
|
|
|
|
163
|
KernelManager, SessionManager]
|
|
|
|
|
164
|
flags = Dict(flags)
|
|
|
|
|
165
|
aliases = Dict(aliases)
|
|
|
|
|
166
|
|
|
|
|
|
167
|
kernel_argv = List(Unicode)
|
|
|
|
|
168
|
|
|
|
|
|
169
|
# connection info:
|
|
|
|
|
170
|
ip = Unicode(LOCALHOST, config=True,
|
|
|
|
|
171
|
help="The IP address the notebook server will listen on."
|
|
|
|
|
172
|
)
|
|
|
|
|
173
|
|
|
|
|
|
174
|
port = Int(8888, config=True,
|
|
|
|
|
175
|
help="The port the notebook server will listen on."
|
|
|
|
|
176
|
)
|
|
|
|
|
177
|
|
|
|
|
|
178
|
# the factory for creating a widget
|
|
|
|
|
179
|
widget_factory = Any(RichIPythonWidget)
|
|
|
|
|
180
|
|
|
|
|
|
181
|
def parse_command_line(self, argv=None):
|
|
|
|
|
182
|
super(IPythonNotebookApp, self).parse_command_line(argv)
|
|
|
|
|
183
|
if argv is None:
|
|
|
|
|
184
|
argv = sys.argv[1:]
|
|
|
|
|
185
|
|
|
|
|
|
186
|
self.kernel_argv = list(argv) # copy
|
|
|
|
|
187
|
# kernel should inherit default config file from frontend
|
|
|
|
|
188
|
self.kernel_argv.append("KernelApp.parent_appname='%s'"%self.name)
|
|
|
|
|
189
|
# scrub frontend-specific flags
|
|
|
|
|
190
|
for a in argv:
|
|
|
|
|
191
|
if a.startswith('--') and a[2:] in qt_flags:
|
|
|
|
|
192
|
self.kernel_argv.remove(a)
|
|
|
|
|
193
|
|
|
|
|
|
194
|
def init_kernel_manager(self):
|
|
|
|
|
195
|
# Don't let Qt or ZMQ swallow KeyboardInterupts.
|
|
|
|
|
196
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
|
|
|
197
|
|
|
|
|
|
198
|
# Create a KernelManager and start a kernel.
|
|
|
|
|
199
|
self.kernel_manager = KernelManager(config=self.config, log=self.log)
|
|
|
|
|
200
|
|
|
|
|
|
201
|
def initialize(self, argv=None):
|
|
|
|
|
202
|
super(IPythonNotebookApp, self).initialize(argv)
|
|
|
|
|
203
|
self.init_kernel_mananger()
|
|
|
|
|
204
|
self.web_app = NotebookWebApplication()
|
|
|
|
|
205
|
self.http_server = httpserver.HTTPServer(self.web_app)
|
|
|
|
|
206
|
self.http_server.listen(self.port)
|
|
|
|
|
207
|
|
|
|
|
|
208
|
def start(self):
|
|
|
|
|
209
|
self.log.info("The IPython Notebook is running at: http://%s:%i" % (self.ip, self.port))
|
|
|
|
|
210
|
ioloop.IOLoop.instance().start()
|
|
|
|
|
211
|
|
|
|
|
|
212
|
#-----------------------------------------------------------------------------
|
|
|
|
|
213
|
# Main entry point
|
|
|
|
|
214
|
#-----------------------------------------------------------------------------
|
|
117
|
|
|
215
|
|
|
118
|
def launch_new_instance():
|
|
216
|
def launch_new_instance():
|
|
119
|
options.parse_command_line()
|
|
217
|
app = IPythonNotebookApp()
|
|
120
|
application = NotebookWebApplication()
|
|
218
|
app.initialize()
|
|
121
|
http_server = httpserver.HTTPServer(application)
|
|
219
|
app.start()
|
|
122
|
http_server.listen(options.options.port)
|
|
|
|
|
123
|
print "IPython Notebook running at: http://127.0.0.1:8888"
|
|
|
|
|
124
|
print "The github master of tornado is required to run this server:"
|
|
|
|
|
125
|
print " https://github.com/facebook/tornado/tree/master/tornado"
|
|
|
|
|
126
|
ioloop.IOLoop.instance().start()
|
|
|
|
|
127
|
|
|
|
|
|
128
|
|
|
|
|
|
129
|
if __name__ == "__main__":
|
|
|
|
|
130
|
main()
|
|
|
|
|
131
|
|
|
220
|
|