##// 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 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 logging.info("Kernel started: %s" % kernel_id)
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 logging.info("Kernel interrupted: %s" % kernel_id)
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 # sm = self.kernel_manager.get_session_manager(kernel_id)
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 #-----------------------------------------------------------------------------
117 130
118 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"
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))
126 210 ioloop.IOLoop.instance().start()
127 211
212 #-----------------------------------------------------------------------------
213 # Main entry point
214 #-----------------------------------------------------------------------------
128 215
129 if __name__ == "__main__":
130 main()
216 def launch_new_instance():
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