def new_notebook(self): """ Create an empty notebook and push it into the workspace without an object_id or name, so that the WSS generates a new object ID for us. Then return that. This will likely only be called as a developer tool from http://<base url>/narrative or from starting up locally. """ wsclient = self.wsclient() user_id = self.get_userid() # Verify that our own home workspace exists, note that we aren't doing this # as a general thing for other workspaces # # This is needed for running locally - a workspace is required. try: (homews, homews_id) = ws_util.check_homews(wsclient, user_id) except Exception as e: raise web.HTTPError(401, u'User must be logged in to access their workspaces') # Have IPython create a new, empty notebook nb = current.new_notebook() new_name = normalize('NFC', u"Untitled %s" % (datetime.datetime.now().strftime("%y%m%d_%H%M%S"))) new_name = self._clean_id(new_name) # Add in basic metadata to the ipynb object try: nb.metadata.ws_name = os.environ.get('KB_WORKSPACE_ID', homews) nb.metadata.creator = user_id nb.metadata.type = self.ws_type nb.metadata.description = '' nb.metadata.name = new_name nb.metadata.data_dependencies = [] nb.metadata.format = self.node_format except Exception as e: raise web.HTTPError(400, u'Unexpected error setting notebook attributes: %s' %e) try: wsobj = { 'type' : self.ws_type, 'data' : nb, 'provenance' : [], 'meta' : nb.metadata.copy(), } wsid = homews_id wsobj['meta']['data_dependencies'] = json.dumps(wsobj['meta']['data_dependencies']) self.log.debug("calling ws_util.put_wsobj") res = ws_util.put_wsobj(wsclient, wsid, wsobj) self.log.debug("save_object returned %s" % res) except Exception as e: raise web.HTTPError(500, u'%s saving Narrative: %s' % (type(e),e)) # use "ws.ws_id.obj.object_id" as the identifier id = "ws.%s.obj.%s" % (res['wsid'], res['objid']) self._set_narrative_env(id) # update the mapping self.list_notebooks() return id
def new_notebook(self): """ Create an empty notebook and push it into the workspace without an object_id or name, so that the WSS generates a new object ID for us. Then return that. """ nb = current.new_notebook() # Verify that our own home workspace exists, note that we aren't doing this # as a general thing for other workspaces wsclient = self.wsclient() user_id = self.kbase_session.get('user_id', ws_util.get_user_id(wsclient)) (homews, homews_id) = ws_util.check_homews( wsclient, user_id) new_name = normalize('NFC', u"Untitled %s" % (datetime.datetime.now().strftime("%y%m%d_%H%M%S"))) new_name = self._clean_id(new_name) # Carry over some of the metadata stuff from ShockNBManager try: nb.metadata.ws_name = os.environ.get('KB_WORKSPACE_ID', homews) nb.metadata.creator = user_id nb.metadata.type = self.ws_type nb.metadata.description = '' nb.metadata.name = new_name nb.metadata.data_dependencies = [] nb.metadata.format = self.node_format except Exception as e: raise web.HTTPError(400, u'Unexpected error setting notebook attributes: %s' %e) try: wsobj = { 'type' : self.ws_type, 'data' : nb, 'provenance' : [], 'meta' : nb.metadata.copy(), } # We flatten the data_dependencies array into a json string so that the # workspace service will accept it wsobj['meta']['data_dependencies'] = json.dumps( wsobj['meta']['data_dependencies']) wsid = homews_id self.log.debug("calling ws_util.put_wsobj") res = ws_util.put_wsobj( wsclient, wsid, wsobj) self.log.debug("save_object returned %s" % res) except Exception as e: raise web.HTTPError(500, u'%s saving Narrative: %s' % (type(e),e)) # use "ws.ws_id.obj.object_id" as the identifier id = "ws.%s.obj.%s" % (res['wsid'], res['objid']) # Stash new narrative ID in environment util.kbase_env.narrative = id return id
def write_notebook_object(self, nb, notebook_id=None): """Save an existing notebook object by notebook_id.""" self.log.debug("writing Narrative %s." % notebook_id) wsclient = self.wsclient() user_id = self.get_userid() if user_id is None: raise web.HTTPError(400, u'Cannot determine user identity from ' u'session information') try: new_name = normalize('NFC', nb.metadata.name) except AttributeError: raise web.HTTPError(400, u'Missing Narrative name') new_name = self._clean_id(new_name) # Verify that our own home workspace exists, note that we aren't doing this # as a general thing for other workspaces wsclient = self.wsclient() (homews, homews_id) = ws_util.check_homews(wsclient, user_id) # Carry over some of the metadata stuff from ShockNBManager try: if not hasattr(nb.metadata, 'ws_name'): nb.metadata.ws_name = os.environ.get('KB_WORKSPACE_ID',homews) if not hasattr(nb.metadata, 'creator'): nb.metadata.creator = user_id if not hasattr(nb.metadata, 'type'): nb.metadata.type = self.ws_type if not hasattr(nb.metadata, 'description'): nb.metadata.description = '' # These are now stored on the front end explicitly as a list of object references # This gets auto-updated on the front end, and is easier to manage. if not hasattr(nb.metadata, 'data_dependencies'): nb.metadata.data_dependencies = list() nb.metadata.format = self.node_format except Exception as e: raise web.HTTPError(400, u'Unexpected error setting Narrative attributes: %s' %e) try: # 'wsobj' = the ObjectSaveData type from the workspace client # requires type, data (the Narrative typed object), provenance, # optionally, user metadata # # requires ONE AND ONLY ONE of objid (existing object id, number) or name (string) wsobj = { 'type' : self.ws_type, 'data' : nb, 'provenance' : [], 'meta' : nb.metadata.copy(), } # We flatten the data_dependencies array into a json string so that the # workspace service will accept it wsobj['meta']['data_dependencies'] = json.dumps(wsobj['meta']['data_dependencies']) # If we're given a notebook id, try to parse it for the save parameters if notebook_id: m = self.ws_regex.match(notebook_id) else: m = None if m: # wsid, objid = ws.XXX.obj.YYY wsid = m.group('wsid') wsobj['objid'] = m.group('objid') elif nb.metadata.ws_name == homews: wsid = homews_id wsobj['name'] = new_name else: wsid = ws_util.get_wsid(nb.metadata.ws_name) wsobj['name'] = new_name self.log.debug("calling ws_util.put_wsobj") res = ws_util.put_wsobj(wsclient, wsid, wsobj) self.log.debug("save_object returned %s" % res) # Now that we've saved the object, if its Narrative name (new_name) has changed, # update that in the Workspace if (res['name'] != new_name): identity = { 'wsid' : res['wsid'], 'objid' : res['objid'] } res = ws_util.rename_wsobj(wsclient, identity, new_name) except Exception as e: raise web.HTTPError(500, u'%s saving Narrative: %s' % (type(e),e)) # use "ws.ws_id.obj.object_id" as the identifier id = "ws.%s.obj.%s" % (res['wsid'], res['objid']) self.mapping[id] = "%s/%s" % (res['workspace'], new_name) self._set_narrative_env(id) return id
def write_notebook_object(self, nb, notebook_id=None): """Save an existing notebook object by notebook_id.""" self.log.debug("writing Narrative %s." % notebook_id) wsclient = self.wsclient() user_id = self.get_userid() if user_id is None: raise web.HTTPError(400, u'Cannot determine user identity from ' u'session information') # we don't rename anymore--- we only set the name in the metadata #try: # new_name = normalize('NFC', nb.metadata.name) #except AttributeError: # raise web.HTTPError(400, u'Missing Narrative name') #new_name = self._clean_id(new_name) # Verify that our own home workspace exists, note that we aren't doing this # as a general thing for other workspaces wsclient = self.wsclient() (homews, homews_id) = ws_util.check_homews(wsclient, user_id) # Carry over some of the metadata stuff from ShockNBManager try: if not hasattr(nb.metadata, 'name'): nb.metadata.name = 'Untitled' if not hasattr(nb.metadata, 'ws_name'): nb.metadata.ws_name = os.environ.get('KB_WORKSPACE_ID',homews) if not hasattr(nb.metadata, 'creator'): nb.metadata.creator = user_id if not hasattr(nb.metadata, 'type'): nb.metadata.type = self.ws_type if not hasattr(nb.metadata, 'description'): nb.metadata.description = '' # These are now stored on the front end explicitly as a list of object references # This gets auto-updated on the front end, and is easier to manage. if not hasattr(nb.metadata, 'data_dependencies'): nb.metadata.data_dependencies = list() if not hasattr(nb.metadata, 'job_ids'): nb.metadata.job_ids = { 'methods' : [], 'apps' : [], 'job_usage': { 'queue_time': 0, 'run_time': 0 } } if 'methods' not in nb.metadata['job_ids']: nb.metadata.job_ids['methods'] = list() if 'apps' not in nb.metadata['job_ids']: nb.metadata.job_ids['apps'] = list() if 'job_usage' not in nb.metadata['job_ids']: nb.metadata.job_ids['job_usage'] = { 'queue_time': 0, 'run_time': 0 } nb.metadata.format = self.node_format except Exception as e: raise web.HTTPError(400, u'Unexpected error setting Narrative attributes: %s' %e) # First, init wsid and wsobj, since they'll be used later wsid = '' # the workspace id wsobj = dict() # the workspace object # Figure out the workspace and object ids. If we have a notebook_id, get it from there # otherwise, figure out the workspace id from the metadata. if notebook_id: m = self.ws_regex.match(notebook_id) else: m = None # After this logic wsid is guaranteed to get set. # The objid of wsobj might not, but that's fine! The workspace will just assign a new id if so. if m: # wsid, objid = ws.XXX.obj.YYY wsid = m.group('wsid') wsobj['objid'] = m.group('objid') elif nb.metadata.ws_name == homews: wsid = homews_id #wsobj['name'] = new_name else: wsid = ws_util.get_wsid(nb.metadata.ws_name) #wsobj['name'] = new_name # With that set, update the workspace metadata with the new info. try: updated_metadata = { "is_temporary":"false", "narrative_nice_name":nb.metadata.name }; ws_util.alter_workspace_metadata(wsclient, None, updated_metadata, ws_id=wsid) except Exception as e: raise web.HTTPError(500, u'Error saving Narrative: %s, %s' % (e.__str__(), wsid)) # Now we can save the Narrative object. try: # 'wsobj' = the ObjectSaveData type from the workspace client # requires type, data (the Narrative typed object), provenance, # optionally, user metadata # # requires ONE AND ONLY ONE of objid (existing object id, number) or name (string) wsobj.update({ 'type' : self.ws_type, 'data' : nb, 'provenance' : [ { 'service' : 'narrative', 'description': 'saved through the narrative interface' } ], 'meta' : nb.metadata.copy(), }) # We flatten the data_dependencies array into a json string so that the # workspace service will accept it wsobj['meta']['data_dependencies'] = json.dumps(wsobj['meta']['data_dependencies']) wsobj['meta']['methods'] = json.dumps(self.extract_cell_info(nb)) # Sort out job info we want to keep # Gonna look like this, so init it that way nb_job_usage = nb.metadata.job_ids.get('job_usage', {'queue_time':0, 'run_time':0}) job_info = { 'queue_time': nb_job_usage.get('queue_time', 0), 'run_time': nb_job_usage.get('run_time', 0), 'running': 0, 'completed': 0, 'error': 0 } for job in nb.metadata.job_ids['methods'] + nb.metadata.job_ids['apps']: status = job.get('status', 'running') if status.startswith('complete'): job_info['completed'] += 1 elif 'error' in status: job_info['error'] += 1 else: job_info['running'] += 1 wsobj['meta']['job_info'] = json.dumps(job_info) if 'job_ids' in wsobj['meta']: wsobj['meta'].pop('job_ids') # # ------ # # If we're given a notebook id, try to parse it for the save parameters # if notebook_id: # m = self.ws_regex.match(notebook_id) # else: # m = None # if m: # # wsid, objid = ws.XXX.obj.YYY # wsid = m.group('wsid') # wsobj['objid'] = m.group('objid') # elif nb.metadata.ws_name == homews: # wsid = homews_id # #wsobj['name'] = new_name # else: # wsid = ws_util.get_wsid(nb.metadata.ws_name) # #wsobj['name'] = new_name # # -------- self.log.debug("calling ws_util.put_wsobj") res = ws_util.put_wsobj(wsclient, wsid, wsobj) self.log.debug("save_object returned %s" % res) # we no longer update names # Now that we've saved the object, if its Narrative name (new_name) has changed, # update that in the Workspace #if (res['name'] != new_name): # identity = { 'wsid' : res['wsid'], 'objid' : res['objid'] } # res = ws_util.rename_wsobj(wsclient, identity, new_name) except Exception as e: raise web.HTTPError(500, u'%s saving Narrative: %s' % (type(e),e)) # use "ws.ws_id.obj.object_id" as the identifier id = "ws.%s.obj.%s" % (res['wsid'], res['objid']) self.mapping[id] = "%s/%s" % (res['workspace'], res['name']) self._set_narrative_env(id) return id
def write_notebook_object(self, nb, notebook_id=None): """Save an existing notebook object by notebook_id.""" self.log.debug("writing Narrative %s." % notebook_id) wsclient = self.wsclient() user_id = self.get_userid() if user_id is None: raise web.HTTPError( 400, u'Cannot determine user identity from ' u'session information') # we don't rename anymore--- we only set the name in the metadata #try: # new_name = normalize('NFC', nb.metadata.name) #except AttributeError: # raise web.HTTPError(400, u'Missing Narrative name') #new_name = self._clean_id(new_name) # Verify that our own home workspace exists, note that we aren't doing this # as a general thing for other workspaces wsclient = self.wsclient() (homews, homews_id) = ws_util.check_homews(wsclient, user_id) # Carry over some of the metadata stuff from ShockNBManager try: if not hasattr(nb.metadata, 'name'): nb.metadata.name = 'Untitled' if not hasattr(nb.metadata, 'ws_name'): nb.metadata.ws_name = os.environ.get('KB_WORKSPACE_ID', homews) if not hasattr(nb.metadata, 'creator'): nb.metadata.creator = user_id if not hasattr(nb.metadata, 'type'): nb.metadata.type = self.ws_type if not hasattr(nb.metadata, 'description'): nb.metadata.description = '' # These are now stored on the front end explicitly as a list of object references # This gets auto-updated on the front end, and is easier to manage. if not hasattr(nb.metadata, 'data_dependencies'): nb.metadata.data_dependencies = list() if not hasattr(nb.metadata, 'job_ids'): nb.metadata.job_ids = { 'methods': [], 'apps': [], 'job_usage': { 'queue_time': 0, 'run_time': 0 } } if 'methods' not in nb.metadata['job_ids']: nb.metadata.job_ids['methods'] = list() if 'apps' not in nb.metadata['job_ids']: nb.metadata.job_ids['apps'] = list() if 'job_usage' not in nb.metadata['job_ids']: nb.metadata.job_ids['job_usage'] = { 'queue_time': 0, 'run_time': 0 } nb.metadata.format = self.node_format except Exception as e: raise web.HTTPError( 400, u'Unexpected error setting Narrative attributes: %s' % e) # First, init wsid and wsobj, since they'll be used later wsid = '' # the workspace id wsobj = dict() # the workspace object # Figure out the workspace and object ids. If we have a notebook_id, get it from there # otherwise, figure out the workspace id from the metadata. if notebook_id: m = self.ws_regex.match(notebook_id) else: m = None # After this logic wsid is guaranteed to get set. # The objid of wsobj might not, but that's fine! The workspace will just assign a new id if so. if m: # wsid, objid = ws.XXX.obj.YYY wsid = m.group('wsid') wsobj['objid'] = m.group('objid') elif nb.metadata.ws_name == homews: wsid = homews_id #wsobj['name'] = new_name else: wsid = ws_util.get_wsid(nb.metadata.ws_name) #wsobj['name'] = new_name # With that set, update the workspace metadata with the new info. try: updated_metadata = { "is_temporary": "false", "narrative_nice_name": nb.metadata.name } ws_util.alter_workspace_metadata(wsclient, None, updated_metadata, ws_id=wsid) except Exception as e: raise web.HTTPError( 500, u'Error saving Narrative: %s, %s' % (e.__str__(), wsid)) # Now we can save the Narrative object. try: # 'wsobj' = the ObjectSaveData type from the workspace client # requires type, data (the Narrative typed object), provenance, # optionally, user metadata # # requires ONE AND ONLY ONE of objid (existing object id, number) or name (string) wsobj.update({ 'type': self.ws_type, 'data': nb, 'provenance': [{ 'service': 'narrative', 'description': 'saved through the narrative interface' }], 'meta': nb.metadata.copy(), }) # We flatten the data_dependencies array into a json string so that the # workspace service will accept it wsobj['meta']['data_dependencies'] = json.dumps( wsobj['meta']['data_dependencies']) wsobj['meta']['methods'] = json.dumps(self.extract_cell_info(nb)) # Sort out job info we want to keep # Gonna look like this, so init it that way nb_job_usage = nb.metadata.job_ids.get('job_usage', { 'queue_time': 0, 'run_time': 0 }) job_info = { 'queue_time': nb_job_usage.get('queue_time', 0), 'run_time': nb_job_usage.get('run_time', 0), 'running': 0, 'completed': 0, 'error': 0 } for job in nb.metadata.job_ids['methods'] + nb.metadata.job_ids[ 'apps']: status = job.get('status', 'running') if status.startswith('complete'): job_info['completed'] += 1 elif 'error' in status: job_info['error'] += 1 else: job_info['running'] += 1 wsobj['meta']['job_info'] = json.dumps(job_info) if 'job_ids' in wsobj['meta']: wsobj['meta'].pop('job_ids') # # ------ # # If we're given a notebook id, try to parse it for the save parameters # if notebook_id: # m = self.ws_regex.match(notebook_id) # else: # m = None # if m: # # wsid, objid = ws.XXX.obj.YYY # wsid = m.group('wsid') # wsobj['objid'] = m.group('objid') # elif nb.metadata.ws_name == homews: # wsid = homews_id # #wsobj['name'] = new_name # else: # wsid = ws_util.get_wsid(nb.metadata.ws_name) # #wsobj['name'] = new_name # # -------- self.log.debug("calling ws_util.put_wsobj") res = ws_util.put_wsobj(wsclient, wsid, wsobj) self.log.debug("save_object returned %s" % res) # we no longer update names # Now that we've saved the object, if its Narrative name (new_name) has changed, # update that in the Workspace #if (res['name'] != new_name): # identity = { 'wsid' : res['wsid'], 'objid' : res['objid'] } # res = ws_util.rename_wsobj(wsclient, identity, new_name) except Exception as e: raise web.HTTPError(500, u'%s saving Narrative: %s' % (type(e), e)) # use "ws.ws_id.obj.object_id" as the identifier id = "ws.%s.obj.%s" % (res['wsid'], res['objid']) self.mapping[id] = "%s/%s" % (res['workspace'], res['name']) self._set_narrative_env(id) return id