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