##// END OF EJS Templates
cleanup IPython handler settings...
MinRK -
Show More
@@ -103,7 +103,7 if tornado.version_info <= (2,1,1):
103 103
104 104 @decorator
105 105 def not_if_readonly(f, self, *args, **kwargs):
106 if self.application.read_only:
106 if self.settings.get('read_only', False):
107 107 raise web.HTTPError(403, "Notebook server is read-only")
108 108 else:
109 109 return f(self, *args, **kwargs)
@@ -120,13 +120,13 def authenticate_unless_readonly(f, self, *args, **kwargs):
120 120 def auth_f(self, *args, **kwargs):
121 121 return f(self, *args, **kwargs)
122 122
123 if self.application.read_only:
123 if self.settings.get('read_only', False):
124 124 return f(self, *args, **kwargs)
125 125 else:
126 126 return auth_f(self, *args, **kwargs)
127 127
128 128 def urljoin(*pieces):
129 """Join componenet of url into a relative url
129 """Join components of url into a relative url
130 130
131 131 Use to prevent double slash when joining subpath
132 132 """
@@ -147,19 +147,31 class RequestHandler(web.RequestHandler):
147 147 class AuthenticatedHandler(RequestHandler):
148 148 """A RequestHandler with an authenticated user."""
149 149
150 def clear_login_cookie(self):
151 self.clear_cookie(self.cookie_name)
152
150 153 def get_current_user(self):
151 user_id = self.get_secure_cookie(self.settings['cookie_name'])
154 user_id = self.get_secure_cookie(self.cookie_name)
152 155 # For now the user_id should not return empty, but it could eventually
153 156 if user_id == '':
154 157 user_id = 'anonymous'
155 158 if user_id is None:
156 159 # prevent extra Invalid cookie sig warnings:
157 self.clear_cookie(self.settings['cookie_name'])
158 if not self.application.password and not self.application.read_only:
160 self.clear_login_cookie()
161 if not self.read_only and not self.login_available:
159 162 user_id = 'anonymous'
160 163 return user_id
161 164
162 165 @property
166 def cookie_name(self):
167 return self.settings.get('cookie_name', '')
168
169 @property
170 def password(self):
171 """our password"""
172 return self.settings.get('password', '')
173
174 @property
163 175 def logged_in(self):
164 176 """Is a user currently logged in?
165 177
@@ -175,20 +187,35 class AuthenticatedHandler(RequestHandler):
175 187 whether the user is already logged in or not.
176 188
177 189 """
178 return bool(self.application.password)
190 return bool(self.settings.get('password', ''))
179 191
180 192 @property
181 193 def read_only(self):
182 194 """Is the notebook read-only?
183 195
184 196 """
185 return self.application.read_only
197 return self.settings.get('read_only', False)
198
186 199
200 class IPythonHandler(AuthenticatedHandler):
201 """IPython-specific extensions to authenticated handling
202
203 Mostly property shortcuts to IPython-specific settings.
204 """
205
206 @property
207 def config(self):
208 return self.settings.get('config', None)
209
187 210 @property
188 211 def use_less(self):
189 212 """Use less instead of css in templates"""
190 return self.application.use_less
191
213 return self.settings.get('use_less', False)
214
215 #---------------------------------------------------------------
216 # URLs
217 #---------------------------------------------------------------
218
192 219 @property
193 220 def ws_url(self):
194 221 """websocket url matching the current request
@@ -197,13 +224,69 class AuthenticatedHandler(RequestHandler):
197 224 ws[s]://host[:port]
198 225 """
199 226 proto = self.request.protocol.replace('http', 'ws')
200 host = self.application.ipython_app.websocket_host # default to config value
227 host = self.settings.get('websocket_host', '')
228 # default to config value
201 229 if host == '':
202 230 host = self.request.host # get from request
203 231 return "%s://%s" % (proto, host)
204
232
233 @property
234 def mathjax_url(self):
235 return self.settings.get('mathjax_url', '')
236
237 @property
238 def base_project_url(self):
239 return self.settings.get('base_project_url', '/')
240
241 @property
242 def base_kernel_url(self):
243 return self.settings.get('base_kernel_url', '/')
244
245 #---------------------------------------------------------------
246 # Manager objects
247 #---------------------------------------------------------------
248
249 @property
250 def kernel_manager(self):
251 return self.settings['kernel_manager']
252
253 @property
254 def notebook_manager(self):
255 return self.settings['notebook_manager']
256
257 @property
258 def cluster_manager(self):
259 return self.settings['cluster_manager']
260
261 @property
262 def project(self):
263 return self.notebook_manager.notebook_dir
264
265 #---------------------------------------------------------------
266 # template rendering
267 #---------------------------------------------------------------
268
269 def get_template(self, name):
270 """Return the jinja template object for a given name"""
271 return self.settings['jinja2_env'].get_template(name)
272
273 def render_template(self, name, **ns):
274 ns.update(self.template_namespace)
275 template = self.get_template(name)
276 return template.render(**ns)
277
278 @property
279 def template_namespace(self):
280 return dict(
281 base_project_url=self.base_project_url,
282 base_kernel_url=self.base_kernel_url,
283 read_only=self.read_only,
284 logged_in=self.logged_in,
285 login_available=self.login_available,
286 use_less=self.use_less,
287 )
205 288
206 class AuthenticatedFileHandler(AuthenticatedHandler, web.StaticFileHandler):
289 class AuthenticatedFileHandler(IPythonHandler, web.StaticFileHandler):
207 290 """static files should only be accessible when logged in"""
208 291
209 292 @authenticate_unless_readonly
@@ -211,125 +294,89 class AuthenticatedFileHandler(AuthenticatedHandler, web.StaticFileHandler):
211 294 return web.StaticFileHandler.get(self, path)
212 295
213 296
214 class ProjectDashboardHandler(AuthenticatedHandler):
297 class ProjectDashboardHandler(IPythonHandler):
215 298
216 299 @authenticate_unless_readonly
217 300 def get(self):
218 nbm = self.application.notebook_manager
219 project = nbm.notebook_dir
220 template = self.application.jinja2_env.get_template('projectdashboard.html')
221 self.write( template.render(
222 project=project,
223 project_component=project.split('/'),
224 base_project_url=self.application.ipython_app.base_project_url,
225 base_kernel_url=self.application.ipython_app.base_kernel_url,
226 read_only=self.read_only,
227 logged_in=self.logged_in,
228 use_less=self.use_less,
229 login_available=self.login_available))
301 self.write(self.render_template('projectdashboard.html',
302 project=self.project,
303 project_component=self.project.split('/'),
304 ))
230 305
231 306
232 class LoginHandler(AuthenticatedHandler):
307 class LoginHandler(IPythonHandler):
233 308
234 def _render(self, message=None):
235 template = self.application.jinja2_env.get_template('login.html')
236 self.write( template.render(
237 next=url_escape(self.get_argument('next', default=self.application.ipython_app.base_project_url)),
238 read_only=self.read_only,
239 logged_in=self.logged_in,
240 login_available=self.login_available,
241 base_project_url=self.application.ipython_app.base_project_url,
242 message=message
309 def _render(self, message=None):
310 self.write(self.render_template('login.html',
311 next=url_escape(self.get_argument('next', default=self.base_project_url)),
312 message=message,
243 313 ))
244 314
245 315 def get(self):
246 316 if self.current_user:
247 self.redirect(self.get_argument('next', default=self.application.ipython_app.base_project_url))
317 self.redirect(self.get_argument('next', default=self.base_project_url))
248 318 else:
249 319 self._render()
250 320
251 321 def post(self):
252 322 pwd = self.get_argument('password', default=u'')
253 if self.application.password:
254 if passwd_check(self.application.password, pwd):
255 self.set_secure_cookie(self.settings['cookie_name'], str(uuid.uuid4()))
323 if self.login_available:
324 if passwd_check(self.password, pwd):
325 self.set_secure_cookie(self.cookie_name, str(uuid.uuid4()))
256 326 else:
257 327 self._render(message={'error': 'Invalid password'})
258 328 return
259 329
260 self.redirect(self.get_argument('next', default=self.application.ipython_app.base_project_url))
330 self.redirect(self.get_argument('next', default=self.base_project_url))
261 331
262 332
263 class LogoutHandler(AuthenticatedHandler):
333 class LogoutHandler(IPythonHandler):
264 334
265 335 def get(self):
266 self.clear_cookie(self.settings['cookie_name'])
336 self.clear_login_cookie()
267 337 if self.login_available:
268 338 message = {'info': 'Successfully logged out.'}
269 339 else:
270 340 message = {'warning': 'Cannot log out. Notebook authentication '
271 341 'is disabled.'}
272 template = self.application.jinja2_env.get_template('logout.html')
273 self.write( template.render(
274 read_only=self.read_only,
275 logged_in=self.logged_in,
276 login_available=self.login_available,
277 base_project_url=self.application.ipython_app.base_project_url,
342 self.write(self.render_template('logout.html',
278 343 message=message))
279 344
280 345
281 class NewHandler(AuthenticatedHandler):
346 class NewHandler(IPythonHandler):
282 347
283 348 @web.authenticated
284 349 def get(self):
285 nbm = self.application.notebook_manager
286 project = nbm.notebook_dir
287 notebook_id = nbm.new_notebook()
288 self.redirect('/'+urljoin(self.application.ipython_app.base_project_url, notebook_id))
350 notebook_id = self.notebook_manager.new_notebook()
351 self.redirect('/' + urljoin(self.base_project_url, notebook_id))
289 352
290 class NamedNotebookHandler(AuthenticatedHandler):
353 class NamedNotebookHandler(IPythonHandler):
291 354
292 355 @authenticate_unless_readonly
293 356 def get(self, notebook_id):
294 nbm = self.application.notebook_manager
295 project = nbm.notebook_dir
357 nbm = self.notebook_manager
296 358 if not nbm.notebook_exists(notebook_id):
297 359 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
298 template = self.application.jinja2_env.get_template('notebook.html')
299 self.write( template.render(
300 project=project,
360 self.write(self.render_template('notebook.html',
361 project=self.project,
301 362 notebook_id=notebook_id,
302 base_project_url=self.application.ipython_app.base_project_url,
303 base_kernel_url=self.application.ipython_app.base_kernel_url,
304 363 kill_kernel=False,
305 read_only=self.read_only,
306 logged_in=self.logged_in,
307 login_available=self.login_available,
308 mathjax_url=self.application.ipython_app.mathjax_url,
309 use_less=self.use_less
364 mathjax_url=self.mathjax_url,
310 365 )
311 366 )
312 367
313 368
314 class PrintNotebookHandler(AuthenticatedHandler):
369 class PrintNotebookHandler(IPythonHandler):
315 370
316 371 @authenticate_unless_readonly
317 372 def get(self, notebook_id):
318 nbm = self.application.notebook_manager
319 project = nbm.notebook_dir
320 if not nbm.notebook_exists(notebook_id):
373 if not self.notebook_manager.notebook_exists(notebook_id):
321 374 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
322 template = self.application.jinja2_env.get_template('printnotebook.html')
323 self.write( template.render(
324 project=project,
375 self.write( self.render_template('printnotebook.html',
376 project=self.project,
325 377 notebook_id=notebook_id,
326 base_project_url=self.application.ipython_app.base_project_url,
327 base_kernel_url=self.application.ipython_app.base_kernel_url,
328 378 kill_kernel=False,
329 read_only=self.read_only,
330 logged_in=self.logged_in,
331 login_available=self.login_available,
332 mathjax_url=self.application.ipython_app.mathjax_url,
379 mathjax_url=self.mathjax_url,
333 380 ))
334 381
335 382 #-----------------------------------------------------------------------------
@@ -337,17 +384,17 class PrintNotebookHandler(AuthenticatedHandler):
337 384 #-----------------------------------------------------------------------------
338 385
339 386
340 class MainKernelHandler(AuthenticatedHandler):
387 class MainKernelHandler(IPythonHandler):
341 388
342 389 @web.authenticated
343 390 def get(self):
344 km = self.application.kernel_manager
391 km = self.kernel_manager
345 392 self.finish(jsonapi.dumps(km.list_kernel_ids()))
346 393
347 394 @web.authenticated
348 395 def post(self):
349 km = self.application.kernel_manager
350 nbm = self.application.notebook_manager
396 km = self.kernel_manager
397 nbm = self.notebook_manager
351 398 notebook_id = self.get_argument('notebook', default=None)
352 399 kernel_id = km.start_kernel(notebook_id, cwd=nbm.notebook_dir)
353 400 data = {'ws_url':self.ws_url,'kernel_id':kernel_id}
@@ -355,23 +402,23 class MainKernelHandler(AuthenticatedHandler):
355 402 self.finish(jsonapi.dumps(data))
356 403
357 404
358 class KernelHandler(AuthenticatedHandler):
405 class KernelHandler(IPythonHandler):
359 406
360 407 SUPPORTED_METHODS = ('DELETE')
361 408
362 409 @web.authenticated
363 410 def delete(self, kernel_id):
364 km = self.application.kernel_manager
411 km = self.kernel_manager
365 412 km.shutdown_kernel(kernel_id)
366 413 self.set_status(204)
367 414 self.finish()
368 415
369 416
370 class KernelActionHandler(AuthenticatedHandler):
417 class KernelActionHandler(IPythonHandler):
371 418
372 419 @web.authenticated
373 420 def post(self, kernel_id, action):
374 km = self.application.kernel_manager
421 km = self.kernel_manager
375 422 if action == 'interrupt':
376 423 km.interrupt_kernel(kernel_id)
377 424 self.set_status(204)
@@ -413,7 +460,7 class ZMQStreamHandler(websocket.WebSocketHandler):
413 460 try:
414 461 msg = self._reserialize_reply(msg_list)
415 462 except Exception:
416 self.application.log.critical("Malformed message: %r" % msg_list, exc_info=True)
463 logging.critical("Malformed message: %r" % msg_list, exc_info=True)
417 464 else:
418 465 self.write_message(msg)
419 466
@@ -426,26 +473,14 class ZMQStreamHandler(websocket.WebSocketHandler):
426 473 return True
427 474
428 475
429 class AuthenticatedZMQStreamHandler(ZMQStreamHandler):
476 class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):
430 477
431 478 def open(self, kernel_id):
432 479 self.kernel_id = kernel_id.decode('ascii')
433 try:
434 cfg = self.application.config
435 except AttributeError:
436 # protect from the case where this is run from something other than
437 # the notebook app:
438 cfg = None
439 self.session = Session(config=cfg)
480 self.session = Session(config=self.config)
440 481 self.save_on_message = self.on_message
441 482 self.on_message = self.on_first_message
442 483
443 def get_current_user(self):
444 user_id = self.get_secure_cookie(self.settings['cookie_name'])
445 if user_id == '' or (user_id is None and not self.application.password):
446 user_id = 'anonymous'
447 return user_id
448
449 484 def _inject_cookie_message(self, msg):
450 485 """Inject the first message, which is the document cookie,
451 486 for authentication."""
@@ -477,7 +512,7 class IOPubHandler(AuthenticatedZMQStreamHandler):
477 512 except web.HTTPError:
478 513 self.close()
479 514 return
480 km = self.application.kernel_manager
515 km = self.kernel_manager
481 516 kernel_id = self.kernel_id
482 517 km.add_restart_callback(kernel_id, self.on_kernel_restarted)
483 518 km.add_restart_callback(kernel_id, self.on_restart_failed, 'dead')
@@ -513,7 +548,7 class IOPubHandler(AuthenticatedZMQStreamHandler):
513 548 # This method can be called twice, once by self.kernel_died and once
514 549 # from the WebSocket close event. If the WebSocket connection is
515 550 # closed before the ZMQ streams are setup, they could be None.
516 km = self.application.kernel_manager
551 km = self.kernel_manager
517 552 if self.kernel_id in km:
518 553 km.remove_restart_callback(
519 554 self.kernel_id, self.on_kernel_restarted,
@@ -527,6 +562,10 class IOPubHandler(AuthenticatedZMQStreamHandler):
527 562
528 563
529 564 class ShellHandler(AuthenticatedZMQStreamHandler):
565
566 @property
567 def max_msg_size(self):
568 return self.settings.get('max_msg_size', 65535)
530 569
531 570 def initialize(self, *args, **kwargs):
532 571 self.shell_stream = None
@@ -537,8 +576,7 class ShellHandler(AuthenticatedZMQStreamHandler):
537 576 except web.HTTPError:
538 577 self.close()
539 578 return
540 km = self.application.kernel_manager
541 self.max_msg_size = km.max_msg_size
579 km = self.kernel_manager
542 580 kernel_id = self.kernel_id
543 581 try:
544 582 self.shell_stream = km.connect_shell(kernel_id)
@@ -566,26 +604,26 class ShellHandler(AuthenticatedZMQStreamHandler):
566 604 # Notebook web service handlers
567 605 #-----------------------------------------------------------------------------
568 606
569 class NotebookRedirectHandler(AuthenticatedHandler):
607 class NotebookRedirectHandler(IPythonHandler):
570 608
571 609 @authenticate_unless_readonly
572 610 def get(self, notebook_name):
573 app = self.application
574 611 # strip trailing .ipynb:
575 612 notebook_name = os.path.splitext(notebook_name)[0]
576 notebook_id = app.notebook_manager.rev_mapping.get(notebook_name, '')
613 notebook_id = self.notebook_manager.rev_mapping.get(notebook_name, '')
577 614 if notebook_id:
578 615 url = self.settings.get('base_project_url', '/') + notebook_id
579 616 return self.redirect(url)
580 617 else:
581 618 raise HTTPError(404)
582 619
583 class NotebookRootHandler(AuthenticatedHandler):
620
621 class NotebookRootHandler(IPythonHandler):
584 622
585 623 @authenticate_unless_readonly
586 624 def get(self):
587 nbm = self.application.notebook_manager
588 km = self.application.kernel_manager
625 nbm = self.notebook_manager
626 km = self.kernel_manager
589 627 files = nbm.list_notebooks()
590 628 for f in files :
591 629 f['kernel_id'] = km.kernel_for_notebook(f['notebook_id'])
@@ -593,7 +631,7 class NotebookRootHandler(AuthenticatedHandler):
593 631
594 632 @web.authenticated
595 633 def post(self):
596 nbm = self.application.notebook_manager
634 nbm = self.notebook_manager
597 635 body = self.request.body.strip()
598 636 format = self.get_argument('format', default='json')
599 637 name = self.get_argument('name', default=None)
@@ -605,13 +643,13 class NotebookRootHandler(AuthenticatedHandler):
605 643 self.finish(jsonapi.dumps(notebook_id))
606 644
607 645
608 class NotebookHandler(AuthenticatedHandler):
646 class NotebookHandler(IPythonHandler):
609 647
610 648 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
611 649
612 650 @authenticate_unless_readonly
613 651 def get(self, notebook_id):
614 nbm = self.application.notebook_manager
652 nbm = self.notebook_manager
615 653 format = self.get_argument('format', default='json')
616 654 last_mod, name, data = nbm.get_notebook(notebook_id, format)
617 655
@@ -626,7 +664,7 class NotebookHandler(AuthenticatedHandler):
626 664
627 665 @web.authenticated
628 666 def put(self, notebook_id):
629 nbm = self.application.notebook_manager
667 nbm = self.notebook_manager
630 668 format = self.get_argument('format', default='json')
631 669 name = self.get_argument('name', default=None)
632 670 nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
@@ -635,20 +673,17 class NotebookHandler(AuthenticatedHandler):
635 673
636 674 @web.authenticated
637 675 def delete(self, notebook_id):
638 nbm = self.application.notebook_manager
639 nbm.delete_notebook(notebook_id)
676 self.notebook_manager.delete_notebook(notebook_id)
640 677 self.set_status(204)
641 678 self.finish()
642 679
643 680
644 class NotebookCopyHandler(AuthenticatedHandler):
681 class NotebookCopyHandler(IPythonHandler):
645 682
646 683 @web.authenticated
647 684 def get(self, notebook_id):
648 nbm = self.application.notebook_manager
649 project = nbm.notebook_dir
650 notebook_id = nbm.copy_notebook(notebook_id)
651 self.redirect('/'+urljoin(self.application.ipython_app.base_project_url, notebook_id))
685 notebook_id = self.notebook_manager.copy_notebook(notebook_id)
686 self.redirect('/'+urljoin(self.base_project_url, notebook_id))
652 687
653 688
654 689 #-----------------------------------------------------------------------------
@@ -656,33 +691,31 class NotebookCopyHandler(AuthenticatedHandler):
656 691 #-----------------------------------------------------------------------------
657 692
658 693
659 class MainClusterHandler(AuthenticatedHandler):
694 class MainClusterHandler(IPythonHandler):
660 695
661 696 @web.authenticated
662 697 def get(self):
663 cm = self.application.cluster_manager
664 self.finish(jsonapi.dumps(cm.list_profiles()))
698 self.finish(jsonapi.dumps(self.cluster_manager.list_profiles()))
665 699
666 700
667 class ClusterProfileHandler(AuthenticatedHandler):
701 class ClusterProfileHandler(IPythonHandler):
668 702
669 703 @web.authenticated
670 704 def get(self, profile):
671 cm = self.application.cluster_manager
672 self.finish(jsonapi.dumps(cm.profile_info(profile)))
705 self.finish(jsonapi.dumps(self.cluster_manager.profile_info(profile)))
673 706
674 707
675 class ClusterActionHandler(AuthenticatedHandler):
708 class ClusterActionHandler(IPythonHandler):
676 709
677 710 @web.authenticated
678 711 def post(self, profile, action):
679 cm = self.application.cluster_manager
712 cm = self.cluster_manager
680 713 if action == 'start':
681 714 n = self.get_argument('n',default=None)
682 715 if n is None:
683 716 data = cm.start_cluster(profile)
684 717 else:
685 data = cm.start_cluster(profile,int(n))
718 data = cm.start_cluster(profile, int(n))
686 719 if action == 'stop':
687 720 data = cm.stop_cluster(profile)
688 721 self.finish(jsonapi.dumps(data))
@@ -693,7 +726,7 class ClusterActionHandler(AuthenticatedHandler):
693 726 #-----------------------------------------------------------------------------
694 727
695 728
696 class RSTHandler(AuthenticatedHandler):
729 class RSTHandler(IPythonHandler):
697 730
698 731 @web.authenticated
699 732 def post(self):
@@ -29,18 +29,13 from IPython.utils.traitlets import (
29 29
30 30
31 31 class MappingKernelManager(MultiKernelManager):
32 """A KernelManager that handles notebok mapping and HTTP error handling"""
32 """A KernelManager that handles notebook mapping and HTTP error handling"""
33 33
34 34 def _kernel_manager_class_default(self):
35 35 return "IPython.kernel.ioloop.IOLoopKernelManager"
36 36
37 37 kernel_argv = List(Unicode)
38 38
39 max_msg_size = Integer(65536, config=True, help="""
40 The max raw message size accepted from the browser
41 over a WebSocket connection.
42 """)
43
44 39 _notebook_mapping = Dict()
45 40
46 41 #-------------------------------------------------------------------------
@@ -178,16 +178,33 class NotebookWebApplication(web.Application):
178 178 # Note that the URLs these patterns check against are escaped,
179 179 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
180 180 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
181
181 template_path = os.path.join(os.path.dirname(__file__), "templates")
182 182 settings = dict(
183 template_path=os.path.join(os.path.dirname(__file__), "templates"),
183 # basics
184 base_project_url=base_project_url,
185 base_kernel_url=ipython_app.base_kernel_url,
186 template_path=template_path,
184 187 static_path=ipython_app.static_file_path,
185 188 static_handler_class = FileFindHandler,
186 189 static_url_prefix = url_path_join(base_project_url,'/static/'),
190
191 # authentication
187 192 cookie_secret=os.urandom(1024),
188 193 login_url=url_path_join(base_project_url,'/login'),
189 194 cookie_name='username-%s' % uuid.uuid4(),
190 base_project_url = base_project_url,
195 read_only=ipython_app.read_only,
196 password=ipython_app.password,
197
198 # managers
199 kernel_manager=kernel_manager,
200 notebook_manager=notebook_manager,
201 cluster_manager=cluster_manager,
202
203 # IPython stuff
204 max_msg_size=ipython_app.max_msg_size,
205 config=ipython_app.config,
206 use_less=ipython_app.use_less,
207 jinja2_env=Environment(loader=FileSystemLoader(template_path)),
191 208 )
192 209
193 210 # allow custom overrides for the tornado web app.
@@ -197,21 +214,11 class NotebookWebApplication(web.Application):
197 214 new_handlers = []
198 215 for handler in handlers:
199 216 pattern = url_path_join(base_project_url, handler[0])
200 new_handler = tuple([pattern]+list(handler[1:]))
201 new_handlers.append( new_handler )
217 new_handler = tuple([pattern] + list(handler[1:]))
218 new_handlers.append(new_handler)
202 219
203 220 super(NotebookWebApplication, self).__init__(new_handlers, **settings)
204 221
205 self.kernel_manager = kernel_manager
206 self.notebook_manager = notebook_manager
207 self.cluster_manager = cluster_manager
208 self.ipython_app = ipython_app
209 self.read_only = self.ipython_app.read_only
210 self.config = self.ipython_app.config
211 self.use_less = self.ipython_app.use_less
212 self.log = log
213 self.jinja2_env = Environment(loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), "templates")))
214
215 222
216 223
217 224 #-----------------------------------------------------------------------------
@@ -301,10 +308,13 class NotebookApp(BaseIPythonApplication):
301 308
302 309 kernel_argv = List(Unicode)
303 310
304 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
305 default_value=logging.INFO,
306 config=True,
307 help="Set the log level by value or name.")
311 max_msg_size = Integer(65536, config=True, help="""
312 The max raw message size accepted from the browser
313 over a WebSocket connection.
314 """)
315
316 def _log_level_default(self):
317 return logging.INFO
308 318
309 319 # create requested profiles by default, if they don't exist:
310 320 auto_create = Bool(True)
General Comments 0
You need to be logged in to leave comments. Login now