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