コード例 #1
0
ファイル: widgets.py プロジェクト: mesmith027/streamlit
def register_widget(
    element_type: str,
    element_proto: WidgetProto,
    deserializer: WidgetDeserializer,
    serializer: WidgetSerializer,
    user_key: Optional[str] = None,
    widget_func_name: Optional[str] = None,
    on_change_handler: Optional[WidgetCallback] = None,
    args: Optional[WidgetArgs] = None,
    kwargs: Optional[WidgetKwargs] = None,
) -> Tuple[Any, bool]:
    """Register a widget with Streamlit, and return its current value.
    NOTE: This function should be called after the proto has been filled.

    Parameters
    ----------
    element_type : str
        The type of the element as stored in proto.
    element_proto : proto
        The proto of the specified type (e.g. Button/Multiselect/Slider proto)
    user_key : Optional[str]
        Optional user-specified string to use as the widget ID.
        If this is None, we'll generate an ID by hashing the element.
    widget_func_name : Optional[str]
        The widget's DeltaGenerator function name, if it's different from
        its element_type. Custom components are a special case: they all have
        the element_type "component_instance", but are instantiated with
        dynamically-named functions.
    on_change_handler : Optional[WidgetCallback]
        An optional callback invoked when the widget's value changes.
    deserializer : Optional[WidgetDeserializer]
        Called to convert a widget's protobuf value to the value returned by
        its st.<widget_name> function.
    args : Optional[WidgetArgs]
        args to pass to on_change_handler when invoked
    kwargs : Optional[WidgetKwargs]
        kwargs to pass to on_change_handler when invoked

    Returns
    -------
    ui_value : Tuple[Any, bool]
        - If our ReportContext doesn't exist (meaning that we're running
        a "bare script" outside of streamlit), we'll return None.
        - Else if this is a new widget, it won't yet have a value and we'll
        return None.
        - Else if the widget has already been registered on a previous run but
        the user hasn't interacted with it on the client, it will have the
        default value it was first created with.
        - Else the widget has already been registered and the user *has*
        interacted with it, it will have that most recent user-specified value.

    """
    widget_id = _get_widget_id(element_type, element_proto, user_key)
    element_proto.id = widget_id

    ctx = report_thread.get_report_ctx()
    if ctx is None:
        # Early-out if we're not running inside a ReportThread (which
        # probably means we're running as a "bare" Python script, and
        # not via `streamlit run`).
        return (deserializer(None, ""), False)

    # Register the widget, and ensure another widget with the same id hasn't
    # already been registered.
    added = ctx.widget_ids_this_run.add(widget_id)
    if not added:
        raise DuplicateWidgetID(
            _build_duplicate_widget_message(
                widget_func_name
                if widget_func_name is not None else element_type,
                user_key,
            ))

    session_state = ctx.session_state

    metadata = WidgetMetadata(
        widget_id,
        deserializer,
        serializer,
        value_type=element_type_to_value_type[element_type],
        callback=on_change_handler,
        callback_args=args,
        callback_kwargs=kwargs,
    )
    # TODO: should these be merged into a more generic call so this code doesn't need to know about keyed vs unkeyed?
    if user_key is not None:
        session_state.set_keyed_widget(metadata, widget_id, user_key)
    else:
        session_state.set_unkeyed_widget(metadata, widget_id)
    value_changed = session_state.should_set_frontend_state_value(
        widget_id, user_key)

    val = session_state.get_value_for_registration(widget_id)

    return (val, value_changed)