team-10/env/Lib/site-packages/streamlit/runtime/state/widgets.py
2025-08-02 07:34:44 +02:00

135 lines
5.2 KiB
Python

# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from typing import TYPE_CHECKING
from streamlit.runtime.state.common import (
RegisterWidgetResult,
T,
ValueFieldName,
WidgetArgs,
WidgetCallback,
WidgetDeserializer,
WidgetKwargs,
WidgetMetadata,
WidgetSerializer,
user_key_from_element_id,
)
if TYPE_CHECKING:
from streamlit.runtime.scriptrunner import ScriptRunContext
def register_widget(
element_id: str,
*,
deserializer: WidgetDeserializer[T],
serializer: WidgetSerializer[T],
ctx: ScriptRunContext | None,
on_change_handler: WidgetCallback | None = None,
args: WidgetArgs | None = None,
kwargs: WidgetKwargs | None = None,
value_type: ValueFieldName,
) -> RegisterWidgetResult[T]:
"""Register a widget with Streamlit, and return its current value.
NOTE: This function should be called after the proto has been filled.
Parameters
----------
element_id : str
The id of the element. Must be unique.
deserializer : WidgetDeserializer[T]
Called to convert a widget's protobuf value to the value returned by
its st.<widget_name> function.
serializer : WidgetSerializer[T]
Called to convert a widget's value to its protobuf representation.
ctx : ScriptRunContext or None
Used to ensure uniqueness of widget IDs, and to look up widget values.
on_change_handler : WidgetCallback or None
An optional callback invoked when the widget's value changes.
args : WidgetArgs or None
args to pass to on_change_handler when invoked
kwargs : WidgetKwargs or None
kwargs to pass to on_change_handler when invoked
value_type: ValueType
The value_type the widget is going to use.
We use this information to start with a best-effort guess for the value_type
of each widget. Once we actually receive a proto for a widget from the
frontend, the guess is updated to be the correct type. Unfortunately, we're
not able to always rely on the proto as the type may be needed earlier.
Thankfully, in these cases (when value_type == "trigger_value"), the static
table here being slightly inaccurate should never pose a problem.
Returns
-------
register_widget_result : RegisterWidgetResult[T]
Provides information on which value to return to the widget caller,
and whether the UI needs updating.
- Unhappy path:
- Our ScriptRunContext doesn't exist (meaning that we're running
as a "bare script" outside streamlit).
- We are disconnected from the SessionState instance.
In both cases we'll return a fallback RegisterWidgetResult[T].
- Happy path:
- The widget has already been registered on a previous run but the
user hasn't interacted with it on the client. The widget will have
the default value it was first created with. We then return a
RegisterWidgetResult[T], containing this value.
- The widget has already been registered and the user *has*
interacted with it. The widget will have that most recent
user-specified value. We then return a RegisterWidgetResult[T],
containing this value.
For both paths a widget return value is provided, allowing the widgets
to be used in a non-streamlit setting.
"""
# Create the widget's updated metadata, and register it with session_state.
metadata = WidgetMetadata(
element_id,
deserializer,
serializer,
value_type=value_type,
callback=on_change_handler,
callback_args=args,
callback_kwargs=kwargs,
fragment_id=ctx.current_fragment_id if ctx else None,
)
return register_widget_from_metadata(metadata, ctx)
def register_widget_from_metadata(
metadata: WidgetMetadata[T],
ctx: ScriptRunContext | None,
) -> RegisterWidgetResult[T]:
"""Register a widget and return its value, using an already constructed
`WidgetMetadata`.
This is split out from `register_widget` to allow caching code to replay
widgets by saving and reusing the completed metadata.
See `register_widget` for details on what this returns.
"""
if ctx is None:
# Early-out if we don't have a script run context (which probably means
# we're running as a "bare" Python script, and not via `streamlit run`).
return RegisterWidgetResult.failure(deserializer=metadata.deserializer)
widget_id = metadata.id
user_key = user_key_from_element_id(widget_id)
return ctx.session_state.register_widget(metadata, user_key)