mirror of
https://github.com/jupyter/notebook.git
synced 2025-01-24 12:05:22 +08:00
Work on the server side of the html notebook.
This commit is contained in:
parent
f44f537ee4
commit
a2aef63d09
98
IPython/frontend/html/notebook/kernelmanager.py
Normal file
98
IPython/frontend/html/notebook/kernelmanager.py
Normal 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)
|
||||
|
||||
|
||||
|
@ -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__":
|
||||
|
@ -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({
|
||||
|
Loading…
Reference in New Issue
Block a user