def get_widget_metadata(annotation, default):
    """Return dict w/ instructions for widget instantiation.

    In this function we inspect the annotation and default
    value of a parameter to determine which widget should
    we use to hold and/or change such value in the node
    for that parameter.

    Sometimes, such data provided in the parameter is not
    enough per se to determine the usage of a specific
    widget. Even when this is the case, we defined some
    extra value/annotation combinations that can be
    considered syntax sugar to define a particular widget.

    Even if we cannot define any particular widget in the
    end, we still return a dict with instructions to
    define a "default holder" widget, which is a general
    widget whose sole purpose is holding a string
    representation of the default value.

    Parameters
    ==========
    annotation (any python object)
        represents data to help define a widget.
    default (any python object, except inspect._empty)
        type provided by the user for the given default
        value
    """
    ######## retrieve/inspect data ########

    ### define an empty widget name
    widget_name = ""

    ### if the annotation is a dict instance,
    ### has a non-empty 'widget_name' field
    ### though, treat such dict instance as
    ### extra metadata provided by the user

    if isinstance(annotation, dict) and annotation.get("widget_name"):

        ## alias the annotation as metadata
        metadata = annotation

        ## store the widget name
        widget_name = metadata["widget_name"]

        ## retrieve a widget_kwargs dict from the
        ## metadata, creating it if it doesn't exists
        widget_kwargs = metadata.setdefault("widget_kwargs", {})

        ## store the default value in the widget
        ## kwargs 'value' field
        widget_kwargs["value"] = default

        ## if the metadata specifies a 'type', use it
        ## as the new annotation

        try:
            annotation = metadata["type"]
        except KeyError:
            pass

    ### if no specific metadata for a widget was provided,
    ### define a widget kwargs dict with the default added
    ### to it in the 'value' field
    else:
        widget_kwargs = {"value": default}

    ### from this point on, we must consider the annotation
    ### as the type for the input
    type_ = annotation

    ######## adjust and return widget data ########

    ### if a widget name was provided it means the user
    ### also provided the needed data for instantiating
    ### the widget, so we return the instructions to
    ### define such widget, but only after checking
    ### if the widget in question is an int float entry,
    ### in which case extra processing is needed before
    ### doing so

    if widget_name:

        ## handle int float entry specific requirements
        ## if widget name matches;
        ##
        ## here we purposefully don't catch possible
        ## errors raised by the function used, since they
        ## mean the data isn't suitable for defining the
        ## widget in question

        if widget_name == "int_float_entry":

            process_int_float_entry_data(widget_kwargs, type_)

        elif widget_name == "color_button":

            if type_ is tuple or (isinstance(type_, (tuple, list)) and tuple in type_):
                widget_kwargs["color_format"] = "rgb_tuple"

            elif type_ is str or (isinstance(type_, (tuple, list)) and str in type_):
                widget_kwargs["color_format"] = "hex_string"

            else:

                raise TypeError(
                    "in the special annotation using a dict, the value in"
                    "the 'type' key for color buttons must be tuple, str, or"
                    " a tuple/list containing one or both of them."
                )

        ## regardless of whether widget_name is equal to
        ## 'int_float_entry' or not, return dict with
        ## instructions to instantiate the widget named
        ## in widget_name with the given keyword arguments

        return {"widget_name": widget_name, "widget_kwargs": widget_kwargs}

    ### if a widget name wasn't specified, though, use the
    ### type_ and value (widget_kwargs['value']) to
    ### determine whether instructions for a widget can be
    ### put together

    else:

        ## retrieve the value
        value = widget_kwargs["value"]

        ## if the value isn't a python literal, a default
        ## holder widget must be used

        try:
            literal_eval(repr(value))

        except Exception:

            return {"widget_name": "default_holder", "widget_kwargs": widget_kwargs}

        ## if the type information is in reality
        ## a sentinel value meaning there's no actual
        ## type data used, a default holder widget must
        ## be used as well

        if type_ is Parameter.empty:

            return {"widget_name": "default_holder", "widget_kwargs": widget_kwargs}

        ## if type is str and value is an instance
        ## of it use a string entry widget

        elif type_ is str and isinstance(value, str):

            return {"widget_name": "string_entry", "widget_kwargs": widget_kwargs}

        ## if type is boolean and value is an instance
        ## of it use a check button widget

        elif type_ is bool and isinstance(value, bool):

            return {"widget_name": "check_button", "widget_kwargs": widget_kwargs}

        ### perform extra checks;
        ###
        ### if we got to this point, without returning
        ### we try going through additional more complex
        ### checks to determine if an widget can be
        ### defined by the value (in the kwargs) and type;
        ###
        ### we do so by iterating over special functions
        ### and associated widget names checking whether
        ### the widget in question can be defined by
        ### the available data

        for processing_operation, widget_name in (
            (process_none_or_boolean_option_tray, "option_tray"),
            (process_int_float_entry_data, "int_float_entry"),
        ):

            ## check whether value (in kwargs) and type
            ## can be used to define specific widget
            try:
                processing_operation(widget_kwargs, type_)

            ## if not, then just pass
            except (TypeError, ValueError):
                pass

            ## otherwise, we return data specifying the
            ## widget in question

            else:

                return {"widget_name": widget_name, "widget_kwargs": widget_kwargs}

        ### if we get to this point without ever returning
        ### then it means there is no way to define other
        ### widget, so we just return data to define the
        ### default holder widget

        return {"widget_name": "default_holder", "widget_kwargs": widget_kwargs}
Return dict w/ instructions for widget instantiation.

    In this function we inspect the annotation and default
    value of a parameter to determine which widget should
    we use to hold and/or change such value in the node
    for that parameter.

    Sometimes, such data provided in the parameter is not
    enough per se to determine the usage of a specific
    widget. Even when this is the case, we defined some
    extra value/annotation combinations that can be
    considered syntax sugar to define a particular widget.

    Even if we cannot define any particular widget in the
    end, we still return a dict with instructions to
    define a "default holder" widget, which is a general
    widget whose sole purpose is holding a string
    representation of the default value.

    Parameters
    ==========
    annotation (any python object)
        represents data to help define a widget.
    default (any python object, except inspect._empty)
        type provided by the user for the given default
        value
    
nodezator/graphman/widget/utils.py