##// END OF EJS Templates
look for mathjax in the custom static path if it's supplied.
Timo Paulssen -
Show More
@@ -1,378 +1,378 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
55 from IPython.config.application import catch_config_error
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 # the flags that are specific to the frontend
160 # the flags that are specific to the frontend
161 # these must be scrubbed before being passed to the kernel,
161 # these must be scrubbed before being passed to the kernel,
162 # or it will raise an error on unrecognized flags
162 # or it will raise an error on unrecognized flags
163 notebook_flags = ['no-browser', 'no-mathjax', 'read-only']
163 notebook_flags = ['no-browser', 'no-mathjax', 'read-only']
164
164
165 aliases = dict(ipkernel_aliases)
165 aliases = dict(ipkernel_aliases)
166
166
167 aliases.update({
167 aliases.update({
168 'ip': 'NotebookApp.ip',
168 'ip': 'NotebookApp.ip',
169 'port': 'NotebookApp.port',
169 'port': 'NotebookApp.port',
170 'keyfile': 'NotebookApp.keyfile',
170 'keyfile': 'NotebookApp.keyfile',
171 'certfile': 'NotebookApp.certfile',
171 'certfile': 'NotebookApp.certfile',
172 'notebook-dir': 'NotebookManager.notebook_dir',
172 'notebook-dir': 'NotebookManager.notebook_dir',
173 })
173 })
174
174
175 # remove ipkernel flags that are singletons, and don't make sense in
175 # remove ipkernel flags that are singletons, and don't make sense in
176 # multi-kernel evironment:
176 # multi-kernel evironment:
177 aliases.pop('f', None)
177 aliases.pop('f', None)
178
178
179 notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile',
179 notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile',
180 u'notebook-dir']
180 u'notebook-dir']
181
181
182 #-----------------------------------------------------------------------------
182 #-----------------------------------------------------------------------------
183 # NotebookApp
183 # NotebookApp
184 #-----------------------------------------------------------------------------
184 #-----------------------------------------------------------------------------
185
185
186 class NotebookApp(BaseIPythonApplication):
186 class NotebookApp(BaseIPythonApplication):
187
187
188 name = 'ipython-notebook'
188 name = 'ipython-notebook'
189 default_config_file_name='ipython_notebook_config.py'
189 default_config_file_name='ipython_notebook_config.py'
190
190
191 description = """
191 description = """
192 The IPython HTML Notebook.
192 The IPython HTML Notebook.
193
193
194 This launches a Tornado based HTML Notebook Server that serves up an
194 This launches a Tornado based HTML Notebook Server that serves up an
195 HTML5/Javascript Notebook client.
195 HTML5/Javascript Notebook client.
196 """
196 """
197 examples = _examples
197 examples = _examples
198
198
199 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
199 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
200 MappingKernelManager, NotebookManager]
200 MappingKernelManager, NotebookManager]
201 flags = Dict(flags)
201 flags = Dict(flags)
202 aliases = Dict(aliases)
202 aliases = Dict(aliases)
203
203
204 kernel_argv = List(Unicode)
204 kernel_argv = List(Unicode)
205
205
206 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
206 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
207 default_value=logging.INFO,
207 default_value=logging.INFO,
208 config=True,
208 config=True,
209 help="Set the log level by value or name.")
209 help="Set the log level by value or name.")
210
210
211 # Network related information.
211 # Network related information.
212
212
213 ip = Unicode(LOCALHOST, config=True,
213 ip = Unicode(LOCALHOST, config=True,
214 help="The IP address the notebook server will listen on."
214 help="The IP address the notebook server will listen on."
215 )
215 )
216
216
217 def _ip_changed(self, name, old, new):
217 def _ip_changed(self, name, old, new):
218 if new == u'*': self.ip = u''
218 if new == u'*': self.ip = u''
219
219
220 port = Integer(8888, config=True,
220 port = Integer(8888, config=True,
221 help="The port the notebook server will listen on."
221 help="The port the notebook server will listen on."
222 )
222 )
223
223
224 certfile = Unicode(u'', config=True,
224 certfile = Unicode(u'', config=True,
225 help="""The full path to an SSL/TLS certificate file."""
225 help="""The full path to an SSL/TLS certificate file."""
226 )
226 )
227
227
228 keyfile = Unicode(u'', config=True,
228 keyfile = Unicode(u'', config=True,
229 help="""The full path to a private key file for usage with SSL/TLS."""
229 help="""The full path to a private key file for usage with SSL/TLS."""
230 )
230 )
231
231
232 password = Unicode(u'', config=True,
232 password = Unicode(u'', config=True,
233 help="""Hashed password to use for web authentication.
233 help="""Hashed password to use for web authentication.
234
234
235 To generate, type in a python/IPython shell:
235 To generate, type in a python/IPython shell:
236
236
237 from IPython.lib import passwd; passwd()
237 from IPython.lib import passwd; passwd()
238
238
239 The string should be of the form type:salt:hashed-password.
239 The string should be of the form type:salt:hashed-password.
240 """
240 """
241 )
241 )
242
242
243 open_browser = Bool(True, config=True,
243 open_browser = Bool(True, config=True,
244 help="Whether to open in a browser after starting.")
244 help="Whether to open in a browser after starting.")
245
245
246 read_only = Bool(False, config=True,
246 read_only = Bool(False, config=True,
247 help="Whether to prevent editing/execution of notebooks."
247 help="Whether to prevent editing/execution of notebooks."
248 )
248 )
249
249
250 webapp_settings = Dict(config=True,
250 webapp_settings = Dict(config=True,
251 help="Supply overrides for the tornado.web.Application that the "
251 help="Supply overrides for the tornado.web.Application that the "
252 "IPython notebook uses.")
252 "IPython notebook uses.")
253
253
254 enable_mathjax = Bool(True, config=True,
254 enable_mathjax = Bool(True, config=True,
255 help="""Whether to enable MathJax for typesetting math/TeX
255 help="""Whether to enable MathJax for typesetting math/TeX
256
256
257 MathJax is the javascript library IPython uses to render math/LaTeX. It is
257 MathJax is the javascript library IPython uses to render math/LaTeX. It is
258 very large, so you may want to disable it if you have a slow internet
258 very large, so you may want to disable it if you have a slow internet
259 connection, or for offline use of the notebook.
259 connection, or for offline use of the notebook.
260
260
261 When disabled, equations etc. will appear as their untransformed TeX source.
261 When disabled, equations etc. will appear as their untransformed TeX source.
262 """
262 """
263 )
263 )
264 def _enable_mathjax_changed(self, name, old, new):
264 def _enable_mathjax_changed(self, name, old, new):
265 """set mathjax url to empty if mathjax is disabled"""
265 """set mathjax url to empty if mathjax is disabled"""
266 if not new:
266 if not new:
267 self.mathjax_url = u''
267 self.mathjax_url = u''
268
268
269 mathjax_url = Unicode("", config=True,
269 mathjax_url = Unicode("", config=True,
270 help="""The url for MathJax.js."""
270 help="""The url for MathJax.js."""
271 )
271 )
272 def _mathjax_url_default(self):
272 def _mathjax_url_default(self):
273 if not self.enable_mathjax:
273 if not self.enable_mathjax:
274 return u''
274 return u''
275 static_path = os.path.join(os.path.dirname(__file__), "static")
275 static_path = self.webapp_settings.get("static_path", os.path.join(os.path.dirname(__file__), "static"))
276 if os.path.exists(os.path.join(static_path, 'mathjax', "MathJax.js")):
276 if os.path.exists(os.path.join(static_path, 'mathjax', "MathJax.js")):
277 self.log.info("Using local MathJax")
277 self.log.info("Using local MathJax")
278 return u"static/mathjax/MathJax.js"
278 return u"static/mathjax/MathJax.js"
279 else:
279 else:
280 self.log.info("Using MathJax from CDN")
280 self.log.info("Using MathJax from CDN")
281 return u"http://cdn.mathjax.org/mathjax/latest/MathJax.js"
281 return u"http://cdn.mathjax.org/mathjax/latest/MathJax.js"
282
282
283 def _mathjax_url_changed(self, name, old, new):
283 def _mathjax_url_changed(self, name, old, new):
284 if new and not self.enable_mathjax:
284 if new and not self.enable_mathjax:
285 # enable_mathjax=False overrides mathjax_url
285 # enable_mathjax=False overrides mathjax_url
286 self.mathjax_url = u''
286 self.mathjax_url = u''
287 else:
287 else:
288 self.log.info("Using MathJax: %s", new)
288 self.log.info("Using MathJax: %s", new)
289
289
290 def parse_command_line(self, argv=None):
290 def parse_command_line(self, argv=None):
291 super(NotebookApp, self).parse_command_line(argv)
291 super(NotebookApp, self).parse_command_line(argv)
292 if argv is None:
292 if argv is None:
293 argv = sys.argv[1:]
293 argv = sys.argv[1:]
294
294
295 # Scrub frontend-specific flags
295 # Scrub frontend-specific flags
296 self.kernel_argv = swallow_argv(argv, notebook_aliases, notebook_flags)
296 self.kernel_argv = swallow_argv(argv, notebook_aliases, notebook_flags)
297 # Kernel should inherit default config file from frontend
297 # Kernel should inherit default config file from frontend
298 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
298 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
299
299
300 def init_configurables(self):
300 def init_configurables(self):
301 # Don't let Qt or ZMQ swallow KeyboardInterupts.
301 # Don't let Qt or ZMQ swallow KeyboardInterupts.
302 signal.signal(signal.SIGINT, signal.SIG_DFL)
302 signal.signal(signal.SIGINT, signal.SIG_DFL)
303
303
304 # force Session default to be secure
304 # force Session default to be secure
305 default_secure(self.config)
305 default_secure(self.config)
306 # Create a KernelManager and start a kernel.
306 # Create a KernelManager and start a kernel.
307 self.kernel_manager = MappingKernelManager(
307 self.kernel_manager = MappingKernelManager(
308 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
308 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
309 connection_dir = self.profile_dir.security_dir,
309 connection_dir = self.profile_dir.security_dir,
310 )
310 )
311 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
311 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
312 self.notebook_manager.list_notebooks()
312 self.notebook_manager.list_notebooks()
313
313
314 def init_logging(self):
314 def init_logging(self):
315 super(NotebookApp, self).init_logging()
315 super(NotebookApp, self).init_logging()
316 # This prevents double log messages because tornado use a root logger that
316 # This prevents double log messages because tornado use a root logger that
317 # self.log is a child of. The logging module dipatches log messages to a log
317 # self.log is a child of. The logging module dipatches log messages to a log
318 # and all of its ancenstors until propagate is set to False.
318 # and all of its ancenstors until propagate is set to False.
319 self.log.propagate = False
319 self.log.propagate = False
320
320
321 @catch_config_error
321 @catch_config_error
322 def initialize(self, argv=None):
322 def initialize(self, argv=None):
323 super(NotebookApp, self).initialize(argv)
323 super(NotebookApp, self).initialize(argv)
324 self.init_configurables()
324 self.init_configurables()
325 self.web_app = NotebookWebApplication(
325 self.web_app = NotebookWebApplication(
326 self, self.kernel_manager, self.notebook_manager, self.log,
326 self, self.kernel_manager, self.notebook_manager, self.log,
327 self.webapp_settings
327 self.webapp_settings
328 )
328 )
329 if self.certfile:
329 if self.certfile:
330 ssl_options = dict(certfile=self.certfile)
330 ssl_options = dict(certfile=self.certfile)
331 if self.keyfile:
331 if self.keyfile:
332 ssl_options['keyfile'] = self.keyfile
332 ssl_options['keyfile'] = self.keyfile
333 else:
333 else:
334 ssl_options = None
334 ssl_options = None
335 self.web_app.password = self.password
335 self.web_app.password = self.password
336 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)
337 if ssl_options is None and not self.ip:
337 if ssl_options is None and not self.ip:
338 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 '
339 'but not using any encryption or authentication. This is highly '
339 'but not using any encryption or authentication. This is highly '
340 'insecure and not recommended.')
340 'insecure and not recommended.')
341
341
342 # Try random ports centered around the default.
342 # Try random ports centered around the default.
343 from random import randint
343 from random import randint
344 n = 50 # Max number of attempts, keep reasonably large.
344 n = 50 # Max number of attempts, keep reasonably large.
345 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)]:
346 try:
346 try:
347 self.http_server.listen(port, self.ip)
347 self.http_server.listen(port, self.ip)
348 except socket.error, e:
348 except socket.error, e:
349 if e.errno != errno.EADDRINUSE:
349 if e.errno != errno.EADDRINUSE:
350 raise
350 raise
351 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)
352 else:
352 else:
353 self.port = port
353 self.port = port
354 break
354 break
355
355
356 def start(self):
356 def start(self):
357 ip = self.ip if self.ip else '[all ip addresses on your system]'
357 ip = self.ip if self.ip else '[all ip addresses on your system]'
358 proto = 'https' if self.certfile else 'http'
358 proto = 'https' if self.certfile else 'http'
359 self.log.info("The IPython Notebook is running at: %s://%s:%i" % (proto,
359 self.log.info("The IPython Notebook is running at: %s://%s:%i" % (proto,
360 ip,
360 ip,
361 self.port))
361 self.port))
362 if self.open_browser:
362 if self.open_browser:
363 ip = self.ip or '127.0.0.1'
363 ip = self.ip or '127.0.0.1'
364 b = lambda : webbrowser.open("%s://%s:%i" % (proto, ip, self.port),
364 b = lambda : webbrowser.open("%s://%s:%i" % (proto, ip, self.port),
365 new=2)
365 new=2)
366 threading.Thread(target=b).start()
366 threading.Thread(target=b).start()
367
367
368 ioloop.IOLoop.instance().start()
368 ioloop.IOLoop.instance().start()
369
369
370 #-----------------------------------------------------------------------------
370 #-----------------------------------------------------------------------------
371 # Main entry point
371 # Main entry point
372 #-----------------------------------------------------------------------------
372 #-----------------------------------------------------------------------------
373
373
374 def launch_new_instance():
374 def launch_new_instance():
375 app = NotebookApp()
375 app = NotebookApp()
376 app.initialize()
376 app.initialize()
377 app.start()
377 app.start()
378
378
General Comments 0
You need to be logged in to leave comments. Login now