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