##// END OF EJS Templates
Creating files to new notebook app.
Brian E. Granger -
Show More
@@ -0,0 +1,275 b''
1 import datetime
2 import json
3 import logging
4 import os
5 import urllib
6 import uuid
7 from Queue import Queue
8
9 import zmq
10
11 # Install the pyzmq ioloop. This has to be done before anything else from
12 # tornado is imported.
13 from zmq.eventloop import ioloop
14 import tornado.ioloop
15 tornado.ioloop = ioloop
16
17 from tornado import httpserver
18 from tornado import options
19 from tornado import web
20 from tornado import websocket
21
22 from kernelmanager import KernelManager
23
24 options.define("port", default=8888, help="run on the given port", type=int)
25
26 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
27 _kernel_action_regex = r"(?P<action>restart|interrupt)"
28
29 class MainHandler(web.RequestHandler):
30 def get(self):
31 self.render('notebook.html')
32
33
34 class KernelHandler(web.RequestHandler):
35
36 def get(self):
37 self.write(json.dumps(self.application.kernel_ids))
38
39 def post(self):
40 kernel_id = self.application.start_kernel()
41 self.write(json.dumps(kernel_id))
42
43
44 class KernelActionHandler(web.RequestHandler):
45
46 def post(self, kernel_id, action):
47 # TODO: figure out a better way of handling RPC style calls.
48 if action == 'interrupt':
49 self.application.interrupt_kernel(kernel_id)
50 if action == 'restart':
51 new_kernel_id = self.application.restart_kernel(kernel_id)
52 self.write(json.dumps(new_kernel_id))
53
54
55 class ZMQStreamRouter(object):
56
57 def __init__(self, zmq_stream):
58 self.zmq_stream = zmq_stream
59 self._clients = {}
60 self.zmq_stream.on_recv(self._on_zmq_reply)
61
62 def register_client(self, client):
63 client_id = uuid.uuid4()
64 self._clients[client_id] = client
65 return client_id
66
67 def unregister_client(self, client_id):
68 del self._clients[client_id]
69
70 def copy_clients(self, router):
71 # Copy the clients of another router.
72 for client_id, client in router._clients.items():
73 client.router = self
74 self._clients[client_id] = client
75
76
77 class IOPubStreamRouter(ZMQStreamRouter):
78
79 def _on_zmq_reply(self, msg_list):
80 for client_id, client in self._clients.items():
81 for msg in msg_list:
82 client.write_message(msg)
83
84 def forward_unicode(self, client_id, msg):
85 # This is a SUB stream that we should never write to.
86 pass
87
88
89 class ShellStreamRouter(ZMQStreamRouter):
90
91 def __init__(self, zmq_stream):
92 ZMQStreamRouter.__init__(self, zmq_stream)
93 self._request_queue = Queue()
94
95 def _on_zmq_reply(self, msg_list):
96 client_id = self._request_queue.get(block=False)
97 client = self._clients.get(client_id)
98 if client is not None:
99 for msg in msg_list:
100 client.write_message(msg)
101
102 def forward_unicode(self, client_id, msg):
103 self._request_queue.put(client_id)
104 self.zmq_stream.send_unicode(msg)
105
106
107 class ZMQStreamHandler(websocket.WebSocketHandler):
108
109 def initialize(self, stream_name):
110 self.stream_name = stream_name
111
112 def open(self, kernel_id):
113 self.router = self.application.get_router(kernel_id, self.stream_name)
114 self.client_id = self.router.register_client(self)
115 logging.info("Connection open: %s, %s" % (kernel_id, self.client_id))
116
117 def on_message(self, msg):
118 self.router.forward_unicode(self.client_id, msg)
119
120 def on_close(self):
121 self.router.unregister_client(self.client_id)
122 logging.info("Connection closed: %s" % self.client_id)
123
124
125 class NotebookRootHandler(web.RequestHandler):
126
127 def get(self):
128 files = os.listdir(os.getcwd())
129 files = [file for file in files if file.endswith(".ipynb")]
130 self.write(json.dumps(files))
131
132
133 class NotebookHandler(web.RequestHandler):
134
135 SUPPORTED_METHODS = ("GET", "DELETE", "PUT")
136
137 def find_path(self, filename):
138 filename = urllib.unquote(filename)
139 if not filename.endswith('.ipynb'):
140 raise web.HTTPError(400)
141 path = os.path.join(os.getcwd(), filename)
142 return path
143
144 def get(self, filename):
145 path = self.find_path(filename)
146 if not os.path.isfile(path):
147 raise web.HTTPError(404)
148 info = os.stat(path)
149 self.set_header("Content-Type", "application/unknown")
150 self.set_header("Last-Modified", datetime.datetime.utcfromtimestamp(
151 info.st_mtime))
152 f = open(path, "r")
153 try:
154 self.finish(f.read())
155 finally:
156 f.close()
157
158 def put(self, filename):
159 path = self.find_path(filename)
160 f = open(path, "w")
161 f.write(self.request.body)
162 f.close()
163 self.finish()
164
165 def delete(self, filename):
166 path = self.find_path(filename)
167 if not os.path.isfile(path):
168 raise web.HTTPError(404)
169 os.unlink(path)
170 self.set_status(204)
171 self.finish()
172
173
174 class NotebookApplication(web.Application):
175
176 def __init__(self):
177 handlers = [
178 (r"/", MainHandler),
179 (r"/kernels", KernelHandler),
180 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
181 (r"/kernels/%s/iopub" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='iopub')),
182 (r"/kernels/%s/shell" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='shell')),
183 (r"/notebooks", NotebookRootHandler),
184 (r"/notebooks/([^/]+)", NotebookHandler)
185 ]
186 settings = dict(
187 template_path=os.path.join(os.path.dirname(__file__), "templates"),
188 static_path=os.path.join(os.path.dirname(__file__), "static"),
189 )
190 web.Application.__init__(self, handlers, **settings)
191
192 self.context = zmq.Context()
193 self.kernel_manager = KernelManager(self.context)
194 self._session_dict = {}
195 self._routers = {}
196
197 #-------------------------------------------------------------------------
198 # Methods for managing kernels and sessions
199 #-------------------------------------------------------------------------
200
201 @property
202 def kernel_ids(self):
203 return self.kernel_manager.kernel_ids
204
205 def start_kernel(self):
206 kernel_id = self.kernel_manager.start_kernel()
207 logging.info("Kernel started: %s" % kernel_id)
208 self.start_session(kernel_id)
209 return kernel_id
210
211 def interrupt_kernel(self, kernel_id):
212 self.kernel_manager.interrupt_kernel(kernel_id)
213 logging.info("Kernel interrupted: %s" % kernel_id)
214
215 def restart_kernel(self, kernel_id):
216 # Create the new kernel first so we can move the clients over.
217 new_kernel_id = self.start_kernel()
218
219 # Copy the clients over to the new routers.
220 old_iopub_router = self.get_router(kernel_id, 'iopub')
221 old_shell_router = self.get_router(kernel_id, 'shell')
222 new_iopub_router = self.get_router(new_kernel_id, 'iopub')
223 new_shell_router = self.get_router(new_kernel_id, 'shell')
224 new_iopub_router.copy_clients(old_iopub_router)
225 new_shell_router.copy_clients(old_shell_router)
226
227 # Now shutdown the old session and the kernel.
228 # TODO: This causes a hard crash in ZMQStream.close, which sets
229 # self.socket to None to hastily. We will need to fix this in PyZMQ
230 # itself. For now, we just leave the old kernel running :(
231 # sm = self.kernel_manager.get_session_manager(kernel_id)
232 # session_id = self._session_dict[kernel_id]
233 # sm.stop_session(session_id)
234 # self.kernel_manager.kill_kernel(kernel_id)
235
236 logging.info("Kernel restarted")
237 return new_kernel_id
238
239 def start_session(self, kernel_id):
240 sm = self.kernel_manager.get_session_manager(kernel_id)
241 session_id = sm.start_session()
242 self._session_dict[kernel_id] = session_id
243 iopub_stream = sm.get_iopub_stream(session_id)
244 shell_stream = sm.get_shell_stream(session_id)
245 iopub_router = IOPubStreamRouter(iopub_stream)
246 shell_router = ShellStreamRouter(shell_stream)
247 self._routers[(kernel_id, session_id, 'iopub')] = iopub_router
248 self._routers[(kernel_id, session_id, 'shell')] = shell_router
249 logging.info("Session started: %s, %s" % (kernel_id, session_id))
250
251 def stop_session(self, kernel_id):
252 # TODO: finish this!
253 sm = self.kernel_manager.get_session_manager(kernel_id)
254 session_id = self._session_dict[kernel_id]
255
256 def get_router(self, kernel_id, stream_name):
257 session_id = self._session_dict[kernel_id]
258 router = self._routers[(kernel_id, session_id, stream_name)]
259 return router
260
261
262 def main():
263 options.parse_command_line()
264 application = NotebookApplication()
265 http_server = httpserver.HTTPServer(application)
266 http_server.listen(options.options.port)
267 print "IPython Notebook running at: http://127.0.0.1:8888"
268 print "The github master of tornado is required to run this server:"
269 print " https://github.com/facebook/tornado/tree/master/tornado"
270 ioloop.IOLoop.instance().start()
271
272
273 if __name__ == "__main__":
274 main()
275
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/notebook.py to IPython/frontend/html/notebook/handlers.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/notebook.py to IPython/frontend/html/notebook/handlers.py
General Comments 0
You need to be logged in to leave comments. Login now