def save_notebook(self, model, name, path=''): """Save the notebook model and return the model with no content.""" self.log.debug("save_notebook(%s, '%s', '%s')", model, str(name), str(path)) assert name.endswith(self.filename_ext) path = path.strip('/') if 'content' not in model: raise web.HTTPError(400, u'No notebook JSON data provided') # One checkpoint should always exist if self.notebook_exists(name, path) \ and not self.list_checkpoints(name, path): self.create_checkpoint(name, path) new_path = model.get('path', path) new_name = model.get('name', name) if path != new_path or name != new_name: self._rename_notebook(name, path, new_name, new_path) # Create the path and notebook entries if necessary if new_path not in self.tree: self.tree[new_path] = {} if new_name not in self.tree[new_path]: self.tree[new_path][new_name] = \ dict(created = tz.utcnow(), checkpoints=[]) notebook = self.tree[new_path][new_name] # Save the notebook file nb = current.to_notebook_json(model['content']) self.check_and_sign(nb, new_path, new_name) if 'name' in nb['metadata']: nb['metadata']['name'] = u'' ipynb_stream = StringIO() current.write(nb, ipynb_stream, u'json') notebook['ipynb'] = ipynb_stream.getvalue() notebook['ipynb_last_modified'] = tz.utcnow() ipynb_stream.close() # Save .py script as well py_stream = StringIO() current.write(nb, py_stream, u'json') notebook['py'] = py_stream.getvalue() notebook['py_last_modified'] = tz.utcnow() py_stream.close() # Return model model = self.get_notebook(new_name, new_path, content=False) self.log.debug("save_notebook -> %s", model) return model
def _base_model(self, path): """Build the common base of a contents model""" last_modified = tz.utcnow() created = tz.utcnow() # Create the base model. model = {} model['name'] = path.rsplit('/', 1)[-1] model['path'] = path model['last_modified'] = last_modified model['created'] = created model['content'] = None model['format'] = None model['mimetype'] = None model['writable'] = True return model
def test_date_default(): data = dict(today=datetime.datetime.now(), utcnow=tz.utcnow()) jsondata = json.dumps(data, default=jsonutil.date_default) nt.assert_in("+00", jsondata) nt.assert_equal(jsondata.count("+00"), 1) extracted = jsonutil.extract_dates(json.loads(jsondata)) for dt in list(extracted.values()): nt.assert_true(isinstance(dt, datetime.datetime))
def test_date_default(): data = dict(today=datetime.datetime.now(), utcnow=tz.utcnow()) jsondata = json.dumps(data, default=jsonutil.date_default) nt.assert_in("+00", jsondata) nt.assert_equal(jsondata.count("+00"), 1) extracted = jsonutil.extract_dates(json.loads(jsondata)) for dt in extracted.values(): nt.assert_true(isinstance(dt, datetime.datetime))
def _base_model(self, path): """Build the common base of a contents model""" # http://jupyter-notebook.readthedocs.io/en/stable/extending/contents.html path = path.strip('/') last_modified = tz.utcnow() created = tz.utcnow() # Create the base model. model = {} model['name'] = path.rsplit('/', 1)[-1] model['path'] = path model['last_modified'] = last_modified model['created'] = created model['content'] = None model['format'] = None model['mimetype'] = None model['writable'] = True return model
def _base_model(self, path, kind=None): """Build the common base of a contents model""" # http://jupyter-notebook.readthedocs.io/en/stable/extending/contents.html from IPython.utils import tz path = unquote(path).strip('/') last_modified = tz.utcnow() created = tz.utcnow() # Create the base model. model = {} model['name'] = os.path.basename(path) model['path'] = path model['last_modified'] = last_modified model['created'] = created model['content'] = None model['format'] = None model['mimetype'] = None model['writable'] = True if kind: model['type'] = kind model['content'] = [] if kind == 'directory' else None return model
def get_dir_model(self, name, path=''): """Get the directory model given a directory name and its API style path. The keys in the model should be: * name * path * last_modified * created * type='directory' """ if not self.path_exists(path): raise IOError('directory does not exist: %r' % path) # Create the directory model. model ={} model['name'] = name model['path'] = path.strip('/') model['last_modified'] = tz.utcnow() model['created'] = tz.utcnow() model['type'] = 'directory' self.log.debug("get_dir_model('%s', '%s') -> %s", name, path, str(model)) return model
def _rename_notebook(self, old_name, new_name): if old_name not in self.nb_list: raise web.HTTPError(400, u"Unavailable Notebook: %s" % (old_name)) # update attributes attr = self.nb_list[old_name]['attributes'] attr['name'] = self._strip_ext(new_name) attr['last_modified'] = tz.utcnow().isoformat() attr_str = json.dumps(attr) # update in shock try: node = self._update_shock_node(self.nb_list[old_name]['id'], attr_str) except Exception as e: raise web.HTTPError(400, u'Unexpected error while renaming notebook: %s' %e) # update listing del self.nb_list[old_name] self.nb_list[new_name] = node
def _delete_notebook(self, os_path, name): if name not in self.nb_list: raise web.HTTPError(400, u"Unavailable Notebook: %s" % (name)) # set as deleted in shock attr = self.nb_list[name]['attributes'] attr['deleted'] = 1 attr['last_modified'] = tz.utcnow().isoformat() attr_str = json.dumps(attr) try: self.log.debug("Deleting %s from Shock", name) node = self._update_shock_node(self.nb_list[name]['id'], attr_str) except Exception as e: raise web.HTTPError(400, u'Unexpected error while deleting notebook: %s' %e) # delete from listing del self.nb_list[name] os.unlink(os_path)
def read_notebook_object(self, notebook_id): """Get the object representation of a notebook by notebook_id.""" if not self.notebook_exists(notebook_id): raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id) try: s = self.blob_service.get_blob(self.container, notebook_id) except: raise web.HTTPError(500, u'Notebook cannot be read.') try: # v1 and v2 and json in the .ipynb files. nb = current.reads(s, u'json') except: raise web.HTTPError(500, u'Unreadable JSON notebook.') # Todo: The last modified should actually be saved in the notebook document. # We are just using the current datetime until that is implemented. last_modified = tz.utcnow() return last_modified, nb
def read_notebook_object(self, notebook_id): """Get the object representation of a notebook by notebook_id.""" if not self.notebook_exists(notebook_id): raise web.HTTPError(404, NB_DNEXIST_ERR.format(notebook_id)) try: obj = self.container.get_object(notebook_id) # Read in the entire notebook file into s s = obj.get() except: raise web.HTTPError(500, "Notebook cannot be read.") try: nb = current.reads(s, "json") except: raise web.HTTPError(500, "Unreadable JSON notebook.") last_modified = utcnow() return last_modified, nb
def read_notebook_object(self, notebook_id): """Get the object representation of a notebook by notebook_id.""" if not self.notebook_exists(notebook_id): raise web.HTTPError(404, NB_DNEXIST_ERR.format(notebook_id)) try: obj = self.container.get_object(notebook_id) # Read in the entire notebook file into s s = obj.get() except: raise web.HTTPError(500, 'Notebook cannot be read.') try: nb = current.reads(s, 'json') except: raise web.HTTPError(500, 'Unreadable JSON notebook.') last_modified = utcnow() return last_modified, nb
def create_checkpoint(self, notebook_id): """Create a checkpoint of the current state of a notebook Returns a dictionary with a checkpoint_id and the timestamp from the last modification """ self.log.info("Creating checkpoint for notebook {}".format(notebook_id)) # We pull the next available checkpoint id (1UP) checkpoints = self.container.get_objects(prefix=(notebook_id + "/")) checkpoint_id = self.new_checkpoint_id() checkpoint_path = self.get_checkpoint_path(notebook_id, checkpoint_id) last_modified = utcnow() metadata = { METADATA_CHK_ID: checkpoint_id, METADATA_LAST_MODIFIED: last_modified.strftime(DATE_FORMAT), METADATA_NB_ID: notebook_id, } try: self.log.info("Copying notebook {} to {}".format(notebook_id, checkpoint_path)) self.cf.copy_object( container=self.container_name, obj=notebook_id, new_container=self.container_name, new_obj_name=checkpoint_path, ) obj = self.container.get_object(checkpoint_path) obj.set_metadata(metadata) except Exception as e: raise web.HTTPError(400, CHK_SAVE_UNK_ERR.format(e)) info = dict(checkpoint_id=checkpoint_id, last_modified=last_modified) return info
def create_checkpoint(self, notebook_id): """Create a checkpoint of the current state of a notebook Returns a dictionary with a checkpoint_id and the timestamp from the last modification """ self.log.info( "Creating checkpoint for notebook {}".format(notebook_id)) # We pull the next available checkpoint id (1UP) checkpoints = self.container.get_objects(prefix=(notebook_id + "/")) checkpoint_id = self.new_checkpoint_id() checkpoint_path = self.get_checkpoint_path(notebook_id, checkpoint_id) last_modified = utcnow() metadata = { METADATA_CHK_ID: checkpoint_id, METADATA_LAST_MODIFIED: last_modified.strftime(DATE_FORMAT), METADATA_NB_ID: notebook_id } try: self.log.info("Copying notebook {} to {}".format( notebook_id, checkpoint_path)) self.cf.copy_object(container=self.container_name, obj=notebook_id, new_container=self.container_name, new_obj_name=checkpoint_path) obj = self.container.get_object(checkpoint_path) obj.set_metadata(metadata) except Exception as e: raise web.HTTPError(400, CHK_SAVE_UNK_ERR.format(e)) info = dict(checkpoint_id=checkpoint_id, last_modified=last_modified) return info
def _save_notebook(self, os_path, model, path): """save a notebook to shock""" # Get name name = path.rsplit('/', 1)[-1] # Get attributes attr = {} attr['name'] = self._strip_ext(name) attr['type'] = self.node_type attr['format'] = 'json' attr['last_modified'] = tz.utcnow().isoformat() # creation timestamp if 'created' in model: attr['created'] = model['created'].isoformat() elif name in self.nb_list: attr['created'] = self.nb_list[name]['attributes']['created'] else: attr['created'] = attr['last_modified'] # original id if name in self.nb_list: attr['original'] = self.nb_list[name]['attributes']['original'] else: attr['original'] = str(uuid.uuid4()) attr_str = json.dumps(attr) # Get the notebook content nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, name) nb_str = nbformat.writes(nb, version=nbformat.NO_CONVERT) # Save to shock try: self.log.debug("Saving %s to Shock", name) node = self._post_shock_node(name, nb_str, attr_str) except Exception as e: raise web.HTTPError(400, u'Unexpected error while saving notebook: %s' %e) # update lists self.nb_list[name] = node open(os_path, 'w').close()