コード例 #1
0
ファイル: widgetmanager.py プロジェクト: msneddon/narrative
    def print_widget_inputs(self, widget_name, tag="release"):
        """
        Prints a list of expected user inputs for a widget.
        These are printed as the following:
        variable name - variable type - <extra information>

        for example:

        id - string - is a workspace object where the type is one of [KBaseGenomes.Genome, KBaseGenome.GenomeSet]
        or
        object_name - string - must be one of ["x", "y", "z"]

        Parameters
        ----------
        widget_name : string
            The name of the widget to print the inputs for.
        tag : string, default="release"
            The version tag to use when looking up widget information.
        """
        check_tag(tag, raise_exception=True)

        if widget_name not in self.widget_info[tag]:
            raise ValueError("Widget %s not found!" % widget_name)
        params = self.widget_info[tag][widget_name]["params"]
        print(widget_name)
        for p in params:
            if not params[p].get("is_constant", False):
                p_def = "%s - %s" % (p, params[p]["param_type"])
                if "allowed_types" in params[p]:
                    p_def = p_def + " - is a workspace object where the type is one of: %s" % (json.dumps(params[p]["allowed_types"]))
                if "allowed_values" in params[p]:
                    p_def = p_def + " - must be one of: %s" % (json.dumps(params[p]["allowed_values"]))
                print(p_def)
コード例 #2
0
ファイル: specmanager.py プロジェクト: mlhenderson/narrative
    def available_apps(self, tag="release"):
        """
        Lists the set of available apps in a pretty HTML way.
        Usable only in the Jupyter notebook.
        """
        check_tag(tag, raise_exception=True)

        tmpl="""
        <b>Available {{tag}} apps</b><br>
        <table class="table table-striped table-bordered table-condensed">
        <thead>
            <tr>
                <th>Id</th>
                <th>Name</th>
                <th>Subtitle</th>
            </tr>
        </thead>
        {% for m in apps %}
            <tr>
                <td>
                    {{ m.info.id }}
                </td>
                <td>
                    {{ m.info.name }}
                </td>
                <td>
                    {{ m.info.subtitle }}
                </td>
            </tr>
        {% endfor %}
        </table>
        """

        return HTML(Template(tmpl).render(tag=tag,
                                          apps=sorted(list(self.app_specs[tag].values()), key=lambda m: m['info']['id'])))
コード例 #3
0
ファイル: widgetmanager.py プロジェクト: msneddon/narrative
    def get_widget_constants(self, widget_name, tag="release"):
        """
        Returns a Dict with constants required for each widget.
        These constants are either part of the widget spec itself, or are provided by the current
        Narrative environment (e.g. Workspace name, user name).

        Parameters
        ----------
        widget_name : string
            The name of the widget to print the constants for.
        tag : string, default="release"
            The version tag to use when looking up widget information.

        """
        check_tag(tag, raise_exception=True)

        if widget_name not in self.widget_info[tag]:
            raise ValueError("Widget %s not found!" % widget_name)

        params = self.widget_info[tag][widget_name]["params"]
        constants = dict()
        for p in params:
            if params[p]["is_constant"]:
                if "param_value" in params[p]:
                    constants[p] = params[p]["param_value"]
                elif "allowed_values" in params[p] and len(params[p]["allowed_values"]) == 1:
                    constants[p] = params[p]["allowed_values"][0]
        return constants
コード例 #4
0
    def get_widget_constants(self, widget_name, tag="release"):
        """
        Returns a Dict with constants required for each widget.
        These constants are either part of the widget spec itself, or are provided by the current
        Narrative environment (e.g. Workspace name, user name).

        Parameters
        ----------
        widget_name : string
            The name of the widget to print the constants for.
        tag : string, default="release"
            The version tag to use when looking up widget information.

        """
        check_tag(tag, raise_exception=True)

        if widget_name not in self.widget_info[tag]:
            raise ValueError("Widget %s not found!" % widget_name)

        params = self.widget_info[tag][widget_name]["params"]
        constants = dict()
        for p in params:
            if params[p]["is_constant"]:
                if "param_value" in params[p]:
                    constants[p] = params[p]["param_value"]
                elif "allowed_values" in params[p] and len(params[p]["allowed_values"]) == 1:
                    constants[p] = params[p]["allowed_values"][0]
        return constants
コード例 #5
0
    def print_widget_inputs(self, widget_name, tag="release"):
        """
        Prints a list of expected user inputs for a widget.
        These are printed as the following:
        variable name - variable type - <extra information>

        for example:

        id - string - is a workspace object where the type is one of [KBaseGenomes.Genome, KBaseGenome.GenomeSet]
        or
        object_name - string - must be one of ["x", "y", "z"]

        Parameters
        ----------
        widget_name : string
            The name of the widget to print the inputs for.
        tag : string, default="release"
            The version tag to use when looking up widget information.
        """
        check_tag(tag, raise_exception=True)

        if widget_name not in self.widget_info[tag]:
            raise ValueError("Widget %s not found!" % widget_name)
        params = self.widget_info[tag][widget_name]["params"]
        print(widget_name)
        for p in params:
            if not params[p].get("is_constant", False):
                p_def = "%s - %s" % (p, params[p]["param_type"])
                if "allowed_types" in params[p]:
                    p_def = p_def + " - is a workspace object where the type is one of: %s" % (json.dumps(params[p]["allowed_types"]))
                if "allowed_values" in params[p]:
                    p_def = p_def + " - must be one of: %s" % (json.dumps(params[p]["allowed_values"]))
                print(p_def)
コード例 #6
0
ファイル: specmanager.py プロジェクト: msneddon/narrative
    def available_apps(self, tag="release"):
        """
        Lists the set of available apps in a pretty HTML way.
        Usable only in the Jupyter notebook.
        """
        check_tag(tag, raise_exception=True)

        tmpl="""
        <b>Available {{tag}} apps</b><br>
        <table class="table table-striped table-bordered table-condensed">
        <thead>
            <tr>
                <th>Id</th>
                <th>Name</th>
                <th>Subtitle</th>
            </tr>
        </thead>
        {% for m in apps %}
            <tr>
                <td>
                    {{ m.info.id }}
                </td>
                <td>
                    {{ m.info.name }}
                </td>
                <td>
                    {{ m.info.subtitle }}
                </td>
            </tr>
        {% endfor %}
        </table>
        """

        return HTML(Template(tmpl).render(tag=tag,
                                          apps=sorted(list(self.app_specs[tag].values()), key=lambda m: m['info']['id'])))
コード例 #7
0
ファイル: widgetmanager.py プロジェクト: msneddon/narrative
    def show_output_widget(self, widget_name, params, tag="release", title="", type="method", cell_id=None, check_widget=True, **kwargs):
        """
        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.
        tag : string, default="release"
            The version tag to use when looking up widget information.
        type : string, default="method"
            The type of output widget to show (options = method,app,viewer)
        check_widget: boolean, default=True
            If True, checks for the presense of the widget_name and get its known constants from
            the various app specs that invoke it. Raises a ValueError if the widget isn't found.
            If False, skip that step.
        **kwargs:
            These vary, based on the widget. Look up required variable names
            with WidgetManager.print_widget_inputs()
        """

        input_data = dict()

        if check_widget:
            check_tag(tag, raise_exception=True)
            if widget_name not in self.widget_info[tag]:
                raise ValueError("Widget %s not found with %s tag!" % (widget_name, tag))
            input_data = self.get_widget_constants(widget_name, tag)

        # Let the kwargs override constants
        input_data.update(params)

        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":"{{output_type}}",
                "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()),
                                             output_type=type,
                                             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)
コード例 #8
0
    def show_output_widget(self, widget_name, params, tag="release", title="", type="method", cell_id=None, check_widget=True, **kwargs):
        """
        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.
        tag : string, default="release"
            The version tag to use when looking up widget information.
        type : string, default="method"
            The type of output widget to show (options = method,app,viewer)
        check_widget: boolean, default=True
            If True, checks for the presense of the widget_name and get its known constants from
            the various app specs that invoke it. Raises a ValueError if the widget isn't found.
            If False, skip that step.
        **kwargs:
            These vary, based on the widget. Look up required variable names
            with WidgetManager.print_widget_inputs()
        """

        input_data = dict()

        if check_widget:
            check_tag(tag, raise_exception=True)
            if widget_name not in self.widget_info[tag]:
                raise ValueError("Widget %s not found with %s tag!" % (widget_name, tag))
            input_data = self.get_widget_constants(widget_name, tag)

        # Let the kwargs override constants
        input_data.update(params)

        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":"{{output_type}}",
                "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()),
                                             output_type=type,
                                             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)
コード例 #9
0
ファイル: specmanager.py プロジェクト: mlhenderson/narrative
    def check_app(self, app_id, tag='release', raise_exception=False):
        """
        Checks if a method (and release tag) is available for running and such.
        If raise_exception==True, and either the tag or app_id are invalid, a ValueError is raised.
        If raise_exception==False, and there's something invalid, it just returns False.
        If everything is hunky-dory, it returns True.
        """
        tag_ok = check_tag(tag, raise_exception=raise_exception)
        if not tag_ok:
            return False

        if app_id not in self.app_specs[tag]:
            if raise_exception:
                raise ValueError('Unknown app id "{}" tagged as "{}"'.format(app_id, tag))
            return False

        return True
コード例 #10
0
ファイル: specmanager.py プロジェクト: msneddon/narrative
    def check_app(self, app_id, tag='release', raise_exception=False):
        """
        Checks if a method (and release tag) is available for running and such.
        If raise_exception==True, and either the tag or app_id are invalid, a ValueError is raised.
        If raise_exception==False, and there's something invalid, it just returns False.
        If everything is hunky-dory, it returns True.
        """
        tag_ok = check_tag(tag, raise_exception=raise_exception)
        if not tag_ok:
            return False

        if app_id not in self.app_specs[tag]:
            if raise_exception:
                raise ValueError('Unknown app id "{}" tagged as "{}"'.format(app_id, tag))
            return False

        return True
コード例 #11
0
 def test_check_tag_bad_except(self):
     with self.assertRaises(ValueError):
         check_tag(self.bad_tag, raise_exception=True)
コード例 #12
0
 def test_check_tag_bad(self):
     self.assertFalse(check_tag(self.bad_tag))
コード例 #13
0
 def test_check_tag_good(self):
     self.assertTrue(check_tag(self.good_tag))
コード例 #14
0
ファイル: widgetmanager.py プロジェクト: msneddon/narrative
    def load_widget_info(self, tag="release", verbose=False):
        """
        Loads widget info and mapping.
        Eventually will fetch from kbase-ui, a kbase CDN, or the catalog service.
        For now, it gets known vis widgets from all method specs.

        This returns the a Dict where all keys are the name of a widget, and all values
        contain widget information in this structure:
        {
            "params": {
                "param_name": {
                    "is_constant": boolean,
                    "param_type": one of (string|boolean|dropdown),
                    "allowed_values": list of strings (exists when param_type==dropdown),
                    "allowed_types": list of data types (when param_type==string),
                    "param_value": something, mainly when is_constant==True
                }
        }
        """
        check_tag(tag, raise_exception=True)

        methods = self._sm.app_specs[tag].values()
        all_widgets = dict()

        # keys = widget names / namespaced require path / etc.
        # Individual widget values should be:
        # {params: {
        #     name1: {
        #         is_constant: boolean,
        #         value: (***something*** | None) (something = any structure),
        #         allowed: [ list of allowed values, optional ],
        #         type: (string, int, float, boolean, etc. list? hash?)
        #         allowed_types: [ list of allowed ws types, optional ]
        #     },
        #     name2: { is_constant, value }
        # }

        for method in methods:
            if 'output' not in method['widgets']:
                widget_name = self._default_output_widget
            else:
                widget_name = method['widgets']['output']
            if widget_name == 'null':
                if verbose:
                    print("Ignoring a widget named 'null' in {} - {}".format(tag, method['info']['id']))
                continue
            out_mapping = method['behavior'].get('kb_service_output_mapping', method['behavior'].get('output_mapping', None))
            if out_mapping is not None:
                params = {}
                for p in out_mapping:
                    param_name = p['target_property']
                    allowed_values = set()
                    is_constant = False
                    param_value = None
                    param_type = 'string'
                    allowed_types = set()

                    if 'constant_value' in p:
                        # add this val to a set of constant values for that param in that widget.
                        # if more than one possible, this need to be optional
                        is_constant = True
                        allowed_values.add(p['constant_value'])
                    if 'input_parameter' in p:
                        # this is a user given input. look up what it expects from the
                        # associated parameter of that name
                        in_param = p['input_parameter']
                        for spec_param in method['parameters']:
                            if spec_param['id'] == in_param:
                                # want its:
                                # field_type = text, float, number, ...
                                in_type = spec_param['field_type']
                                if in_type == 'text':
                                    param_type = 'string'
                                    if spec_param.has_key('text_options'):
                                        validate_as = spec_param['text_options'].get('validate_as', None)
                                        if validate_as == 'int':
                                            param_type = 'int'
                                        elif validate_as == 'float':
                                            param_type = 'float'
                                        if spec_param['text_options'].has_key('valid_ws_types'):
                                            allowed_types.update(spec_param['text_options']['valid_ws_types'])
                                elif param_type == 'textarea':
                                    param_type = 'string'
                                elif param_type == 'checkbox':
                                    param_type = 'boolean'
                                elif param_type == 'dropdown':
                                    param_type = 'dropdown'
                                    allowed_values.update([o['value'] for o in spec_param['dropdown_options']])
                    if 'narrative_system_variable' in p:
                        # this is something like the ws name or token that needs to get fetched
                        # by the system. Shouldn't be handled by the user.
                        is_constant = True
                        param_value = system_variable(p['narrative_system_variable'])
                    if 'service_method_output_path' in p:
                        param_type = 'from_service_output'

                    param_info = {
                        'is_constant': is_constant,
                        'param_type': param_type,
                    }
                    if allowed_values:
                        param_info['allowed_values'] = allowed_values
                    if allowed_types:
                        param_info['allowed_types'] = allowed_types
                    if param_value:
                        param_info['param_value'] = param_value
                    params[param_name] = param_info

                if widget_name in all_widgets:
                    # if it's already there, just update the allowed_types and allowed_values for some params that have them
                    for p_name in params.keys():
                        if 'allowed_types' in params[p_name]:
                            if p_name not in all_widgets[widget_name]['params']:
                                all_widgets[widget_name]['params'][p_name] = params[p_name]
                            else:
                                widget_types = all_widgets[widget_name]['params'].get(p_name, {}).get('allowed_types', set())
                                widget_types.update(params[p_name]['allowed_types'])
                                all_widgets[widget_name]['params'][p_name]['allowed_types'] = widget_types
                        if 'allowed_values' in params[p_name]:
                            if p_name not in all_widgets[widget_name]['params']:
                                all_widgets[widget_name]['params'][p_name] = params[p_name]
                            else:
                                widget_vals = all_widgets[widget_name]['params'].get(p_name, {}).get('allowed_values', set())
                                widget_vals.update(params[p_name]['allowed_values'])
                                all_widgets[widget_name]['params'][p_name]['allowed_values'] = widget_vals
                else:
                    all_widgets[widget_name] = { 'params': params }

        # finally, turn all sets into lists
        for w in all_widgets:
            for p in all_widgets[w]["params"]:
                if "allowed_types" in all_widgets[w]["params"][p]:
                    all_widgets[w]["params"][p]["allowed_types"] = list(all_widgets[w]["params"][p]["allowed_types"])
                if "allowed_values" in all_widgets[w]['params'][p]:
                    all_widgets[w]["params"][p]["allowed_values"] = list(all_widgets[w]["params"][p]["allowed_values"])
        return all_widgets
コード例 #15
0
    def load_widget_info(self, tag="release", verbose=False):
        """
        Loads widget info and mapping.
        Eventually will fetch from kbase-ui, a kbase CDN, or the catalog service.
        For now, it gets known vis widgets from all method specs.

        This returns the a Dict where all keys are the name of a widget, and all values
        contain widget information in this structure:
        {
            "params": {
                "param_name": {
                    "is_constant": boolean,
                    "param_type": one of (string|boolean|dropdown),
                    "allowed_values": list of strings (exists when param_type==dropdown),
                    "allowed_types": list of data types (when param_type==string),
                    "param_value": something, mainly when is_constant==True
                }
        }
        """
        check_tag(tag, raise_exception=True)

        methods = self._sm.app_specs[tag].values()
        all_widgets = dict()

        # keys = widget names / namespaced require path / etc.
        # Individual widget values should be:
        # {params: {
        #     name1: {
        #         is_constant: boolean,
        #         value: (***something*** | None) (something = any structure),
        #         allowed: [ list of allowed values, optional ],
        #         type: (string, int, float, boolean, etc. list? hash?)
        #         allowed_types: [ list of allowed ws types, optional ]
        #     },
        #     name2: { is_constant, value }
        # }

        for method in methods:
            if 'output' not in method['widgets']:
                widget_name = self._default_output_widget
            else:
                widget_name = method['widgets']['output']
            if widget_name == 'null':
                if verbose:
                    print("Ignoring a widget named 'null' in {} - {}".format(tag, method['info']['id']))
                continue
            out_mapping = method['behavior'].get('kb_service_output_mapping', method['behavior'].get('output_mapping', None))
            if out_mapping is not None:
                params = {}
                for p in out_mapping:
                    param_name = p['target_property']
                    allowed_values = set()
                    is_constant = False
                    param_value = None
                    param_type = 'string'
                    allowed_types = set()

                    if 'constant_value' in p:
                        # add this val to a set of constant values for that param in that widget.
                        # if more than one possible, this need to be optional
                        is_constant = True
                        allowed_values.add(p['constant_value'])
                    if 'input_parameter' in p:
                        # this is a user given input. look up what it expects from the
                        # associated parameter of that name
                        in_param = p['input_parameter']
                        for spec_param in method['parameters']:
                            if spec_param['id'] == in_param:
                                # want its:
                                # field_type = text, float, number, ...
                                in_type = spec_param['field_type']
                                if in_type == 'text':
                                    param_type = 'string'
                                    if spec_param.has_key('text_options'):
                                        validate_as = spec_param['text_options'].get('validate_as', None)
                                        if validate_as == 'int':
                                            param_type = 'int'
                                        elif validate_as == 'float':
                                            param_type = 'float'
                                        if spec_param['text_options'].has_key('valid_ws_types'):
                                            allowed_types.update(spec_param['text_options']['valid_ws_types'])
                                elif param_type == 'textarea':
                                    param_type = 'string'
                                elif param_type == 'checkbox':
                                    param_type = 'boolean'
                                elif param_type == 'dropdown':
                                    param_type = 'dropdown'
                                    allowed_values.update([o['value'] for o in spec_param['dropdown_options']])
                    if 'narrative_system_variable' in p:
                        # this is something like the ws name or token that needs to get fetched
                        # by the system. Shouldn't be handled by the user.
                        is_constant = True
                        param_value = system_variable(p['narrative_system_variable'])
                    if 'service_method_output_path' in p:
                        param_type = 'from_service_output'

                    param_info = {
                        'is_constant': is_constant,
                        'param_type': param_type,
                    }
                    if allowed_values:
                        param_info['allowed_values'] = allowed_values
                    if allowed_types:
                        param_info['allowed_types'] = allowed_types
                    if param_value:
                        param_info['param_value'] = param_value
                    params[param_name] = param_info

                if widget_name in all_widgets:
                    # if it's already there, just update the allowed_types and allowed_values for some params that have them
                    for p_name in params.keys():
                        if 'allowed_types' in params[p_name]:
                            if p_name not in all_widgets[widget_name]['params']:
                                all_widgets[widget_name]['params'][p_name] = params[p_name]
                            else:
                                widget_types = all_widgets[widget_name]['params'].get(p_name, {}).get('allowed_types', set())
                                widget_types.update(params[p_name]['allowed_types'])
                                all_widgets[widget_name]['params'][p_name]['allowed_types'] = widget_types
                        if 'allowed_values' in params[p_name]:
                            if p_name not in all_widgets[widget_name]['params']:
                                all_widgets[widget_name]['params'][p_name] = params[p_name]
                            else:
                                widget_vals = all_widgets[widget_name]['params'].get(p_name, {}).get('allowed_values', set())
                                widget_vals.update(params[p_name]['allowed_values'])
                                all_widgets[widget_name]['params'][p_name]['allowed_values'] = widget_vals
                else:
                    all_widgets[widget_name] = { 'params': params }

        # finally, turn all sets into lists
        for w in all_widgets:
            for p in all_widgets[w]["params"]:
                if "allowed_types" in all_widgets[w]["params"][p]:
                    all_widgets[w]["params"][p]["allowed_types"] = list(all_widgets[w]["params"][p]["allowed_types"])
                if "allowed_values" in all_widgets[w]['params'][p]:
                    all_widgets[w]["params"][p]["allowed_values"] = list(all_widgets[w]["params"][p]["allowed_values"])
        return all_widgets
コード例 #16
0
    def load_widget_info(self, tag="release", verbose=False):
        """
        Loads widget info and mapping.
        Eventually will fetch from kbase-ui, a kbase CDN, or the catalog service.
        For now, it gets known vis widgets from all method specs.

        This returns the a Dict where all keys are the name of a widget, and all values
        contain widget information in this structure:
        {
            "params": {
                "param_name": {
                    "is_constant": boolean,
                    "param_type": one of (string|boolean|dropdown),
                    "allowed_values": list of strings (exists when param_type==dropdown),
                    "allowed_types": list of data types (when param_type==string),
                    "param_value": something, mainly when is_constant==True
                }
        }
        """
        check_tag(tag, raise_exception=True)

        methods = list(self._sm.app_specs[tag].values())
        all_widgets = dict()
        """
        keys = widget names / namespaced require path / etc.
         Individual widget values should be:
         {params: {
             name1: {
                 is_constant: boolean,
                 value: (***something*** | None) (something = any structure),
                 allowed: [ list of allowed values, optional ],
                 type: (string, int, float, boolean, etc. list? hash?)
                 allowed_types: [ list of allowed ws types, optional ]
             },
             name2: { is_constant, value }
        }
        """

        for method in methods:
            if "output" not in method["widgets"]:
                widget_name = self._default_output_widget
            else:
                widget_name = method["widgets"]["output"]
            if widget_name == "null":
                if verbose:
                    print(
                        f"Ignoring a widget named 'null' in {tag} - {method['info']['id']}"
                    )
                continue
            out_mapping = method["behavior"].get(
                "kb_service_output_mapping",
                method["behavior"].get("output_mapping", None),
            )
            if out_mapping is not None:
                params = {}
                for p in out_mapping:
                    param_name = p["target_property"]
                    allowed_values = set()
                    is_constant = False
                    param_value = None
                    param_type = "string"
                    allowed_types = set()

                    if "constant_value" in p:
                        # add this val to a set of constant values for that param in that widget.
                        # if more than one possible, this need to be optional
                        is_constant = True
                        allowed_values.add(p["constant_value"])
                    if "input_parameter" in p:
                        # this is a user given input. look up what it expects from the
                        # associated parameter of that name
                        in_param = p["input_parameter"]
                        for spec_param in method["parameters"]:
                            if spec_param["id"] == in_param:
                                # want its:
                                # field_type = text, float, number, ...
                                in_type = spec_param["field_type"]
                                if in_type == "text":
                                    param_type = "string"
                                    if "text_options" in spec_param:
                                        validate_as = spec_param[
                                            "text_options"].get(
                                                "validate_as", None)
                                        if validate_as == "int":
                                            param_type = "int"
                                        elif validate_as == "float":
                                            param_type = "float"
                                        if ("valid_ws_types"
                                                in spec_param["text_options"]):
                                            allowed_types.update(
                                                spec_param["text_options"]
                                                ["valid_ws_types"])
                                elif param_type == "textarea":
                                    param_type = "string"
                                elif param_type == "checkbox":
                                    param_type = "boolean"
                                elif param_type == "dropdown":
                                    param_type = "dropdown"
                                    allowed_values.update([
                                        o["value"]
                                        for o in spec_param["dropdown_options"]
                                    ])
                    if "narrative_system_variable" in p:
                        # this is something like the ws name or token that needs to get fetched
                        # by the system. Shouldn't be handled by the user.
                        is_constant = True
                        param_value = system_variable(
                            p["narrative_system_variable"])
                    if "service_method_output_path" in p:
                        param_type = "from_service_output"

                    param_info = {
                        "is_constant": is_constant,
                        "param_type": param_type,
                    }
                    if allowed_values:
                        param_info["allowed_values"] = allowed_values
                    if allowed_types:
                        param_info["allowed_types"] = allowed_types
                    if param_value:
                        param_info["param_value"] = param_value
                    params[param_name] = param_info

                if widget_name in all_widgets:
                    # if it's already there, just update the allowed_types and allowed_values
                    # for some params that have them
                    for p_name in params.keys():
                        if "allowed_types" in params[p_name]:
                            if p_name not in all_widgets[widget_name][
                                    "params"]:
                                all_widgets[widget_name]["params"][
                                    p_name] = params[p_name]
                            else:
                                widget_types = (
                                    all_widgets[widget_name]["params"].get(
                                        p_name,
                                        {}).get("allowed_types", set()))
                                widget_types.update(
                                    params[p_name]["allowed_types"])
                                all_widgets[widget_name]["params"][p_name][
                                    "allowed_types"] = widget_types
                        if "allowed_values" in params[p_name]:
                            if p_name not in all_widgets[widget_name][
                                    "params"]:
                                all_widgets[widget_name]["params"][
                                    p_name] = params[p_name]
                            else:
                                widget_vals = (
                                    all_widgets[widget_name]["params"].get(
                                        p_name,
                                        {}).get("allowed_values", set()))
                                widget_vals.update(
                                    params[p_name]["allowed_values"])
                                all_widgets[widget_name]["params"][p_name][
                                    "allowed_values"] = widget_vals
                else:
                    all_widgets[widget_name] = {"params": params}

        # finally, turn all sets into lists
        for w in all_widgets:
            for p in all_widgets[w]["params"]:
                if "allowed_types" in all_widgets[w]["params"][p]:
                    all_widgets[w]["params"][p]["allowed_types"] = list(
                        all_widgets[w]["params"][p]["allowed_types"])
                if "allowed_values" in all_widgets[w]["params"][p]:
                    all_widgets[w]["params"][p]["allowed_values"] = list(
                        all_widgets[w]["params"][p]["allowed_values"])
        return all_widgets