"""Tornado handlers for the notebooks web service. Authors: * Brian Granger """ #----------------------------------------------------------------------------- # Copyright (C) 2008-2011 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- import json from tornado import web from ...utils import url_path_join from IPython.utils.jsonutil import date_default from ...base.handlers import IPythonHandler, json_errors #----------------------------------------------------------------------------- # Notebook web service handlers #----------------------------------------------------------------------------- class NotebookHandler(IPythonHandler): SUPPORTED_METHODS = (u'GET', u'PUT', u'PATCH', u'POST', u'DELETE') def notebook_location(self, name, path): """Return the full URL location of a notebook based. Parameters ---------- name : unicode The name of the notebook like "foo.ipynb". path : unicode The URL path of the notebook. """ return url_path_join(self.base_project_url, u'/api/notebooks', path, name) @web.authenticated @json_errors def get(self, notebook_path): """get checks if a notebook is not named, an returns a list of notebooks in the notebook path given. If a name is given, return the notebook representation""" nbm = self.notebook_manager # path will have leading and trailing slashes, such as '/foo/bar/' name, path = nbm.named_notebook_path(notebook_path) # Check to see if a notebook name was given if name is None: # List notebooks in 'notebook_path' notebooks = nbm.list_notebooks(path) self.finish(json.dumps(notebooks, default=date_default)) else: # get and return notebook representation model = nbm.get_notebook_model(name, path) self.set_header(u'Last-Modified', model[u'last_modified']) self.finish(json.dumps(model, default=date_default)) @web.authenticated # @json_errors def patch(self, notebook_path): """patch is currently used strictly for notebook renaming. Changes the notebook name to the name given in data.""" nbm = self.notebook_manager # path will have leading and trailing slashes, such as '/foo/bar/' name, path = nbm.named_notebook_path(notebook_path) if name is None: raise web.HTTPError(400, u'Notebook name missing') model = self.get_json_body() if model is None: raise web.HTTPError(400, u'JSON body missing') model = nbm.update_notebook_model(model, name, path) if model[u'name'] != name or model[u'path'] != path: self.set_status(301) location = self.notebook_location(model[u'name'], model[u'path']) self.set_header(u'Location', location) self.set_header(u'Last-Modified', model[u'last_modified']) self.finish(json.dumps(model, default=date_default)) @web.authenticated @json_errors def post(self, notebook_path): """Create a new notebook in the location given by 'notebook_path'.""" nbm = self.notebook_manager # path will have leading and trailing slashes, such as '/foo/bar/' name, path = nbm.named_notebook_path(notebook_path) model = self.get_json_body() if name is not None: raise web.HTTPError(400, 'No name can be provided when POSTing a new notebook.') model = nbm.create_notebook_model(model, path) location = nbm.notebook_dir + model[u'path'] + model[u'name'] location = self.notebook_location(model[u'name'], model[u'path']) self.set_header(u'Location', location) self.set_header(u'Last-Modified', model[u'last_modified']) self.set_status(201) self.finish(json.dumps(model, default=date_default)) @web.authenticated @json_errors def put(self, notebook_path): """saves the notebook in the location given by 'notebook_path'.""" nbm = self.notebook_manager # path will have leading and trailing slashes, such as '/foo/bar/' name, path = nbm.named_notebook_path(notebook_path) model = self.get_json_body() if model is None: raise web.HTTPError(400, u'JSON body missing') nbm.save_notebook_model(model, name, path) self.finish(json.dumps(model, default=date_default)) @web.authenticated @json_errors def delete(self, notebook_path): """delete the notebook in the given notebook path""" nbm = self.notebook_manager # path will have leading and trailing slashes, such as '/foo/bar/' name, path = nbm.named_notebook_path(notebook_path) nbm.delete_notebook_model(name, path) self.set_status(204) self.finish() class NotebookCheckpointsHandler(IPythonHandler): SUPPORTED_METHODS = ('GET', 'POST') @web.authenticated @json_errors def get(self, notebook_path): """get lists checkpoints for a notebook""" nbm = self.notebook_manager # path will have leading and trailing slashes, such as '/foo/bar/' name, path = nbm.named_notebook_path(notebook_path) checkpoints = nbm.list_checkpoints(name, path) data = json.dumps(checkpoints, default=date_default) self.finish(data) @web.authenticated @json_errors def post(self, notebook_path): """post creates a new checkpoint""" nbm = self.notebook_manager name, path = nbm.named_notebook_path(notebook_path) # path will have leading and trailing slashes, such as '/foo/bar/' checkpoint = nbm.create_checkpoint(name, path) data = json.dumps(checkpoint, default=date_default) location = url_path_join(self.base_project_url, u'/api/notebooks', path, name, '/checkpoints', checkpoint[u'checkpoint_id']) self.set_header(u'Location', location) self.finish(data) class ModifyNotebookCheckpointsHandler(IPythonHandler): SUPPORTED_METHODS = ('POST', 'DELETE') @web.authenticated @json_errors def post(self, notebook_path, checkpoint_id): """post restores a notebook from a checkpoint""" nbm = self.notebook_manager # path will have leading and trailing slashes, such as '/foo/bar/' name, path = nbm.named_notebook_path(notebook_path) nbm.restore_checkpoint(checkpoint_id, name, path) self.set_status(204) self.finish() @web.authenticated @json_errors def delete(self, notebook_path, checkpoint_id): """delete clears a checkpoint for a given notebook""" nbm = self.notebook_manager # path will have leading and trailing slashes, such as '/foo/bar/' name, path = nbm.named_notebook_path(notebook_path) nbm.delete_checkpoint(checkpoint_id, name, path) self.set_status(204) self.finish() #----------------------------------------------------------------------------- # URL to handler mappings #----------------------------------------------------------------------------- _notebook_path_regex = r"(?P.*)" _checkpoint_id_regex = r"(?P[\w-]+)" default_handlers = [ (r"/api/notebooks/%s/checkpoints" % _notebook_path_regex, NotebookCheckpointsHandler), (r"/api/notebooks/%s/checkpoints/%s" % (_notebook_path_regex, _checkpoint_id_regex), ModifyNotebookCheckpointsHandler), (r"/api/notebooks%s" % _notebook_path_regex, NotebookHandler), ]