Work on the server side of the html notebook.

This commit is contained in:
Brian Granger 2011-03-23 10:00:52 -07:00 committed by Brian E. Granger
parent f44f537ee4
commit a2aef63d09
3 changed files with 241 additions and 16 deletions

View File

@ -0,0 +1,98 @@
import signal
import sys
import uuid
from IPython.zmq.ipkernel import launch_kernel
from session import SessionManager
class KernelManager(object):
ip = '127.0.0.1'
def __init__(self, context):
self.context = context
self._kernels = {}
@property
def kernel_ids(self):
return self._kernels.keys()
def __len__(self):
return len(self.kernel_ids)
def __contains__(self, kernel_id):
if kernel_id in self.kernel_ids:
return True
else:
return False
def start_kernel(self):
kid = str(uuid.uuid4())
(process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel()
d = dict(
process = process,
stdin_port = stdin_port,
iopub_port = iopub_port,
shell_port = shell_port,
hb_port = hb_port,
session_manager = SessionManager(self, kid, self.context)
)
self._kernels[kid] = d
return kid
def kill_kernel(self, kernel_id):
kernel_process = self.get_kernel_process(kernel_id)
if kernel_process is not None:
# Attempt to kill the kernel.
try:
kernel_process.kill()
except OSError, e:
# In Windows, we will get an Access Denied error if the process
# has already terminated. Ignore it.
if not (sys.platform == 'win32' and e.winerror == 5):
raise
del self._kernels[kernel_id]
def interrupt_kernel(self, kernel_id):
kernel_process = self.get_kernel_process(kernel_id)
if kernel_process is not None:
if sys.platform == 'win32':
from parentpoller import ParentPollerWindows as Poller
Poller.send_interrupt(kernel_process.win32_interrupt_event)
else:
kernel_process.send_signal(signal.SIGINT)
def signal_kernel(self, kernel_id, signum):
""" Sends a signal to the kernel. Note that since only SIGTERM is
supported on Windows, this function is only useful on Unix systems.
"""
kernel_process = self.get_kernel_process(kernel_id)
if kernel_process is not None:
kernel_process.send_signal(signum)
def get_kernel_process(self, kernel_id):
d = self._kernels.get(kernel_id)
if d is not None:
return d['process']
else:
raise KeyError("Kernel with id not found: %s" % kernel_id)
def get_kernel_ports(self, kernel_id):
d = self._kernels.get(kernel_id)
if d is not None:
dcopy = d.copy()
dcopy.pop('process')
return dcopy
else:
raise KeyError("Kernel with id not found: %s" % kernel_id)
def get_session_manager(self, kernel_id):
d = self._kernels.get(kernel_id)
if d is not None:
return d['session_manager']
else:
raise KeyError("Kernel with id not found: %s" % kernel_id)

View File

@ -1,38 +1,122 @@
import json
import logging
import os
import uuid
import tornado.httpserver
import zmq
# Install the pyzmq ioloop. This has to be done before anything else from
# tornado is imported.
from zmq.eventloop.zmqstream import ZMQStream
from zmq.eventloop import ioloop
import tornado.ioloop
import tornado.options
import tornado.web
tornado.ioloop = ioloop
from tornado.options import define, options
from tornado import httpserver
from tornado import options
from tornado import web
from tornado import websocket
define("port", default=8888, help="run on the given port", type=int)
from kernelmanager import KernelManager
class MainHandler(tornado.web.RequestHandler):
options.define("port", default=8888, help="run on the given port", type=int)
_kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
_session_id_regex = r"(?P<session_id>\w+)"
class MainHandler(web.RequestHandler):
def get(self):
self.render('notebook.html')
class NotebookApplication(tornado.web.Application):
class KernelHandler(web.RequestHandler):
def get(self):
self.write(json.dumps(self.application.kernel_manager.kernel_ids))
def post(self):
kid = self.application.kernel_manager.start_kernel()
logging.info("Starting kernel: %s" % kid)
self.write(json.dumps(kid))
class SessionHandler(web.RequestHandler):
def post(self, *args, **kwargs):
kernel_id = kwargs['kernel_id']
session_id = kwargs['session_id']
logging.info("Starting session: %s, %s" % (kernel_id,session_id))
km = self.application.kernel_manager
sm = km.get_session_manager(kernel_id)
sm.start_session(session_id)
self.finish()
class ZMQStreamHandler(websocket.WebSocketHandler):
stream_name = ''
def open(self, *args, **kwargs):
kernel_id = kwargs['kernel_id']
session_id = kwargs['session_id']
logging.info("Connection open: %s, %s" % (kernel_id,session_id))
sm = self.application.kernel_manager.get_session_manager(kernel_id)
method_name = "get_%s_stream" % self.stream_name
method = getattr(sm, method_name)
self.zmq_stream = method(session_id)
self.zmq_stream.on_recv(self._on_zmq_reply)
self.session_manager = sm
self.session_id = session_id
def on_message(self, msg):
logging.info("Message received: %r" % msg)
self.zmq_stream.send(msg)
def on_close(self):
logging.info("Connection closed: %s, %s" % (kernel_id,session_id))
self.zmq_stream.close()
def _on_zmq_reply(self, msg):
logging.info("Message reply: %r" % msg)
self.write_message(msg)
class IOPubStreamHandler(ZMQStreamHandler):
stream_name = 'iopub'
class ShellStreamHandler(ZMQStreamHandler):
stream_name = 'shell'
class NotebookApplication(web.Application):
def __init__(self):
handlers = [
(r"/", MainHandler)
(r"/", MainHandler),
(r"/kernels", KernelHandler),
(r"/kernels/%s/sessions/%s" % (_kernel_id_regex,_session_id_regex), SessionHandler),
(r"/kernels/%s/sessions/%s/iopub" % (_kernel_id_regex,_session_id_regex), IOPubStreamHandler),
(r"/kernels/%s/sessions/%s/shell" % (_kernel_id_regex,_session_id_regex), ShellStreamHandler),
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static"),
)
tornado.web.Application.__init__(self, handlers, **settings)
web.Application.__init__(self, handlers, **settings)
self.context = zmq.Context()
self.kernel_manager = KernelManager(self.context)
def main():
tornado.options.parse_command_line()
options.parse_command_line()
application = NotebookApplication()
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
http_server = httpserver.HTTPServer(application)
http_server.listen(options.options.port)
ioloop.IOLoop.instance().start()
if __name__ == "__main__":

View File

@ -8,10 +8,11 @@ var IPYTHON = {};
var Notebook = function (selector) {
this.element = $(selector);
this.element.scroll();
this.element.data("notebook", this);
this.next_prompt_number = 1;
this.bind_events();
}
};
Notebook.prototype.bind_events = function () {
@ -197,6 +198,7 @@ Notebook.prototype.move_cell_down = function (index) {
Notebook.prototype.sort_cells = function () {
var ncells = this.ncells();
var sindex = this.selected_index();
var swapped;
do {
swapped = false
@ -209,6 +211,7 @@ Notebook.prototype.sort_cells = function () {
};
};
} while (swapped);
this.select(sindex);
return this;
};
@ -464,7 +467,7 @@ TextCell.prototype.select = function () {
TextCell.prototype.edit = function () {
var text_cell = this.element;
var input = text_cell.find("textarea.text_cell_input");
var output = text_cell.find("div.text_cell_render");
var output = text_cell.find("div.text_cell_render");
output.hide();
input.show().trigger('focus');
};
@ -475,6 +478,10 @@ TextCell.prototype.render = function () {
var input = text_cell.find("textarea.text_cell_input");
var output = text_cell.find("div.text_cell_render");
var text = input.val();
if (text === "") {
text = this.placeholder;
input.val(text);
};
output.html(text)
input.html(text);
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
@ -501,6 +508,42 @@ TextCell.prototype.config_mathjax = function () {
//============================================================================
var KernelManager = function () {
this.kernelid = null;
this.baseurl = "/kernels";
};
KernelManager.prototype.create_kernel = function () {
var that = this;
$.post(this.baseurl, function (data) {
that.kernelid = data;
}, 'json');
}
KernelManager.prototype.execute = function (code, callback) {
var msg = {
header : {msg_id : 0, username : "bgranger", session: 0},
msg_type : "execute_request",
content : {code : code}
};
var settings = {
data : JSON.stringify(msg),
processData : false,
contentType : "application/json",
success : callback,
type : "POST"
}
var url = this.baseurl + "/" + this.kernelid + "/" + ""
}
//============================================================================
// On document ready
//============================================================================
$(document).ready(function () {
MathJax.Hub.Config({