##// END OF EJS Templates
cleanup connection files on notebook shutdown...
MinRK -
Show More
@@ -1,385 +1,402 b''
1 """A tornado based IPython notebook server.
1 """A tornado based IPython notebook server.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # stdlib
19 # stdlib
20 import errno
20 import errno
21 import logging
21 import logging
22 import os
22 import os
23 import signal
23 import signal
24 import socket
24 import socket
25 import sys
25 import sys
26 import threading
26 import threading
27 import webbrowser
27 import webbrowser
28
28
29 # Third party
29 # Third party
30 import zmq
30 import zmq
31
31
32 # Install the pyzmq ioloop. This has to be done before anything else from
32 # Install the pyzmq ioloop. This has to be done before anything else from
33 # tornado is imported.
33 # tornado is imported.
34 from zmq.eventloop import ioloop
34 from zmq.eventloop import ioloop
35 # FIXME: ioloop.install is new in pyzmq-2.1.7, so remove this conditional
35 # FIXME: ioloop.install is new in pyzmq-2.1.7, so remove this conditional
36 # when pyzmq dependency is updated beyond that.
36 # when pyzmq dependency is updated beyond that.
37 if hasattr(ioloop, 'install'):
37 if hasattr(ioloop, 'install'):
38 ioloop.install()
38 ioloop.install()
39 else:
39 else:
40 import tornado.ioloop
40 import tornado.ioloop
41 tornado.ioloop.IOLoop = ioloop.IOLoop
41 tornado.ioloop.IOLoop = ioloop.IOLoop
42
42
43 from tornado import httpserver
43 from tornado import httpserver
44 from tornado import web
44 from tornado import web
45
45
46 # Our own libraries
46 # Our own libraries
47 from .kernelmanager import MappingKernelManager
47 from .kernelmanager import MappingKernelManager
48 from .handlers import (LoginHandler, LogoutHandler,
48 from .handlers import (LoginHandler, LogoutHandler,
49 ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
49 ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
50 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
50 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
51 ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler
51 ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler
52 )
52 )
53 from .notebookmanager import NotebookManager
53 from .notebookmanager import NotebookManager
54
54
55 from IPython.config.application import catch_config_error, boolean_flag
55 from IPython.config.application import catch_config_error, boolean_flag
56 from IPython.core.application import BaseIPythonApplication
56 from IPython.core.application import BaseIPythonApplication
57 from IPython.core.profiledir import ProfileDir
57 from IPython.core.profiledir import ProfileDir
58 from IPython.lib.kernel import swallow_argv
58 from IPython.lib.kernel import swallow_argv
59 from IPython.zmq.session import Session, default_secure
59 from IPython.zmq.session import Session, default_secure
60 from IPython.zmq.zmqshell import ZMQInteractiveShell
60 from IPython.zmq.zmqshell import ZMQInteractiveShell
61 from IPython.zmq.ipkernel import (
61 from IPython.zmq.ipkernel import (
62 flags as ipkernel_flags,
62 flags as ipkernel_flags,
63 aliases as ipkernel_aliases,
63 aliases as ipkernel_aliases,
64 IPKernelApp
64 IPKernelApp
65 )
65 )
66 from IPython.utils.traitlets import Dict, Unicode, Integer, List, Enum, Bool
66 from IPython.utils.traitlets import Dict, Unicode, Integer, List, Enum, Bool
67
67
68 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
69 # Module globals
69 # Module globals
70 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
71
71
72 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
72 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
73 _kernel_action_regex = r"(?P<action>restart|interrupt)"
73 _kernel_action_regex = r"(?P<action>restart|interrupt)"
74 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
74 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
75
75
76 LOCALHOST = '127.0.0.1'
76 LOCALHOST = '127.0.0.1'
77
77
78 _examples = """
78 _examples = """
79 ipython notebook # start the notebook
79 ipython notebook # start the notebook
80 ipython notebook --profile=sympy # use the sympy profile
80 ipython notebook --profile=sympy # use the sympy profile
81 ipython notebook --pylab=inline # pylab in inline plotting mode
81 ipython notebook --pylab=inline # pylab in inline plotting mode
82 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
82 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
83 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
83 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
84 """
84 """
85
85
86 #-----------------------------------------------------------------------------
86 #-----------------------------------------------------------------------------
87 # The Tornado web application
87 # The Tornado web application
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89
89
90 class NotebookWebApplication(web.Application):
90 class NotebookWebApplication(web.Application):
91
91
92 def __init__(self, ipython_app, kernel_manager, notebook_manager, log, settings_overrides):
92 def __init__(self, ipython_app, kernel_manager, notebook_manager, log, settings_overrides):
93 handlers = [
93 handlers = [
94 (r"/", ProjectDashboardHandler),
94 (r"/", ProjectDashboardHandler),
95 (r"/login", LoginHandler),
95 (r"/login", LoginHandler),
96 (r"/logout", LogoutHandler),
96 (r"/logout", LogoutHandler),
97 (r"/new", NewHandler),
97 (r"/new", NewHandler),
98 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
98 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
99 (r"/kernels", MainKernelHandler),
99 (r"/kernels", MainKernelHandler),
100 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
100 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
101 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
101 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
102 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
102 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
103 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
103 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
104 (r"/notebooks", NotebookRootHandler),
104 (r"/notebooks", NotebookRootHandler),
105 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
105 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
106 (r"/rstservice/render", RSTHandler)
106 (r"/rstservice/render", RSTHandler)
107 ]
107 ]
108 settings = dict(
108 settings = dict(
109 template_path=os.path.join(os.path.dirname(__file__), "templates"),
109 template_path=os.path.join(os.path.dirname(__file__), "templates"),
110 static_path=os.path.join(os.path.dirname(__file__), "static"),
110 static_path=os.path.join(os.path.dirname(__file__), "static"),
111 cookie_secret=os.urandom(1024),
111 cookie_secret=os.urandom(1024),
112 login_url="/login",
112 login_url="/login",
113 )
113 )
114
114
115 # allow custom overrides for the tornado web app.
115 # allow custom overrides for the tornado web app.
116 settings.update(settings_overrides)
116 settings.update(settings_overrides)
117
117
118 super(NotebookWebApplication, self).__init__(handlers, **settings)
118 super(NotebookWebApplication, self).__init__(handlers, **settings)
119
119
120 self.kernel_manager = kernel_manager
120 self.kernel_manager = kernel_manager
121 self.log = log
121 self.log = log
122 self.notebook_manager = notebook_manager
122 self.notebook_manager = notebook_manager
123 self.ipython_app = ipython_app
123 self.ipython_app = ipython_app
124 self.read_only = self.ipython_app.read_only
124 self.read_only = self.ipython_app.read_only
125
125
126
126
127 #-----------------------------------------------------------------------------
127 #-----------------------------------------------------------------------------
128 # Aliases and Flags
128 # Aliases and Flags
129 #-----------------------------------------------------------------------------
129 #-----------------------------------------------------------------------------
130
130
131 flags = dict(ipkernel_flags)
131 flags = dict(ipkernel_flags)
132 flags['no-browser']=(
132 flags['no-browser']=(
133 {'NotebookApp' : {'open_browser' : False}},
133 {'NotebookApp' : {'open_browser' : False}},
134 "Don't open the notebook in a browser after startup."
134 "Don't open the notebook in a browser after startup."
135 )
135 )
136 flags['no-mathjax']=(
136 flags['no-mathjax']=(
137 {'NotebookApp' : {'enable_mathjax' : False}},
137 {'NotebookApp' : {'enable_mathjax' : False}},
138 """Disable MathJax
138 """Disable MathJax
139
139
140 MathJax is the javascript library IPython uses to render math/LaTeX. It is
140 MathJax is the javascript library IPython uses to render math/LaTeX. It is
141 very large, so you may want to disable it if you have a slow internet
141 very large, so you may want to disable it if you have a slow internet
142 connection, or for offline use of the notebook.
142 connection, or for offline use of the notebook.
143
143
144 When disabled, equations etc. will appear as their untransformed TeX source.
144 When disabled, equations etc. will appear as their untransformed TeX source.
145 """
145 """
146 )
146 )
147 flags['read-only'] = (
147 flags['read-only'] = (
148 {'NotebookApp' : {'read_only' : True}},
148 {'NotebookApp' : {'read_only' : True}},
149 """Allow read-only access to notebooks.
149 """Allow read-only access to notebooks.
150
150
151 When using a password to protect the notebook server, this flag
151 When using a password to protect the notebook server, this flag
152 allows unauthenticated clients to view the notebook list, and
152 allows unauthenticated clients to view the notebook list, and
153 individual notebooks, but not edit them, start kernels, or run
153 individual notebooks, but not edit them, start kernels, or run
154 code.
154 code.
155
155
156 If no password is set, the server will be entirely read-only.
156 If no password is set, the server will be entirely read-only.
157 """
157 """
158 )
158 )
159
159
160 # Add notebook manager flags
160 # Add notebook manager flags
161 flags.update(boolean_flag('script', 'NotebookManager.save_script',
161 flags.update(boolean_flag('script', 'NotebookManager.save_script',
162 'Auto-save a .py script everytime the .ipynb notebook is saved',
162 'Auto-save a .py script everytime the .ipynb notebook is saved',
163 'Do not auto-save .py scripts for every notebook'))
163 'Do not auto-save .py scripts for every notebook'))
164
164
165 # the flags that are specific to the frontend
165 # the flags that are specific to the frontend
166 # these must be scrubbed before being passed to the kernel,
166 # these must be scrubbed before being passed to the kernel,
167 # or it will raise an error on unrecognized flags
167 # or it will raise an error on unrecognized flags
168 notebook_flags = ['no-browser', 'no-mathjax', 'read-only', 'script', 'no-script']
168 notebook_flags = ['no-browser', 'no-mathjax', 'read-only', 'script', 'no-script']
169
169
170 aliases = dict(ipkernel_aliases)
170 aliases = dict(ipkernel_aliases)
171
171
172 aliases.update({
172 aliases.update({
173 'ip': 'NotebookApp.ip',
173 'ip': 'NotebookApp.ip',
174 'port': 'NotebookApp.port',
174 'port': 'NotebookApp.port',
175 'keyfile': 'NotebookApp.keyfile',
175 'keyfile': 'NotebookApp.keyfile',
176 'certfile': 'NotebookApp.certfile',
176 'certfile': 'NotebookApp.certfile',
177 'notebook-dir': 'NotebookManager.notebook_dir',
177 'notebook-dir': 'NotebookManager.notebook_dir',
178 })
178 })
179
179
180 # remove ipkernel flags that are singletons, and don't make sense in
180 # remove ipkernel flags that are singletons, and don't make sense in
181 # multi-kernel evironment:
181 # multi-kernel evironment:
182 aliases.pop('f', None)
182 aliases.pop('f', None)
183
183
184 notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile',
184 notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile',
185 u'notebook-dir']
185 u'notebook-dir']
186
186
187 #-----------------------------------------------------------------------------
187 #-----------------------------------------------------------------------------
188 # NotebookApp
188 # NotebookApp
189 #-----------------------------------------------------------------------------
189 #-----------------------------------------------------------------------------
190
190
191 class NotebookApp(BaseIPythonApplication):
191 class NotebookApp(BaseIPythonApplication):
192
192
193 name = 'ipython-notebook'
193 name = 'ipython-notebook'
194 default_config_file_name='ipython_notebook_config.py'
194 default_config_file_name='ipython_notebook_config.py'
195
195
196 description = """
196 description = """
197 The IPython HTML Notebook.
197 The IPython HTML Notebook.
198
198
199 This launches a Tornado based HTML Notebook Server that serves up an
199 This launches a Tornado based HTML Notebook Server that serves up an
200 HTML5/Javascript Notebook client.
200 HTML5/Javascript Notebook client.
201 """
201 """
202 examples = _examples
202 examples = _examples
203
203
204 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
204 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
205 MappingKernelManager, NotebookManager]
205 MappingKernelManager, NotebookManager]
206 flags = Dict(flags)
206 flags = Dict(flags)
207 aliases = Dict(aliases)
207 aliases = Dict(aliases)
208
208
209 kernel_argv = List(Unicode)
209 kernel_argv = List(Unicode)
210
210
211 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
211 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
212 default_value=logging.INFO,
212 default_value=logging.INFO,
213 config=True,
213 config=True,
214 help="Set the log level by value or name.")
214 help="Set the log level by value or name.")
215
215
216 # Network related information.
216 # Network related information.
217
217
218 ip = Unicode(LOCALHOST, config=True,
218 ip = Unicode(LOCALHOST, config=True,
219 help="The IP address the notebook server will listen on."
219 help="The IP address the notebook server will listen on."
220 )
220 )
221
221
222 def _ip_changed(self, name, old, new):
222 def _ip_changed(self, name, old, new):
223 if new == u'*': self.ip = u''
223 if new == u'*': self.ip = u''
224
224
225 port = Integer(8888, config=True,
225 port = Integer(8888, config=True,
226 help="The port the notebook server will listen on."
226 help="The port the notebook server will listen on."
227 )
227 )
228
228
229 certfile = Unicode(u'', config=True,
229 certfile = Unicode(u'', config=True,
230 help="""The full path to an SSL/TLS certificate file."""
230 help="""The full path to an SSL/TLS certificate file."""
231 )
231 )
232
232
233 keyfile = Unicode(u'', config=True,
233 keyfile = Unicode(u'', config=True,
234 help="""The full path to a private key file for usage with SSL/TLS."""
234 help="""The full path to a private key file for usage with SSL/TLS."""
235 )
235 )
236
236
237 password = Unicode(u'', config=True,
237 password = Unicode(u'', config=True,
238 help="""Hashed password to use for web authentication.
238 help="""Hashed password to use for web authentication.
239
239
240 To generate, type in a python/IPython shell:
240 To generate, type in a python/IPython shell:
241
241
242 from IPython.lib import passwd; passwd()
242 from IPython.lib import passwd; passwd()
243
243
244 The string should be of the form type:salt:hashed-password.
244 The string should be of the form type:salt:hashed-password.
245 """
245 """
246 )
246 )
247
247
248 open_browser = Bool(True, config=True,
248 open_browser = Bool(True, config=True,
249 help="Whether to open in a browser after starting.")
249 help="Whether to open in a browser after starting.")
250
250
251 read_only = Bool(False, config=True,
251 read_only = Bool(False, config=True,
252 help="Whether to prevent editing/execution of notebooks."
252 help="Whether to prevent editing/execution of notebooks."
253 )
253 )
254
254
255 webapp_settings = Dict(config=True,
255 webapp_settings = Dict(config=True,
256 help="Supply overrides for the tornado.web.Application that the "
256 help="Supply overrides for the tornado.web.Application that the "
257 "IPython notebook uses.")
257 "IPython notebook uses.")
258
258
259 enable_mathjax = Bool(True, config=True,
259 enable_mathjax = Bool(True, config=True,
260 help="""Whether to enable MathJax for typesetting math/TeX
260 help="""Whether to enable MathJax for typesetting math/TeX
261
261
262 MathJax is the javascript library IPython uses to render math/LaTeX. It is
262 MathJax is the javascript library IPython uses to render math/LaTeX. It is
263 very large, so you may want to disable it if you have a slow internet
263 very large, so you may want to disable it if you have a slow internet
264 connection, or for offline use of the notebook.
264 connection, or for offline use of the notebook.
265
265
266 When disabled, equations etc. will appear as their untransformed TeX source.
266 When disabled, equations etc. will appear as their untransformed TeX source.
267 """
267 """
268 )
268 )
269 def _enable_mathjax_changed(self, name, old, new):
269 def _enable_mathjax_changed(self, name, old, new):
270 """set mathjax url to empty if mathjax is disabled"""
270 """set mathjax url to empty if mathjax is disabled"""
271 if not new:
271 if not new:
272 self.mathjax_url = u''
272 self.mathjax_url = u''
273
273
274 mathjax_url = Unicode("", config=True,
274 mathjax_url = Unicode("", config=True,
275 help="""The url for MathJax.js."""
275 help="""The url for MathJax.js."""
276 )
276 )
277 def _mathjax_url_default(self):
277 def _mathjax_url_default(self):
278 if not self.enable_mathjax:
278 if not self.enable_mathjax:
279 return u''
279 return u''
280 static_path = self.webapp_settings.get("static_path", os.path.join(os.path.dirname(__file__), "static"))
280 static_path = self.webapp_settings.get("static_path", os.path.join(os.path.dirname(__file__), "static"))
281 if os.path.exists(os.path.join(static_path, 'mathjax', "MathJax.js")):
281 if os.path.exists(os.path.join(static_path, 'mathjax', "MathJax.js")):
282 self.log.info("Using local MathJax")
282 self.log.info("Using local MathJax")
283 return u"static/mathjax/MathJax.js"
283 return u"static/mathjax/MathJax.js"
284 else:
284 else:
285 self.log.info("Using MathJax from CDN")
285 self.log.info("Using MathJax from CDN")
286 return u"http://cdn.mathjax.org/mathjax/latest/MathJax.js"
286 return u"http://cdn.mathjax.org/mathjax/latest/MathJax.js"
287
287
288 def _mathjax_url_changed(self, name, old, new):
288 def _mathjax_url_changed(self, name, old, new):
289 if new and not self.enable_mathjax:
289 if new and not self.enable_mathjax:
290 # enable_mathjax=False overrides mathjax_url
290 # enable_mathjax=False overrides mathjax_url
291 self.mathjax_url = u''
291 self.mathjax_url = u''
292 else:
292 else:
293 self.log.info("Using MathJax: %s", new)
293 self.log.info("Using MathJax: %s", new)
294
294
295 def parse_command_line(self, argv=None):
295 def parse_command_line(self, argv=None):
296 super(NotebookApp, self).parse_command_line(argv)
296 super(NotebookApp, self).parse_command_line(argv)
297 if argv is None:
297 if argv is None:
298 argv = sys.argv[1:]
298 argv = sys.argv[1:]
299
299
300 # Scrub frontend-specific flags
300 # Scrub frontend-specific flags
301 self.kernel_argv = swallow_argv(argv, notebook_aliases, notebook_flags)
301 self.kernel_argv = swallow_argv(argv, notebook_aliases, notebook_flags)
302 # Kernel should inherit default config file from frontend
302 # Kernel should inherit default config file from frontend
303 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
303 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
304
304
305 def init_configurables(self):
305 def init_configurables(self):
306 # Don't let Qt or ZMQ swallow KeyboardInterupts.
307 signal.signal(signal.SIGINT, signal.SIG_DFL)
308
309 # force Session default to be secure
306 # force Session default to be secure
310 default_secure(self.config)
307 default_secure(self.config)
311 # Create a KernelManager and start a kernel.
308 # Create a KernelManager and start a kernel.
312 self.kernel_manager = MappingKernelManager(
309 self.kernel_manager = MappingKernelManager(
313 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
310 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
314 connection_dir = self.profile_dir.security_dir,
311 connection_dir = self.profile_dir.security_dir,
315 )
312 )
316 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
313 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
317 self.notebook_manager.list_notebooks()
314 self.notebook_manager.list_notebooks()
318
315
319 def init_logging(self):
316 def init_logging(self):
320 super(NotebookApp, self).init_logging()
317 super(NotebookApp, self).init_logging()
321 # This prevents double log messages because tornado use a root logger that
318 # This prevents double log messages because tornado use a root logger that
322 # self.log is a child of. The logging module dipatches log messages to a log
319 # self.log is a child of. The logging module dipatches log messages to a log
323 # and all of its ancenstors until propagate is set to False.
320 # and all of its ancenstors until propagate is set to False.
324 self.log.propagate = False
321 self.log.propagate = False
325
322
326 @catch_config_error
323 def init_webapp(self):
327 def initialize(self, argv=None):
324 """initialize tornado webapp and httpserver"""
328 super(NotebookApp, self).initialize(argv)
329 self.init_configurables()
330 self.web_app = NotebookWebApplication(
325 self.web_app = NotebookWebApplication(
331 self, self.kernel_manager, self.notebook_manager, self.log,
326 self, self.kernel_manager, self.notebook_manager, self.log,
332 self.webapp_settings
327 self.webapp_settings
333 )
328 )
334 if self.certfile:
329 if self.certfile:
335 ssl_options = dict(certfile=self.certfile)
330 ssl_options = dict(certfile=self.certfile)
336 if self.keyfile:
331 if self.keyfile:
337 ssl_options['keyfile'] = self.keyfile
332 ssl_options['keyfile'] = self.keyfile
338 else:
333 else:
339 ssl_options = None
334 ssl_options = None
340 self.web_app.password = self.password
335 self.web_app.password = self.password
341 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
336 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
342 if ssl_options is None and not self.ip:
337 if ssl_options is None and not self.ip and not (self.read_only and not self.password):
343 self.log.critical('WARNING: the notebook server is listening on all IP addresses '
338 self.log.critical('WARNING: the notebook server is listening on all IP addresses '
344 'but not using any encryption or authentication. This is highly '
339 'but not using any encryption or authentication. This is highly '
345 'insecure and not recommended.')
340 'insecure and not recommended.')
346
341
347 # Try random ports centered around the default.
342 # Try random ports centered around the default.
348 from random import randint
343 from random import randint
349 n = 50 # Max number of attempts, keep reasonably large.
344 n = 50 # Max number of attempts, keep reasonably large.
350 for port in range(self.port, self.port+5) + [self.port + randint(-2*n, 2*n) for i in range(n-5)]:
345 for port in range(self.port, self.port+5) + [self.port + randint(-2*n, 2*n) for i in range(n-5)]:
351 try:
346 try:
352 self.http_server.listen(port, self.ip)
347 self.http_server.listen(port, self.ip)
353 except socket.error, e:
348 except socket.error, e:
354 if e.errno != errno.EADDRINUSE:
349 if e.errno != errno.EADDRINUSE:
355 raise
350 raise
356 self.log.info('The port %i is already in use, trying another random port.' % port)
351 self.log.info('The port %i is already in use, trying another random port.' % port)
357 else:
352 else:
358 self.port = port
353 self.port = port
359 break
354 break
355
356 @catch_config_error
357 def initialize(self, argv=None):
358 super(NotebookApp, self).initialize(argv)
359 self.init_configurables()
360 self.init_webapp()
361
362 def cleanup_kernels(self):
363 """shutdown all kernels
364
365 The kernels will shutdown themselves when this process no longer exists,
366 but explicit shutdown allows the KernelManagers to cleanup the connection files.
367 """
368 self.log.info('Shutting down kernels')
369 km = self.kernel_manager
370 while km.kernel_ids:
371 km.kill_kernel(km.kernel_ids[0])
360
372
361 def start(self):
373 def start(self):
362 ip = self.ip if self.ip else '[all ip addresses on your system]'
374 ip = self.ip if self.ip else '[all ip addresses on your system]'
363 proto = 'https' if self.certfile else 'http'
375 proto = 'https' if self.certfile else 'http'
364 info = self.log.info
376 info = self.log.info
365 info("The IPython Notebook is running at: %s://%s:%i" %
377 info("The IPython Notebook is running at: %s://%s:%i" %
366 (proto, ip, self.port) )
378 (proto, ip, self.port) )
367 info("Use Control-C to stop this server and shut down all kernels.")
379 info("Use Control-C to stop this server and shut down all kernels.")
368
380
369 if self.open_browser:
381 if self.open_browser:
370 ip = self.ip or '127.0.0.1'
382 ip = self.ip or '127.0.0.1'
371 b = lambda : webbrowser.open("%s://%s:%i" % (proto, ip, self.port),
383 b = lambda : webbrowser.open("%s://%s:%i" % (proto, ip, self.port),
372 new=2)
384 new=2)
373 threading.Thread(target=b).start()
385 threading.Thread(target=b).start()
374
386 try:
375 ioloop.IOLoop.instance().start()
387 ioloop.IOLoop.instance().start()
388 except KeyboardInterrupt:
389 info("Interrupted...")
390 finally:
391 self.cleanup_kernels()
392
376
393
377 #-----------------------------------------------------------------------------
394 #-----------------------------------------------------------------------------
378 # Main entry point
395 # Main entry point
379 #-----------------------------------------------------------------------------
396 #-----------------------------------------------------------------------------
380
397
381 def launch_new_instance():
398 def launch_new_instance():
382 app = NotebookApp()
399 app = NotebookApp.instance()
383 app.initialize()
400 app.initialize()
384 app.start()
401 app.start()
385
402
General Comments 0
You need to be logged in to leave comments. Login now