Show More
@@ -1,5 +1,9 b'' | |||
|
1 | 1 | """A kernel manager for multiple kernels.""" |
|
2 | 2 | |
|
3 | #----------------------------------------------------------------------------- | |
|
4 | # Imports | |
|
5 | #----------------------------------------------------------------------------- | |
|
6 | ||
|
3 | 7 | import logging |
|
4 | 8 | import signal |
|
5 | 9 | import sys |
@@ -11,6 +15,9 b' from IPython.config.configurable import Configurable' | |||
|
11 | 15 | from IPython.zmq.ipkernel import launch_kernel |
|
12 | 16 | from IPython.utils.traitlets import Instance, Dict, Unicode |
|
13 | 17 | |
|
18 | #----------------------------------------------------------------------------- | |
|
19 | # Classes | |
|
20 | #----------------------------------------------------------------------------- | |
|
14 | 21 | |
|
15 | 22 | class DuplicateKernelError(Exception): |
|
16 | 23 | pass |
@@ -1,3 +1,9 b'' | |||
|
1 | """A tornado based IPython notebook server.""" | |
|
2 | ||
|
3 | #----------------------------------------------------------------------------- | |
|
4 | # Imports | |
|
5 | #----------------------------------------------------------------------------- | |
|
6 | ||
|
1 | 7 | import logging |
|
2 | 8 | import os |
|
3 | 9 | |
@@ -14,22 +20,30 b' from tornado import options' | |||
|
14 | 20 | from tornado import web |
|
15 | 21 | |
|
16 | 22 | from kernelmanager import KernelManager |
|
23 | from sessionmanager import SessionManager | |
|
17 | 24 | from handlers import ( |
|
18 | 25 | MainHandler, KernelHandler, KernelActionHandler, ZMQStreamHandler, |
|
19 | 26 | NotebookRootHandler, NotebookHandler |
|
20 | 27 | ) |
|
21 | 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 | 37 | _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)" |
|
26 | 38 | _kernel_action_regex = r"(?P<action>restart|interrupt)" |
|
27 | 39 | |
|
28 | ||
|
40 | #----------------------------------------------------------------------------- | |
|
41 | # The Tornado web application | |
|
42 | #----------------------------------------------------------------------------- | |
|
29 | 43 | |
|
30 | 44 | class NotebookWebApplication(web.Application): |
|
31 | 45 | |
|
32 | def __init__(self): | |
|
46 | def __init__(self, kernel_manager, log): | |
|
33 | 47 | handlers = [ |
|
34 | 48 | (r"/", MainHandler), |
|
35 | 49 | (r"/kernels", KernelHandler), |
@@ -45,9 +59,8 b' class NotebookWebApplication(web.Application):' | |||
|
45 | 59 | ) |
|
46 | 60 | web.Application.__init__(self, handlers, **settings) |
|
47 | 61 | |
|
48 | self.context = zmq.Context() | |
|
49 | self.kernel_manager = KernelManager(self.context) | |
|
50 | self._session_dict = {} | |
|
62 | self.kernel_manager = kernel_manager | |
|
63 | self.log = log | |
|
51 | 64 | self._routers = {} |
|
52 | 65 | |
|
53 | 66 | #------------------------------------------------------------------------- |
@@ -59,14 +72,32 b' class NotebookWebApplication(web.Application):' | |||
|
59 | 72 | return self.kernel_manager.kernel_ids |
|
60 | 73 | |
|
61 | 74 | def start_kernel(self): |
|
75 | # TODO: pass command line options to the kernel in start_kernel() | |
|
62 | 76 | kernel_id = self.kernel_manager.start_kernel() |
|
63 |
log |
|
|
64 | self.start_session(kernel_id) | |
|
77 | self.log.info("Kernel started: %s" % kernel_id) | |
|
78 | self.start_session_manager(kernel_id) | |
|
65 | 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 | 98 | def interrupt_kernel(self, kernel_id): |
|
68 | 99 | self.kernel_manager.interrupt_kernel(kernel_id) |
|
69 |
|
|
|
100 | self.log.debug("Kernel interrupted: %s" % kernel_id) | |
|
70 | 101 | |
|
71 | 102 | def restart_kernel(self, kernel_id): |
|
72 | 103 | # Create the new kernel first so we can move the clients over. |
@@ -84,48 +115,106 b' class NotebookWebApplication(web.Application):' | |||
|
84 | 115 | # TODO: This causes a hard crash in ZMQStream.close, which sets |
|
85 | 116 | # self.socket to None to hastily. We will need to fix this in PyZMQ |
|
86 | 117 | # itself. For now, we just leave the old kernel running :( |
|
87 |
# s |
|
|
88 | # session_id = self._session_dict[kernel_id] | |
|
89 | # sm.stop_session(session_id) | |
|
90 | # self.kernel_manager.kill_kernel(kernel_id) | |
|
118 | # self.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 | 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 | 123 | def get_router(self, kernel_id, stream_name): |
|
113 | session_id = self._session_dict[kernel_id] | |
|
114 | router = self._routers[(kernel_id, session_id, stream_name)] | |
|
124 | router = self._routers[(kernel_id, stream_name)] | |
|
115 | 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 | 216 | def launch_new_instance(): |
|
119 | options.parse_command_line() | |
|
120 | application = NotebookWebApplication() | |
|
121 | http_server = httpserver.HTTPServer(application) | |
|
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() | |
|
217 | app = IPythonNotebookApp() | |
|
218 | app.initialize() | |
|
219 | app.start() | |
|
131 | 220 |
@@ -1,5 +1,9 b'' | |||
|
1 | 1 | """A manager for session and channels for a single kernel.""" |
|
2 | 2 | |
|
3 | #----------------------------------------------------------------------------- | |
|
4 | # Imports | |
|
5 | #----------------------------------------------------------------------------- | |
|
6 | ||
|
3 | 7 | import zmq |
|
4 | 8 | from zmq.eventloop.zmqstream import ZMQStream |
|
5 | 9 | |
@@ -10,6 +14,10 b' from IPython.zmq.session import SessionFactory' | |||
|
10 | 14 | class SessionManagerRunningError(Exception): |
|
11 | 15 | pass |
|
12 | 16 | |
|
17 | #----------------------------------------------------------------------------- | |
|
18 | # Classes | |
|
19 | #----------------------------------------------------------------------------- | |
|
20 | ||
|
13 | 21 | |
|
14 | 22 | class SessionManager(SessionFactory): |
|
15 | 23 | """Manages a session for a kernel. |
@@ -1,3 +1,4 b'' | |||
|
1 | """Tests for the notebook kernel and session manager.""" | |
|
1 | 2 | |
|
2 | 3 | from unittest import TestCase |
|
3 | 4 |
@@ -195,6 +195,9 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):' | |||
|
195 | 195 | qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp', |
|
196 | 196 | """Launch the IPython Qt Console.""" |
|
197 | 197 | ), |
|
198 | hotebook=('IPython.frontend.html.notebook.notebookapp.IPythonNotebookApp', | |
|
199 | """Launch the IPython HTML Notebook Server""" | |
|
200 | ), | |
|
198 | 201 | profile = ("IPython.core.profileapp.ProfileApp", |
|
199 | 202 | "Create and manage IPython profiles.") |
|
200 | 203 | )) |
General Comments 0
You need to be logged in to leave comments.
Login now