def test_validate_params(self): inputs = { "reads_tuple": [ { "input_reads_label": "reads file 1", "input_reads_obj": "rhodobacterium.art.q20.int.PE.reads", "input_reads_metadata": { "key1": "value1" } }, { "input_reads_label": "reads file 2", "input_reads_obj": "rhodobacterium.art.q10.PE.reads", "input_reads_metadata": { "key2": "value2" } } ], "output_object": "MyReadsSet", "description": "New Reads Set" } app_id = "NarrativeTest/test_create_set" tag = "dev" prev_ws_id = os.environ.get('KB_WORKSPACE_ID') os.environ['KB_WORKSPACE_ID'] = self.public_ws sm = specmanager.SpecManager() spec = sm.get_spec(app_id, tag=tag) (params, ws_inputs) = app_util.validate_parameters(app_id, tag, sm.app_params(spec), inputs) self.assertDictEqual(params, inputs) self.assertIn('12345/8/1', ws_inputs) self.assertIn('12345/7/1', ws_inputs) if prev_ws_id is None: del(os.environ['KB_WORKSPACE_ID']) else: os.environ['KB_WORKSPACE_ID'] = prev_ws_id
def test_validate_params(self): inputs = { "reads_tuple": [ { "input_reads_label": READS_FILE_1, "input_reads_obj": READS_OBJ_1, "input_reads_metadata": { "key1": "value1" }, }, { "input_reads_label": READS_FILE_2, "input_reads_obj": READS_OBJ_2, "input_reads_metadata": { "key2": "value2" }, }, ], "output_object": "MyReadsSet", "description": NEW_READS_SET, } app_id = "NarrativeTest/test_create_set" tag = "dev" spec = self.am.spec_manager.get_spec(app_id, tag=tag) spec_params = self.am.spec_manager.app_params(spec) (params, ws_inputs) = app_util.validate_parameters(app_id, tag, spec_params, inputs) self.assertDictEqual(params, inputs) self.assertIn("12345/8/1", ws_inputs) self.assertIn("12345/7/1", ws_inputs)
def _run_local_app_internal(self, app_id, params, widget_state, tag, version, cell_id, run_id): self._send_comm_message('run_status', { 'event': 'validating_app', 'event_at': datetime.datetime.utcnow().isoformat() + 'Z', 'cell_id': cell_id, 'run_id': run_id }) spec = self._get_validated_app_spec(app_id, tag, False, version=version) # Here, we just deal with two behaviors: # 1. None of the above - it's a viewer. # 2. ***TODO*** python_class / python_function. # Import and exec the python code. # for now, just map the inputs to outputs. # First, validate. # Preflight check the params - all required ones are present, all # values are the right type, all numerical values are in given ranges spec_params = self.spec_manager.app_params(spec) (params, ws_refs) = validate_parameters(app_id, tag, spec_params, params) # Log that we're trying to run a job... log_info = { 'app_id': app_id, 'tag': tag, 'username': system_variable('user_id'), 'ws': system_variable('workspace') } kblogging.log_event(self._log, "run_local_app", log_info) self._send_comm_message('run_status', { 'event': 'success', 'event_at': datetime.datetime.utcnow().isoformat() + 'Z', 'cell_id': cell_id, 'run_id': run_id }) (output_widget, widget_params) = map_outputs_from_state([], params, spec) # All a local app does is route the inputs to outputs through the # spec's mapping, and then feed that into the specified output widget. wm = WidgetManager() if widget_state is not None: return wm.show_advanced_viewer_widget( output_widget, widget_params, widget_state, cell_id=cell_id, tag=tag ) else: return wm.show_output_widget( output_widget, widget_params, cell_id=cell_id, tag=tag )
def _validate_parameters(self, app_id, tag, spec_params, params): """ Validates the dict of params against the spec_params. If all is good, it updates a few parameters that need it - checkboxes go from True/False to 1/0, and sets default values where necessary. Then it returns a tuple like this: (dict_of_params, list_of_ws_refs) where list_of_ws_refs is the list of workspace references for objects being passed into the app. If it fails, this will raise a ValueError with a description of the problem and a (hopefully useful!) hint for the user as to what went wrong. """ return validate_parameters(app_id, tag, spec_params, params)
def test_validate_params(self): inputs = { "reads_tuple": [ { "input_reads_label": "reads file 1", "input_reads_obj": "rhodobacterium.art.q20.int.PE.reads", "input_reads_metadata": { "key1": "value1" }, }, { "input_reads_label": "reads file 2", "input_reads_obj": "rhodobacterium.art.q10.PE.reads", "input_reads_metadata": { "key2": "value2" }, }, ], "output_object": "MyReadsSet", "description": "New Reads Set", } app_id = "NarrativeTest/test_create_set" tag = "dev" prev_ws_id = os.environ.get("KB_WORKSPACE_ID") os.environ["KB_WORKSPACE_ID"] = self.public_ws sm = specmanager.SpecManager() spec = sm.get_spec(app_id, tag=tag) (params, ws_inputs) = app_util.validate_parameters(app_id, tag, sm.app_params(spec), inputs) self.assertDictEqual(params, inputs) self.assertIn("12345/8/1", ws_inputs) self.assertIn("12345/7/1", ws_inputs) if prev_ws_id is None: del os.environ["KB_WORKSPACE_ID"] else: os.environ["KB_WORKSPACE_ID"] = prev_ws_id
def show_data_widget(self, widget_name, params, title="", cell_id=None, tag="release"): """ Renders a widget using the generic kbaseNarrativeOutputWidget container. Parameters ---------- widget_name : string The name of the widget to print the widgets for. params : dict The dictionary of parameters that gets fed into the widget. """ input_data = dict(params) obj_ref = None info = None if 'info' in params: info = params['info'] obj_ref = str(info['ws_id']) + '/' + str(info['id']) + '/' + str(info['version']) elif 'ref' in params: obj_ref = params['ref'] # may include ref-path (or chain, not sure which one is text) else: raise ValueError("Neither 'info' nor 'ref' field is set in input parameters") info_tuple = clients.get('workspace').get_object_info_new({'objects': [{'ref': obj_ref}], 'includeMetadata': 1})[0] input_data['info'] = info input_data['info_tuple'] = info_tuple bare_type = info_tuple[2].split('-')[0] type_spec = self._sm.get_type_spec(bare_type, raise_exception=False) if type_spec is None: input_data['error_message'] = "Type-spec wasn't found for '" + bare_type + "'" elif 'view_method_ids' not in type_spec or len(type_spec['view_method_ids']) != 1: input_data['error_message'] = ("Type-spec for '" + bare_type + "' should " + "have exactly one ID in 'view_method_ids' field") else: input_data['type_spec'] = type_spec method_id = type_spec['view_method_ids'][0] spec = self._sm.get_spec(method_id, tag=tag) input_data['app_spec'] = spec # Let's build output according to mappings in method-spec spec_params = self._sm.app_params(spec) input_params = {} is_ref_path = ';' in obj_ref is_external = info_tuple[7] != os.environ['KB_WORKSPACE_ID'] # it's not safe to use reference yet (until we switch to them all over the Apps) # But in case we deal with ref-path we have to do it anyway: obj_param_value = obj_ref if (is_ref_path or is_external) else info_tuple[1] for param in spec_params: if any(t == bare_type for t in param['allowed_types']): input_params[param['id']] = obj_param_value (input_params, ws_refs) = validate_parameters(method_id, tag, spec_params, input_params) (output_widget, output) = map_outputs_from_state([], input_params, spec) input_data['output'] = output input_template = """ element.html("<div id='{{input_id}}' class='kb-vis-area'></div>"); require(['kbaseNarrativeOutputCell'], function(KBaseNarrativeOutputCell) { var w = new KBaseNarrativeOutputCell($('#{{input_id}}'), { "data": {{input_data}}, "type":"viewer", "widget":"{{widget_name}}", "cellId":"{{cell_id}}", "title":"{{cell_title}}", "time":{{timestamp}} }); }); """ js = Template(input_template).render(input_id=self._cell_id_prefix + str(uuid.uuid4()), widget_name=widget_name, input_data=json.dumps(input_data), cell_title=title, cell_id=cell_id, timestamp=int(round(time.time()*1000))) return Javascript(data=js, lib=None, css=None)
def _run_local_app_internal(self, app_id, params, widget_state, tag, version, cell_id, run_id): self._send_comm_message( 'run_status', { 'event': 'validating_app', 'event_at': datetime.datetime.utcnow().isoformat() + 'Z', 'cell_id': cell_id, 'run_id': run_id }) spec = self._get_validated_app_spec(app_id, tag, False, version=version) # Here, we just deal with two behaviors: # 1. None of the above - it's a viewer. # 2. ***TODO*** python_class / python_function. # Import and exec the python code. # for now, just map the inputs to outputs. # First, validate. # Preflight check the params - all required ones are present, all # values are the right type, all numerical values are in given ranges spec_params = self.spec_manager.app_params(spec) (params, ws_refs) = validate_parameters(app_id, tag, spec_params, params) # Log that we're trying to run a job... log_info = { 'app_id': app_id, 'tag': tag, 'username': system_variable('user_id'), 'ws': system_variable('workspace') } kblogging.log_event(self._log, "run_local_app", log_info) self._send_comm_message( 'run_status', { 'event': 'success', 'event_at': datetime.datetime.utcnow().isoformat() + 'Z', 'cell_id': cell_id, 'run_id': run_id }) (output_widget, widget_params) = map_outputs_from_state([], params, spec) # All a local app does is route the inputs to outputs through the # spec's mapping, and then feed that into the specified output widget. wm = WidgetManager() if widget_state is not None: return wm.show_advanced_viewer_widget(output_widget, widget_params, widget_state, cell_id=cell_id, tag=tag) else: return wm.show_output_widget(output_widget, widget_params, cell_id=cell_id, tag=tag)
def run_local_app( self, app_id, params, tag="release", version=None, cell_id=None, run_id=None, widget_state=None, ): """ Attempts to run a local app. These do not return a Job object, but just the result of the app. In most cases, this will be a Javascript display of the result, but could be anything. If the app_spec looks like it makes a service call, then this raises a ValueError. Otherwise, it validates each parameter in **kwargs against the app spec, executes it, and returns the result. Parameters: ----------- app_id - should be from the app spec, e.g. 'view_expression_profile' params - the dictionary of parameters for the app. Should be key-value pairs where they keys are strings. If any non-optional parameters are missing, an informative string will be printed. tag - optional, one of [release|beta|dev] (default=release) version - optional, a semantic version string. Only released modules have versions, so if the tag is not 'release', and a version is given, a ValueError will be raised. Example: run_local_app('NarrativeViewers/view_expression_profile', { "input_expression_matrix": "MyMatrix", "input_gene_ids": "1234" }, version='0.0.1', input_expression_matrix="MyMatrix") """ spec = self._get_validated_app_spec(app_id, tag, False, version=version) # Here, we just deal with two behaviors: # 1. None of the above - it's a viewer. # 2. ***TODO*** python_class / python_function. # Import and exec the python code. # for now, just map the inputs to outputs. # First, validate. # Preflight check the params - all required ones are present, all # values are the right type, all numerical values are in given ranges spec_params = self.spec_manager.app_params(spec) (params, ws_refs) = validate_parameters(app_id, tag, spec_params, params) # Log that we're trying to run a job... log_info = { "app_id": app_id, "tag": tag, "username": system_variable("user_id"), "ws": system_variable("workspace"), } kblogging.log_event(self._log, "run_local_app", log_info) self._send_comm_message( MESSAGE_TYPE["RUN_STATUS"], { "event": "success", "event_at": timestamp(), "cell_id": cell_id, "run_id": run_id, }, ) (output_widget, widget_params) = map_outputs_from_state([], params, spec) # All a local app does is route the inputs to outputs through the # spec's mapping, and then feed that into the specified output widget. wm = WidgetManager() if widget_state is not None: return wm.show_advanced_viewer_widget( output_widget, widget_params, widget_state, cell_id=cell_id, tag=tag ) else: return wm.show_output_widget( output_widget, widget_params, cell_id=cell_id, tag=tag )
def show_data_widget(self, upa, title=None, cell_id=None, tag="release"): """ Renders a widget using the generic kbaseNarrativeOutputCell container. First, it looks up the UPA to get its object type. It then uses that type to look up what the viewer app should be. This contains the widget and the parameter mapping to view that widget. It then maps all of these together to run show_output_widget against a widget with a set of parameters for it. If there's an error here at any step, it still renders a widget, but it makes a kbaseNarrativeError widget instead, that'll hopefully be informative. Parameters ---------- upa : string UPA defining a workspace object. Used to translate that object into parameters for the mapping to the data object used in the output cell. This may also be a Workspace reference path. title=None : string A title for the cell. If None, this just gets replaced with an empty string. cell_id=None : string if not None, this should be the id of the cell where the widget will live. Generated by the Narrative frontend. tag="release" : string All objects are related to their viewers by an app. This is the tag for that app's release state (should be one of release, beta, or dev) """ widget_name = 'widgets/function_output/kbaseDefaultObjectView' # set as default, overridden below widget_data = dict() upas = dict() info_tuple = clients.get('workspace').get_object_info_new({ 'objects': [{ 'ref': upa }], 'includeMetadata': 1 })[0] bare_type = info_tuple[2].split('-')[0] type_module = bare_type.split(".")[0] type_spec = self._sm.get_type_spec(bare_type, raise_exception=False) if type_spec is None: widget_data = { "error": { "msg": f"Unable to find viewer specification for objects of type {bare_type}.", "method_name": "WidgetManager.show_data_widget", "traceback": f"Can't find type spec info for type {bare_type}" } } upas['upas'] = [upa] # doompety-doo else: if not type_spec.get('view_method_ids'): return f"No viewer found for objects of type {bare_type}" app_id = type_spec['view_method_ids'][0] app_spec = None try: app_spec = self._sm.get_spec(app_id, tag=tag) except Exception as e: widget_data = { "error": { "msg": f"Unable to find specification for viewer app {app_id}", "method_name": "WidgetManager.show_data_widget", "traceback": e.message } } if app_spec is not None: spec_params = self._sm.app_params(app_spec) input_params = {} is_ref_path = ';' in upa is_external = info_tuple[7] != os.environ['KB_WORKSPACE_ID'] # it's not safe to use reference yet (until we switch to them all over the Apps) # But in case we deal with ref-path we have to do it anyway: obj_param_value = upa if (is_ref_path or is_external) else info_tuple[1] upa_params = list() for param in spec_params: if param.get('allowed_types') is None or any( (t == bare_type or t == type_module) for t in param.get('allowed_types', [])): input_params[param['id']] = obj_param_value upa_params.append(param['id']) (input_params, ws_refs) = validate_parameters(app_id, tag, spec_params, input_params) (widget_name, widget_data) = map_outputs_from_state([], input_params, app_spec) # Figure out params for upas. for mapping in app_spec.get('behavior', {}).get('output_mapping', []): if mapping.get( 'input_parameter', '') in upa_params and 'target_property' in mapping: upas[mapping['target_property']] = upa return self.show_output_widget(widget_name, widget_data, upas=upas, title=title, type="viewer", cell_id=cell_id)
def show_data_widget(self, upa, title=None, cell_id=None, tag="release"): """ Renders a widget using the generic kbaseNarrativeOutputCell container. First, it looks up the UPA to get its object type. It then uses that type to look up what the viewer app should be. This contains the widget and the parameter mapping to view that widget. It then maps all of these together to run show_output_widget against a widget with a set of parameters for it. If there's an error here at any step, it still renders a widget, but it makes a kbaseNarrativeError widget instead, that'll hopefully be informative. Parameters ---------- upa : string UPA defining a workspace object. Used to translate that object into parameters for the mapping to the data object used in the output cell. This may also be a Workspace reference path. title=None : string A title for the cell. If None, this just gets replaced with an empty string. cell_id=None : string if not None, this should be the id of the cell where the widget will live. Generated by the Narrative frontend. tag="release" : string All objects are related to their viewers by an app. This is the tag for that app's release state (should be one of release, beta, or dev) """ widget_name = 'widgets/function_output/kbaseDefaultObjectView' # set as default, overridden below widget_data = dict() upas = dict() info_tuple = clients.get('workspace').get_object_info_new({'objects': [{'ref': upa}], 'includeMetadata': 1})[0] bare_type = info_tuple[2].split('-')[0] type_module = bare_type.split(".")[0] type_spec = self._sm.get_type_spec(bare_type, raise_exception=False) if type_spec is None: widget_data = { "error": { "msg": "Unable to find viewer specification for objects of type {}.".format(bare_type), "method_name": "WidgetManager.show_data_widget", "traceback": "Can't find type spec info for type {}".format(bare_type) } } upas['upas'] = [upa] # doompety-doo else: if not type_spec.get('view_method_ids'): return "No viewer found for objects of type {}".format(bare_type) app_id = type_spec['view_method_ids'][0] app_spec = None try: app_spec = self._sm.get_spec(app_id, tag=tag) except Exception as e: widget_data = { "error": { "msg": "Unable to find specification for viewer app {}".format(app_id), "method_name": "WidgetManager.show_data_widget", "traceback": e.message } } if app_spec is not None: spec_params = self._sm.app_params(app_spec) input_params = {} is_ref_path = ';' in upa is_external = info_tuple[7] != os.environ['KB_WORKSPACE_ID'] # it's not safe to use reference yet (until we switch to them all over the Apps) # But in case we deal with ref-path we have to do it anyway: obj_param_value = upa if (is_ref_path or is_external) else info_tuple[1] upa_params = list() for param in spec_params: if param.get('allowed_types') is None or any((t == bare_type or t == type_module) for t in param.get('allowed_types', [])): input_params[param['id']] = obj_param_value upa_params.append(param['id']) (input_params, ws_refs) = validate_parameters(app_id, tag, spec_params, input_params) (widget_name, widget_data) = map_outputs_from_state([], input_params, app_spec) # Figure out params for upas. for mapping in app_spec.get('behavior', {}).get('output_mapping', []): if mapping.get('input_parameter', '') in upa_params and 'target_property' in mapping: upas[mapping['target_property']] = upa return self.show_output_widget( widget_name, widget_data, upas=upas, title=title, type="viewer", cell_id=cell_id )