##// END OF EJS Templates
Refactoring the notebook app to support the new config system.
Brian E. Granger -
Show More
@@ -1,5 +1,9 b''
1 """A kernel manager for multiple kernels."""
1 """A kernel manager for multiple kernels."""
2
2
3 #-----------------------------------------------------------------------------
4 # Imports
5 #-----------------------------------------------------------------------------
6
3 import logging
7 import logging
4 import signal
8 import signal
5 import sys
9 import sys
@@ -11,6 +15,9 b' from IPython.config.configurable import Configurable'
11 from IPython.zmq.ipkernel import launch_kernel
15 from IPython.zmq.ipkernel import launch_kernel
12 from IPython.utils.traitlets import Instance, Dict, Unicode
16 from IPython.utils.traitlets import Instance, Dict, Unicode
13
17
18 #-----------------------------------------------------------------------------
19 # Classes
20 #-----------------------------------------------------------------------------
14
21
15 class DuplicateKernelError(Exception):
22 class DuplicateKernelError(Exception):
16 pass
23 pass
@@ -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
@@ -1,5 +1,9 b''
1 """A manager for session and channels for a single kernel."""
1 """A manager for session and channels for a single kernel."""
2
2
3 #-----------------------------------------------------------------------------
4 # Imports
5 #-----------------------------------------------------------------------------
6
3 import zmq
7 import zmq
4 from zmq.eventloop.zmqstream import ZMQStream
8 from zmq.eventloop.zmqstream import ZMQStream
5
9
@@ -10,6 +14,10 b' from IPython.zmq.session import SessionFactory'
10 class SessionManagerRunningError(Exception):
14 class SessionManagerRunningError(Exception):
11 pass
15 pass
12
16
17 #-----------------------------------------------------------------------------
18 # Classes
19 #-----------------------------------------------------------------------------
20
13
21
14 class SessionManager(SessionFactory):
22 class SessionManager(SessionFactory):
15 """Manages a session for a kernel.
23 """Manages a session for a kernel.
@@ -1,3 +1,4 b''
1 """Tests for the notebook kernel and session manager."""
1
2
2 from unittest import TestCase
3 from unittest import TestCase
3
4
@@ -195,6 +195,9 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
195 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
195 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
196 """Launch the IPython Qt Console."""
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 profile = ("IPython.core.profileapp.ProfileApp",
201 profile = ("IPython.core.profileapp.ProfileApp",
199 "Create and manage IPython profiles.")
202 "Create and manage IPython profiles.")
200 ))
203 ))
General Comments 0
You need to be logged in to leave comments. Login now