def test_map_outputs_from_state_bad_spec(self): os.environ["KB_WORKSPACE_ID"] = self.workspace app_spec = {"not": "really"} params = {"an_input": "input_val"} state = {} with self.assertRaises(ValueError): map_outputs_from_state(state, params, app_spec)
def test_map_outputs_from_state_bad_spec(self): os.environ['KB_WORKSPACE_ID'] = self.workspace app_spec = {'not': 'really'} params = {'an_input': 'input_val'} state = {} with self.assertRaises(ValueError): map_outputs_from_state(state, params, app_spec)
def test_map_outputs_from_state_bad_spec(self): os.environ['KB_WORKSPACE_ID'] = self.workspace app_spec = { 'not': 'really' } params = { 'an_input': 'input_val' } state = {} with self.assertRaises(ValueError): map_outputs_from_state(state, params, app_spec)
def test_map_outputs_from_state(self): os.environ["KB_WORKSPACE_ID"] = self.workspace app_spec = { "widgets": {"input": None, "output": "testOutputWidget"}, "parameters": [], "behavior": { "kb_service_output_mapping": [ {"narrative_system_variable": "workspace", "target_property": "ws"}, {"constant_value": 5, "target_property": "a_constant"}, { "service_method_output_path": [1], "target_property": "a_path_ref", }, {"input_parameter": "an_input", "target_property": "an_input"}, ] }, } params = {"an_input": "input_val"} state = {"job_output": {"result": ["foo", "bar"]}} expected = ( "testOutputWidget", { "ws": self.workspace, "a_constant": 5, "a_path_ref": "bar", "an_input": "input_val", }, ) self.assertTupleEqual(map_outputs_from_state(state, params, app_spec), expected)
def test_map_outputs_from_state(self): os.environ['KB_WORKSPACE_ID'] = self.workspace app_spec = { 'widgets': { 'input': None, 'output': 'testOutputWidget' }, 'parameters': [], 'behavior': { 'kb_service_output_mapping': [{ 'narrative_system_variable': 'workspace', 'target_property': 'ws' }, { 'constant_value': 5, 'target_property': 'a_constant' }, { 'service_method_output_path': [1], 'target_property': 'a_path_ref' }, { 'input_parameter': 'an_input', 'target_property': 'an_input' }] } } params = {'an_input': 'input_val'} state = {'job_output': {'result': ['foo', 'bar']}} expected = ('testOutputWidget', { 'ws': self.workspace, 'a_constant': 5, 'a_path_ref': 'bar', 'an_input': 'input_val' }) self.assertTupleEqual(map_outputs_from_state(state, params, app_spec), expected)
def map_viewer_params(cls, job_state, job_inputs, app_id, app_tag): # get app spec. if job_state is None or job_state.get("status", "") != "completed": return None spec = SpecManager().get_spec(app_id, app_tag) (output_widget, widget_params) = map_outputs_from_state( job_state, map_inputs_from_job(job_inputs, spec), spec) return {"name": output_widget, "tag": app_tag, "params": widget_params}
def map_viewer_params(Job, job_state, job_inputs, app_id, app_tag): # get app spec. if job_state is None or job_state['job_state'] != 'completed': return None spec = SpecManager().get_spec(app_id, app_tag) (output_widget, widget_params) = map_outputs_from_state( job_state, map_inputs_from_job(job_inputs, spec), spec) return {'name': output_widget, 'tag': app_tag, 'params': widget_params}
def test_map_outputs_from_state_simple(self): os.environ["KB_WORKSPACE_ID"] = self.workspace app_spec = { "parameters": [], "behavior": { "output_mapping": [{"narrative_system_variable": "workspace"}] }, } self.assertTupleEqual( map_outputs_from_state(None, None, app_spec), ("kbaseDefaultNarrativeOutput", self.workspace), )
def map_viewer_params(Job, job_state, job_inputs, app_id, app_tag): # get app spec. if job_state is None or job_state['job_state'] != 'completed': return None spec = SpecManager().get_spec(app_id, app_tag) (output_widget, widget_params) = map_outputs_from_state(job_state, map_inputs_from_job(job_inputs, spec), spec) return { 'name': output_widget, 'tag': app_tag, 'params': widget_params }
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 test_map_outputs_from_state_simple(self): os.environ['KB_WORKSPACE_ID'] = self.workspace app_spec = { 'parameters': [], 'behavior': { 'output_mapping': [{ 'narrative_system_variable': 'workspace' }] } } self.assertTupleEqual(map_outputs_from_state(None, None, app_spec), ('kbaseDefaultNarrativeOutput', self.workspace))
def test_map_outputs_from_state_simple(self): os.environ['KB_WORKSPACE_ID'] = self.workspace app_spec = { 'parameters': [], 'behavior': { 'output_mapping': [ { 'narrative_system_variable': 'workspace' } ] } } self.assertTupleEqual(map_outputs_from_state(None, None, app_spec), ('kbaseDefaultNarrativeOutput', self.workspace))
def test_map_outputs_from_state(self): os.environ['KB_WORKSPACE_ID'] = self.workspace app_spec = { 'widgets': { 'input': None, 'output': 'testOutputWidget' }, 'parameters': [], 'behavior': { 'kb_service_output_mapping': [ { 'narrative_system_variable': 'workspace', 'target_property': 'ws' }, { 'constant_value': 5, 'target_property': 'a_constant' }, { 'service_method_output_path': [1], 'target_property': 'a_path_ref' }, { 'input_parameter': 'an_input', 'target_property': 'an_input' } ] } } params = { 'an_input': 'input_val' } state = { 'result': ['foo', 'bar'] } expected = ( 'testOutputWidget', { 'ws': self.workspace, 'a_constant': 5, 'a_path_ref': 'bar', 'an_input': 'input_val' } ) self.assertTupleEqual(map_outputs_from_state(state, params, app_spec), expected)
def get_widget_info(job_id): state = get_test_job(job_id) if state.get("status") != COMPLETED_STATUS: return None job_input = state.get("job_input", {}) app_id = job_input.get("app_id", JOB_ATTR_DEFAULTS["app_id"]) params = job_input.get("params", JOB_ATTR_DEFAULTS["params"]) tag = job_input.get("narrative_cell_info", {}).get("tag", JOB_ATTR_DEFAULTS["tag"]) spec = get_test_spec(tag, app_id) with mock.patch("biokbase.narrative.app_util.clients.get", get_mock_client): output_widget, widget_params = map_outputs_from_state( state, map_inputs_from_job(params, spec), spec, ) return { "name": output_widget, "tag": tag, "params": widget_params, }
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_internal(self, app_id, params, tag, version, cell_id, run_id, **kwargs): self._send_comm_message('run_status', { 'event': 'validating_app', 'event_at': datetime.datetime.utcnow().isoformat() + 'Z', 'cell_id': cell_id, 'run_id': run_id }) ### TODO: this needs restructuring so that we can send back validation failure ### messages. Perhaps a separate function and catch the errors, or return an ### error structure. # Intro tests: self.spec_manager.check_app(app_id, tag, raise_exception=True) if version is not None and tag != "release": raise ValueError("App versions only apply to released app modules!") # Get the spec & params spec = self.spec_manager.get_spec(app_id, tag) if 'behavior' not in spec: raise ValueError("This app appears invalid - it has no defined behavior") behavior = spec['behavior'] if 'kb_service_input_mapping' in behavior: # it's a service! Should run this with run_app! raise ValueError('This app appears to be a long-running job! Please start it using the run_app function instead.') if 'script_module' in behavior or 'script_name' in behavior: # It's an old NJS script. These don't work anymore. raise ValueError('This app relies on a service that is now obsolete. Please contact the administrator.') # 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) = self._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 }) # now just map onto outputs. (output_widget, widget_params) = map_outputs_from_state([], params, spec) return WidgetManager().show_output_widget(output_widget, widget_params, cell_id=cell_id, tag=tag)
def _run_local_app_advanced_internal(self, app_id, params, widget_state, tag, version, cell_id, run_id, **kwargs): self._send_comm_message( 'run_status', { 'event': 'validating_app', 'event_at': datetime.datetime.utcnow().isoformat() + 'Z', 'cell_id': cell_id, 'run_id': run_id }) # Intro tests: self.spec_manager.check_app(app_id, tag, raise_exception=True) if version is not None and tag != "release": raise ValueError("App versions only apply to released modules!") # Get the spec & params spec = self.spec_manager.get_spec(app_id, tag) if 'behavior' not in spec: raise ValueError("This app appears invalid - " + "it has no defined behavior") behavior = spec['behavior'] if 'script_module' in behavior or 'script_name' in behavior: # It's an old NJS script. These don't work anymore. raise ValueError('This app relies on a service that is now ' + 'obsolete. Please contact the administrator.') # 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) = self._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. return WidgetManager().show_advanced_viewer_widget(output_widget, widget_params, widget_state, 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 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 _get_output_info(self, state): spec = self.app_spec() return map_outputs_from_state(state, map_inputs_from_job(self.parameters(), spec), spec)
def _get_output_info(self, state): spec = self.app_spec() return map_outputs_from_state( state, map_inputs_from_job(self.parameters(), spec), spec)
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 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 )