streamlit-nightly 1.52.3.dev20260108__py3-none-any.whl → 1.52.3.dev20260110__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- streamlit/components/v2/__init__.py +3 -3
- streamlit/components/v2/types.py +4 -4
- streamlit/config.py +14 -0
- streamlit/elements/lib/options_selector_utils.py +98 -0
- streamlit/elements/widgets/multiselect.py +19 -9
- streamlit/elements/widgets/selectbox.py +12 -24
- streamlit/proto/MetricsEvent_pb2.py +4 -4
- streamlit/proto/MetricsEvent_pb2.pyi +4 -1
- streamlit/proto/PageProfile_pb2.py +6 -6
- streamlit/proto/PageProfile_pb2.pyi +11 -1
- streamlit/runtime/metrics_util.py +4 -0
- streamlit/runtime/runtime.py +3 -0
- streamlit/starlette.py +34 -0
- streamlit/static/index.html +1 -1
- streamlit/static/manifest.json +300 -300
- streamlit/static/static/js/{ErrorOutline.esm.j3b3OjAK.js → ErrorOutline.esm.BcqUpfNe.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.DCizXv6Q.js → FileDownload.esm.CtJWBuub.js} +1 -1
- streamlit/static/static/js/{FileHelper.EpMV5UVe.js → FileHelper.D0dQPhOs.js} +1 -1
- streamlit/static/static/js/{FormClearHelper.lF7Ran5M.js → FormClearHelper.Cm3GDSk6.js} +1 -1
- streamlit/static/static/js/{InputInstructions.CMvqhPhy.js → InputInstructions.D7Hxdzwv.js} +1 -1
- streamlit/static/static/js/{Particles.DsGe8psi.js → Particles.vAUDtAR8.js} +1 -1
- streamlit/static/static/js/{ProgressBar.DzoKn4D-.js → ProgressBar.Dp2CGRba.js} +2 -2
- streamlit/static/static/js/{StreamlitSyntaxHighlighter.CFab0b_b.js → StreamlitSyntaxHighlighter.DC0000nJ.js} +1 -1
- streamlit/static/static/js/{TableChart.esm.nZsTq1Sb.js → TableChart.esm.DDVoSKOT.js} +1 -1
- streamlit/static/static/js/{Toolbar.CFMvwQYl.js → Toolbar.CuMH-Gqe.js} +1 -1
- streamlit/static/static/js/{WidgetLabelHelpIconInline.D2EEUEQX.js → WidgetLabelHelpIconInline.WAReecol.js} +1 -1
- streamlit/static/static/js/{base-input.DKTA2QNz.js → base-input.BX9Jll5o.js} +4 -4
- streamlit/static/static/js/{checkbox.D9H9J-_W.js → checkbox.BzMHUSz1.js} +1 -1
- streamlit/static/static/js/{createDownloadLinkElement.DCk6EhPM.js → createDownloadLinkElement.CviG5BQx.js} +1 -1
- streamlit/static/static/js/{data-grid-overlay-editor.DExrGdqs.js → data-grid-overlay-editor.Dzo9A4l6.js} +1 -1
- streamlit/static/static/js/{downloader.CLJ7BreF.js → downloader.DIDvj0d5.js} +1 -1
- streamlit/static/static/js/{embed.CxOHZWx2.js → embed.C8qeQ38b.js} +6 -6
- streamlit/static/static/js/{es6.C99ebre4.js → es6.Dpcc-U7U.js} +2 -2
- streamlit/static/static/js/{formatNumber.D_w4fBsk.js → formatNumber.CPvuaBa8.js} +1 -1
- streamlit/static/static/js/{iconPosition.Cfhw1RkE.js → iconPosition.y0q-Rqem.js} +1 -1
- streamlit/static/static/js/{iframeResizer.contentWindow.BcWUIYOe.js → iframeResizer.contentWindow.DblExdXF.js} +1 -1
- streamlit/static/static/js/{index.BWK_h3IL.js → index.B-g6lwYa.js} +1 -1
- streamlit/static/static/js/{index.DoLorXMA.js → index.B10MmI2m.js} +1 -1
- streamlit/static/static/js/{index.Dx8TcTHV.js → index.B6vCS66f.js} +6 -6
- streamlit/static/static/js/{index.Bp_LrAiI.js → index.B9TG5Ah8.js} +1 -1
- streamlit/static/static/js/{index.CrJ9KZpt.js → index.BDb0PRvK.js} +1 -1
- streamlit/static/static/js/{index.1AemKTSK.js → index.BGufEmCz.js} +1 -1
- streamlit/static/static/js/{index.7Q3Iaebc.js → index.BItU4jMo.js} +1 -1
- streamlit/static/static/js/{index.D18KqoUa.js → index.BPMqWDef.js} +1 -1
- streamlit/static/static/js/index.BTHi5W25.js +1 -0
- streamlit/static/static/js/{index.BHx4Qw7z.js → index.BVN9cI-k.js} +1 -1
- streamlit/static/static/js/index.BWOP7HFT.js +1 -0
- streamlit/static/static/js/{index.DDx6TP95.js → index.BXYgO5B8.js} +1 -1
- streamlit/static/static/js/{index.DkSjHoXw.js → index.BZBWLU1C.js} +8 -8
- streamlit/static/static/js/{index.f_s01aPm.js → index.BfZdZpv-.js} +2 -2
- streamlit/static/static/js/{index.C7_5JMRC.js → index.Bxe7fKbw.js} +1 -1
- streamlit/static/static/js/{index.BcbR2mbc.js → index.C1ElSZEy.js} +1 -1
- streamlit/static/static/js/index.C26ZOVFL.js +1 -0
- streamlit/static/static/js/{index.aJ3XRx8R.js → index.C7lwRBvF.js} +1 -1
- streamlit/static/static/js/{index.CGX2fllG.js → index.C93QGPyk.js} +1 -1
- streamlit/static/static/js/{index.COjurlZk.js → index.CCDejIvL.js} +2 -2
- streamlit/static/static/js/index.CcMmNHAq.js +1 -0
- streamlit/static/static/js/index.D42y-GeO.js +1 -0
- streamlit/static/static/js/{index.C0VFHmJN.js → index.D69ULFWq.js} +1 -1
- streamlit/static/static/js/{index.V4C1Oi-F.js → index.DB4MbQ40.js} +3 -3
- streamlit/static/static/js/{index.DJ4GBc1k.js → index.DRFJgBf-.js} +1 -1
- streamlit/static/static/js/{index.BXQNt1hj.js → index.DTK-btqV.js} +1 -1
- streamlit/static/static/js/{index.CFE-yHdT.js → index.DZEQ0G7H.js} +1 -1
- streamlit/static/static/js/{index.Bu3Lto_G.js → index.DaU1ayM7.js} +1 -1
- streamlit/static/static/js/{index.DSSQzzPk.js → index.Dla9XiNe.js} +2 -2
- streamlit/static/static/js/{index.DiZfOR0A.js → index.DmQqT9OM.js} +1 -1
- streamlit/static/static/js/{index.DuFqxjbN.js → index.DppScppA.js} +1 -1
- streamlit/static/static/js/{index.Dqphk1ee.js → index.Dr8b3Vn6.js} +1 -1
- streamlit/static/static/js/{index.CPo5dtx7.js → index.DvQ7-afx.js} +1 -1
- streamlit/static/static/js/{index.ATP5607r.js → index.F-NmmwfK.js} +1 -1
- streamlit/static/static/js/{index.gnFSTAhI.js → index.MKI8t7l2.js} +1 -1
- streamlit/static/static/js/{index.BXnQdCa5.js → index.RRAKXgBZ.js} +1 -1
- streamlit/static/static/js/{index.CyVBY8PG.js → index.VSsf6tsu.js} +2 -2
- streamlit/static/static/js/{index.DcudoGfL.js → index.aEeM0ekc.js} +1 -1
- streamlit/static/static/js/{index.Ds-w0zIo.js → index.eweE9HKU.js} +1 -1
- streamlit/static/static/js/{index.CBZQ_6AF.js → index.gr6yGiCL.js} +1 -1
- streamlit/static/static/js/{index.mZ1qbnKs.js → index.kKkHk9Mc.js} +1 -1
- streamlit/static/static/js/index.pMvzHC7z.js +1 -0
- streamlit/static/static/js/{index.DIIdzDwK.js → index.pgifwCIr.js} +1 -1
- streamlit/static/static/js/index.q83b8_8b.js +1 -0
- streamlit/static/static/js/{index.BzQChe4y.js → index.u2AvcQQT.js} +1 -1
- streamlit/static/static/js/{index.CrzXL2V8.js → index.w2_VrtVw.js} +1 -1
- streamlit/static/static/js/{index.DbmtfcDm.js → index.wv1DYVsn.js} +1 -1
- streamlit/static/static/js/{index.COZICZL6.js → index.x4j6nnNb.js} +1 -1
- streamlit/static/static/js/{input.CZPD7mCu.js → input.BoJqOS7a.js} +1 -1
- streamlit/static/static/js/{main.CX1jAiMw.js → main.B5XmUwmQ.js} +1 -1
- streamlit/static/static/js/{memory.m0jC5ULx.js → memory.9izgq54V.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.Dy0iTeCo.js → number-overlay-editor.PqOGQcLn.js} +1 -1
- streamlit/static/static/js/{pandasStylerUtils.D9jj-wHU.js → pandasStylerUtils.DUtF2t3R.js} +1 -1
- streamlit/static/static/js/{sandbox.CbvG1iAz.js → sandbox.DgKTHPLO.js} +1 -1
- streamlit/static/static/js/{styled-components.Cw3ioniY.js → styled-components.D4x8jmOI.js} +1 -1
- streamlit/static/static/js/{throttle.CAwhGpn0.js → throttle.DxEHIIp7.js} +1 -1
- streamlit/static/static/js/{timepicker.Bh3m6Pjp.js → timepicker.CDks5DWI.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.DM0o32JS.js → toConsumableArray.CvTQRsV-.js} +1 -1
- streamlit/static/static/js/uniqueId.RScLN3St.js +1 -0
- streamlit/static/static/js/{useBasicWidgetState.C9zOVP8a.js → useBasicWidgetState.D6_b0IqA.js} +1 -1
- streamlit/static/static/js/{useIntlLocale.Bo42aN1U.js → useIntlLocale.Ctz17A7g.js} +1 -1
- streamlit/static/static/js/{useTextInputAutoExpand.DmyHLDxl.js → useTextInputAutoExpand.PAFB5o1T.js} +1 -1
- streamlit/static/static/js/{useUpdateUiValue.aWXWpqmw.js → useUpdateUiValue.CcTvmGlb.js} +1 -1
- streamlit/static/static/js/{useWaveformController.DlE14M1X.js → useWaveformController.vLi36Ir4.js} +1 -1
- streamlit/static/static/js/{withCalculatedWidth.B5JFJSmG.js → withCalculatedWidth.BtA2jL5-.js} +1 -1
- streamlit/static/static/js/{withFullScreenWrapper.dgVioHk1.js → withFullScreenWrapper.CeeoYBpc.js} +1 -1
- streamlit/web/bootstrap.py +105 -10
- streamlit/web/cli.py +21 -4
- streamlit/web/server/app_discovery.py +421 -0
- streamlit/web/server/server.py +0 -13
- streamlit/web/server/starlette/__init__.py +2 -1
- streamlit/web/server/starlette/starlette_app.py +326 -3
- streamlit/web/server/starlette/starlette_routes.py +27 -8
- {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/RECORD +115 -113
- streamlit/static/static/js/index.BOGNGR9a.js +0 -1
- streamlit/static/static/js/index.C-lnh8pI.js +0 -1
- streamlit/static/static/js/index.C98anBCM.js +0 -1
- streamlit/static/static/js/index.CFtGP8pH.js +0 -1
- streamlit/static/static/js/index.Cg59Loqx.js +0 -1
- streamlit/static/static/js/index.CiU2Tdcl.js +0 -1
- streamlit/static/static/js/index.DpnqUQVD.js +0 -1
- streamlit/static/static/js/uniqueId.DtV_RZzG.js +0 -1
- {streamlit_nightly-1.52.3.dev20260108.data → streamlit_nightly-1.52.3.dev20260110.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.52.3.dev20260108.dist-info → streamlit_nightly-1.52.3.dev20260110.dist-info}/top_level.txt +0 -0
|
@@ -28,7 +28,7 @@ from streamlit.components.v2.get_bidi_component_manager import (
|
|
|
28
28
|
from streamlit.errors import StreamlitAPIException
|
|
29
29
|
|
|
30
30
|
if TYPE_CHECKING:
|
|
31
|
-
from streamlit.components.v2.types import
|
|
31
|
+
from streamlit.components.v2.types import ComponentRenderer
|
|
32
32
|
|
|
33
33
|
if TYPE_CHECKING:
|
|
34
34
|
from collections.abc import Callable
|
|
@@ -211,7 +211,7 @@ def component(
|
|
|
211
211
|
css: str | None = None,
|
|
212
212
|
js: str | None = None,
|
|
213
213
|
isolate_styles: bool = True,
|
|
214
|
-
) ->
|
|
214
|
+
) -> ComponentRenderer:
|
|
215
215
|
'''Register an ``st.components.v2`` component and return a callable to mount it.
|
|
216
216
|
|
|
217
217
|
Components may provide any combination of HTML, CSS, and JavaScript. If none
|
|
@@ -287,7 +287,7 @@ def component(
|
|
|
287
287
|
|
|
288
288
|
Returns
|
|
289
289
|
-------
|
|
290
|
-
|
|
290
|
+
ComponentRenderer
|
|
291
291
|
The component's mounting command.
|
|
292
292
|
|
|
293
293
|
This callable accepts the component parameters like ``key`` and
|
streamlit/components/v2/types.py
CHANGED
|
@@ -45,7 +45,7 @@ BidiComponentDefaults = dict[str, Any] | None
|
|
|
45
45
|
ComponentIsolateStyles = bool
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
class
|
|
48
|
+
class ComponentRenderer(Protocol):
|
|
49
49
|
'''Signature of the mounting command returned by ``st.components.v2.component``.
|
|
50
50
|
|
|
51
51
|
This callable mounts a bidirectional component in a Streamlit app and
|
|
@@ -69,8 +69,8 @@ class BidiComponentCallable(Protocol):
|
|
|
69
69
|
.. note::
|
|
70
70
|
If you want to access this key in your component's frontend, you
|
|
71
71
|
must pass it explicitly within the ``data`` parameter. The ``key``
|
|
72
|
-
parameter in ``
|
|
73
|
-
``key`` property in ``
|
|
72
|
+
parameter in ``ComponentRenderer`` is not the same as the
|
|
73
|
+
``key`` property in ``FrontendRendererArgs`` in the component's frontend
|
|
74
74
|
code.
|
|
75
75
|
|
|
76
76
|
The frontend key is automatically generated to be unique among all
|
|
@@ -309,9 +309,9 @@ class BidiComponentCallable(Protocol):
|
|
|
309
309
|
|
|
310
310
|
|
|
311
311
|
__all__ = [
|
|
312
|
-
"BidiComponentCallable",
|
|
313
312
|
"BidiComponentData",
|
|
314
313
|
"BidiComponentDefaults",
|
|
315
314
|
"BidiComponentKey",
|
|
316
315
|
"ComponentIsolateStyles",
|
|
316
|
+
"ComponentRenderer",
|
|
317
317
|
]
|
streamlit/config.py
CHANGED
|
@@ -62,6 +62,20 @@ _config_options: dict[str, ConfigOption] | None = None
|
|
|
62
62
|
# resolve config and secret files relative to the main script:
|
|
63
63
|
_main_script_path: str | None = None
|
|
64
64
|
|
|
65
|
+
# Stores the server mode for metrics tracking.
|
|
66
|
+
# Possible values:
|
|
67
|
+
# - "tornado": Traditional Tornado server
|
|
68
|
+
# - "starlette-managed": Starlette server via server.useStarlette config
|
|
69
|
+
# - "starlette-app": st.App started via streamlit run
|
|
70
|
+
# - "asgi-server": st.App with external ASGI server (uvicorn, gunicorn, etc.)
|
|
71
|
+
# - "asgi-mounted": st.App mounted on another ASGI framework (FastAPI, Starlette)
|
|
72
|
+
_server_mode: (
|
|
73
|
+
Literal[
|
|
74
|
+
"tornado", "starlette-managed", "starlette-app", "asgi-server", "asgi-mounted"
|
|
75
|
+
]
|
|
76
|
+
| None
|
|
77
|
+
) = None
|
|
78
|
+
|
|
65
79
|
# Indicates that a config option was defined by the user.
|
|
66
80
|
_USER_DEFINED: Final = "<user defined>"
|
|
67
81
|
|
|
@@ -20,6 +20,7 @@ from typing import TYPE_CHECKING, Any, Final, TypeVar, overload
|
|
|
20
20
|
from streamlit import config, logger
|
|
21
21
|
from streamlit.dataframe_util import OptionSequence, convert_anything_to_list
|
|
22
22
|
from streamlit.errors import StreamlitAPIException
|
|
23
|
+
from streamlit.runtime.state import get_session_state
|
|
23
24
|
from streamlit.runtime.state.common import RegisterWidgetResult
|
|
24
25
|
from streamlit.type_util import (
|
|
25
26
|
check_python_comparable,
|
|
@@ -282,3 +283,100 @@ def create_mappings(
|
|
|
282
283
|
formatted_options,
|
|
283
284
|
formatted_option_to_option_mapping,
|
|
284
285
|
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def validate_and_sync_value_with_options(
|
|
289
|
+
current_value: T | None,
|
|
290
|
+
opt: Sequence[T],
|
|
291
|
+
default_index: int | None,
|
|
292
|
+
key: str | int | None,
|
|
293
|
+
) -> tuple[T | None, bool]:
|
|
294
|
+
"""Validate current value against options, resetting session state if invalid.
|
|
295
|
+
|
|
296
|
+
This function has a side-effect: if the value is not found in the options
|
|
297
|
+
and a key is provided, it will update session state with the new value.
|
|
298
|
+
|
|
299
|
+
Parameters
|
|
300
|
+
----------
|
|
301
|
+
current_value
|
|
302
|
+
The current widget value to validate.
|
|
303
|
+
opt
|
|
304
|
+
The sequence of valid options.
|
|
305
|
+
default_index
|
|
306
|
+
The default index to reset to if value is invalid.
|
|
307
|
+
key
|
|
308
|
+
The widget key for session state updates.
|
|
309
|
+
|
|
310
|
+
Returns
|
|
311
|
+
-------
|
|
312
|
+
tuple[T | None, bool]
|
|
313
|
+
A tuple of (validated_value, value_was_reset).
|
|
314
|
+
"""
|
|
315
|
+
if current_value is None:
|
|
316
|
+
return current_value, False
|
|
317
|
+
|
|
318
|
+
# Check if current value is still in the new options
|
|
319
|
+
try:
|
|
320
|
+
index_(opt, current_value)
|
|
321
|
+
return current_value, False
|
|
322
|
+
except ValueError:
|
|
323
|
+
# Value not in options - reset to default
|
|
324
|
+
if default_index is not None and len(opt) > 0:
|
|
325
|
+
new_value: T | None = opt[default_index]
|
|
326
|
+
else:
|
|
327
|
+
new_value = None
|
|
328
|
+
|
|
329
|
+
if key is not None:
|
|
330
|
+
# Update session_state so subsequent accesses in this run
|
|
331
|
+
# return the corrected value. Use reset_state_value to avoid
|
|
332
|
+
# the "cannot be modified after widget instantiated" error.
|
|
333
|
+
get_session_state().reset_state_value(str(key), new_value)
|
|
334
|
+
|
|
335
|
+
return new_value, True
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def validate_and_sync_multiselect_value_with_options(
|
|
339
|
+
current_values: list[T] | list[T | str],
|
|
340
|
+
opt: Sequence[T],
|
|
341
|
+
key: str | int | None,
|
|
342
|
+
) -> tuple[list[T] | list[T | str], bool]:
|
|
343
|
+
"""Validate multiselect values against options, syncing session state if needed.
|
|
344
|
+
|
|
345
|
+
This function has a side-effect: if any values are filtered out and a key
|
|
346
|
+
is provided, it will update session state with the filtered list.
|
|
347
|
+
|
|
348
|
+
Unlike selectbox which resets to a default when the value is invalid,
|
|
349
|
+
multiselect filters out invalid values and keeps the valid ones.
|
|
350
|
+
|
|
351
|
+
Parameters
|
|
352
|
+
----------
|
|
353
|
+
current_values
|
|
354
|
+
The current list of selected values to validate.
|
|
355
|
+
opt
|
|
356
|
+
The sequence of valid options.
|
|
357
|
+
key
|
|
358
|
+
The widget key for session state updates.
|
|
359
|
+
|
|
360
|
+
Returns
|
|
361
|
+
-------
|
|
362
|
+
tuple[list[T] | list[T | str], bool]
|
|
363
|
+
A tuple of (validated_values, values_were_filtered).
|
|
364
|
+
"""
|
|
365
|
+
if not current_values:
|
|
366
|
+
return current_values, False
|
|
367
|
+
|
|
368
|
+
valid_values: list[T | str] = []
|
|
369
|
+
for value in current_values:
|
|
370
|
+
try:
|
|
371
|
+
index_(opt, value)
|
|
372
|
+
valid_values.append(value)
|
|
373
|
+
except ValueError: # noqa: PERF203
|
|
374
|
+
pass
|
|
375
|
+
|
|
376
|
+
if len(valid_values) == len(current_values):
|
|
377
|
+
return current_values, False
|
|
378
|
+
|
|
379
|
+
if key is not None:
|
|
380
|
+
get_session_state().reset_state_value(str(key), valid_values)
|
|
381
|
+
|
|
382
|
+
return valid_values, True
|
|
@@ -38,6 +38,7 @@ from streamlit.elements.lib.options_selector_utils import (
|
|
|
38
38
|
create_mappings,
|
|
39
39
|
get_default_indices,
|
|
40
40
|
maybe_coerce_enum_sequence,
|
|
41
|
+
validate_and_sync_multiselect_value_with_options,
|
|
41
42
|
)
|
|
42
43
|
from streamlit.elements.lib.policies import (
|
|
43
44
|
check_widget_policies,
|
|
@@ -493,15 +494,9 @@ class MultiSelectMixin:
|
|
|
493
494
|
element_id = compute_and_register_element_id(
|
|
494
495
|
widget_name,
|
|
495
496
|
user_key=key,
|
|
496
|
-
# Treat the provided key as the main identity. Only include
|
|
497
|
-
# changes to the options, accept_new_options, and max_selections
|
|
498
|
-
# in the identity computation as those can invalidate the
|
|
499
|
-
# current selection.
|
|
500
497
|
key_as_main_identity={
|
|
501
|
-
"options",
|
|
502
498
|
"max_selections",
|
|
503
499
|
"accept_new_options",
|
|
504
|
-
"format_func",
|
|
505
500
|
},
|
|
506
501
|
dg=self.dg,
|
|
507
502
|
label=label,
|
|
@@ -554,8 +549,23 @@ class MultiSelectMixin:
|
|
|
554
549
|
widget_state, options, indexable_options
|
|
555
550
|
)
|
|
556
551
|
|
|
557
|
-
if
|
|
558
|
-
|
|
552
|
+
if accept_new_options:
|
|
553
|
+
# accept_new_options is True, so we keep the user-entered values.
|
|
554
|
+
current_values = widget_state.value
|
|
555
|
+
value_needs_reset = False
|
|
556
|
+
else:
|
|
557
|
+
# Validate the current values against the new options.
|
|
558
|
+
# If values are no longer valid (not in options), filter them out.
|
|
559
|
+
# This handles the case where options change dynamically and the
|
|
560
|
+
# previously selected values are no longer available.
|
|
561
|
+
current_values, value_needs_reset = (
|
|
562
|
+
validate_and_sync_multiselect_value_with_options(
|
|
563
|
+
widget_state.value, indexable_options, key
|
|
564
|
+
)
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
if value_needs_reset or widget_state.value_changed:
|
|
568
|
+
proto.raw_values[:] = serde.serialize(current_values)
|
|
559
569
|
proto.set_value = True
|
|
560
570
|
|
|
561
571
|
validate_width(width)
|
|
@@ -566,7 +576,7 @@ class MultiSelectMixin:
|
|
|
566
576
|
|
|
567
577
|
self.dg._enqueue(widget_name, proto, layout_config=layout_config)
|
|
568
578
|
|
|
569
|
-
return
|
|
579
|
+
return current_values
|
|
570
580
|
|
|
571
581
|
@property
|
|
572
582
|
def dg(self) -> DeltaGenerator:
|
|
@@ -37,6 +37,7 @@ from streamlit.elements.lib.options_selector_utils import (
|
|
|
37
37
|
create_mappings,
|
|
38
38
|
index_,
|
|
39
39
|
maybe_coerce_enum,
|
|
40
|
+
validate_and_sync_value_with_options,
|
|
40
41
|
)
|
|
41
42
|
from streamlit.elements.lib.policies import (
|
|
42
43
|
check_widget_policies,
|
|
@@ -595,30 +596,17 @@ class SelectboxMixin:
|
|
|
595
596
|
)
|
|
596
597
|
widget_state = maybe_coerce_enum(widget_state, options, opt)
|
|
597
598
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
except ValueError:
|
|
610
|
-
# Value not in options - reset to default.
|
|
611
|
-
value_needs_reset = True
|
|
612
|
-
if index is not None and len(opt) > 0:
|
|
613
|
-
current_value = opt[index]
|
|
614
|
-
else:
|
|
615
|
-
current_value = None
|
|
616
|
-
|
|
617
|
-
# Update session_state so subsequent accesses in this run
|
|
618
|
-
# return the corrected value. Use reset_state_value to avoid
|
|
619
|
-
# the "cannot be modified after widget instantiated" error.
|
|
620
|
-
if key is not None:
|
|
621
|
-
get_session_state().reset_state_value(key, current_value)
|
|
599
|
+
if accept_new_options:
|
|
600
|
+
current_value = widget_state.value
|
|
601
|
+
value_needs_reset = False
|
|
602
|
+
else:
|
|
603
|
+
# Validate the current value against the new options.
|
|
604
|
+
# If the value is no longer valid (not in options), reset to default.
|
|
605
|
+
# This handles the case where options change dynamically and the
|
|
606
|
+
# previously selected value is no longer available.
|
|
607
|
+
current_value, value_needs_reset = validate_and_sync_value_with_options(
|
|
608
|
+
widget_state.value, opt, index, key
|
|
609
|
+
)
|
|
622
610
|
|
|
623
611
|
if value_needs_reset or widget_state.value_changed:
|
|
624
612
|
serialized_value = serde.serialize(current_value)
|
|
@@ -15,7 +15,7 @@ _sym_db = _symbol_database.Default()
|
|
|
15
15
|
from streamlit.proto import PageProfile_pb2 as streamlit_dot_proto_dot_PageProfile__pb2
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"streamlit/proto/MetricsEvent.proto\x1a!streamlit/proto/PageProfile.proto\"\
|
|
18
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"streamlit/proto/MetricsEvent.proto\x1a!streamlit/proto/PageProfile.proto\"\xd4\x07\n\x0cMetricsEvent\x12\r\n\x05\x65vent\x18\x01 \x01(\t\x12\x14\n\x0c\x61nonymous_id\x18\x02 \x01(\t\x12\x15\n\rmachine_id_v3\x18\x03 \x01(\t\x12\x15\n\rmachine_id_v4\x18) \x01(\t\x12\x13\n\x0breport_hash\x18\x04 \x01(\t\x12\x0b\n\x03\x64\x65v\x18\x05 \x01(\x08\x12\x0e\n\x06source\x18\x06 \x01(\t\x12\x19\n\x11streamlit_version\x18\x07 \x01(\t\x12\x10\n\x08is_hello\x18\x08 \x01(\x08\x12\x0e\n\x06\x61pp_id\x18! \x01(\t\x12\x12\n\nsession_id\x18# \x01(\t\x12\x16\n\x0epython_version\x18$ \x01(\t\x12\x11\n\tserver_os\x18* \x01(\t\x12\x13\n\x0bhas_display\x18+ \x01(\x08\x12\x14\n\x0cis_webdriver\x18, \x01(\x08\x12\x11\n\thosted_at\x18\t \x01(\t\x12\r\n\x05owner\x18\n \x01(\t\x12\x0c\n\x04repo\x18\x0b \x01(\t\x12\x0e\n\x06\x62ranch\x18\x0c \x01(\t\x12\x13\n\x0bmain_module\x18\r \x01(\t\x12\x12\n\ncreator_id\x18\x0e \x01(\t\x12\x18\n\x10\x63ontext_page_url\x18\x0f \x01(\t\x12\x1a\n\x12\x63ontext_page_title\x18\x10 \x01(\t\x12\x19\n\x11\x63ontext_page_path\x18\x11 \x01(\t\x12\x1d\n\x15\x63ontext_page_referrer\x18\x12 \x01(\t\x12\x1b\n\x13\x63ontext_page_search\x18\x13 \x01(\t\x12\x16\n\x0e\x63ontext_locale\x18\x14 \x01(\t\x12\x1a\n\x12\x63ontext_user_agent\x18\x15 \x01(\t\x12\r\n\x05label\x18\x16 \x01(\t\x12\x1a\n\x08\x63ommands\x18\x17 \x03(\x0b\x32\x08.Command\x12\x11\n\texec_time\x18\x18 \x01(\x03\x12\x11\n\tprep_time\x18\x19 \x01(\x03\x12\x0e\n\x06\x63onfig\x18\x1a \x03(\t\x12\x1a\n\x12uncaught_exception\x18\x1b \x01(\t\x12\x14\n\x0c\x61ttributions\x18\x1c \x03(\t\x12\n\n\x02os\x18\x1d \x01(\t\x12\x10\n\x08timezone\x18\x1e \x01(\t\x12\x10\n\x08headless\x18\x1f \x01(\x08\x12\x17\n\x0fis_fragment_run\x18 \x01(\x08\x12\x10\n\x08numPages\x18\" \x01(\x03\x12\x18\n\x10page_script_hash\x18% \x01(\t\x12\x14\n\x0c\x61\x63tive_theme\x18& \x01(\t\x12\x17\n\x0ftotal_load_time\x18\' \x01(\x03\x12\"\n\x0c\x62rowser_info\x18( \x01(\x0b\x32\x0c.BrowserInfo\x12\x13\n\x0bserver_mode\x18- \x01(\t\"]\n\x0b\x42rowserInfo\x12\x14\n\x0c\x62rowser_name\x18\x01 \x01(\t\x12\x17\n\x0f\x62rowser_version\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65vice_type\x18\x03 \x01(\t\x12\n\n\x02os\x18\x04 \x01(\tB1\n\x1c\x63om.snowflake.apps.streamlitB\x11MetricsEventProtob\x06proto3')
|
|
19
19
|
|
|
20
20
|
_globals = globals()
|
|
21
21
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -24,7 +24,7 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
24
24
|
_globals['DESCRIPTOR']._loaded_options = None
|
|
25
25
|
_globals['DESCRIPTOR']._serialized_options = b'\n\034com.snowflake.apps.streamlitB\021MetricsEventProto'
|
|
26
26
|
_globals['_METRICSEVENT']._serialized_start=74
|
|
27
|
-
_globals['_METRICSEVENT']._serialized_end=
|
|
28
|
-
_globals['_BROWSERINFO']._serialized_start=
|
|
29
|
-
_globals['_BROWSERINFO']._serialized_end=
|
|
27
|
+
_globals['_METRICSEVENT']._serialized_end=1054
|
|
28
|
+
_globals['_BROWSERINFO']._serialized_start=1056
|
|
29
|
+
_globals['_BROWSERINFO']._serialized_end=1149
|
|
30
30
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -83,6 +83,7 @@ class MetricsEvent(google.protobuf.message.Message):
|
|
|
83
83
|
ACTIVE_THEME_FIELD_NUMBER: builtins.int
|
|
84
84
|
TOTAL_LOAD_TIME_FIELD_NUMBER: builtins.int
|
|
85
85
|
BROWSER_INFO_FIELD_NUMBER: builtins.int
|
|
86
|
+
SERVER_MODE_FIELD_NUMBER: builtins.int
|
|
86
87
|
event: builtins.str
|
|
87
88
|
"""Common Event Fields:"""
|
|
88
89
|
anonymous_id: builtins.str
|
|
@@ -128,6 +129,7 @@ class MetricsEvent(google.protobuf.message.Message):
|
|
|
128
129
|
page_script_hash: builtins.str
|
|
129
130
|
active_theme: builtins.str
|
|
130
131
|
total_load_time: builtins.int
|
|
132
|
+
server_mode: builtins.str
|
|
131
133
|
@property
|
|
132
134
|
def commands(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[streamlit.proto.PageProfile_pb2.Command]:
|
|
133
135
|
"""Page Profile Event fields:
|
|
@@ -187,10 +189,11 @@ class MetricsEvent(google.protobuf.message.Message):
|
|
|
187
189
|
active_theme: builtins.str = ...,
|
|
188
190
|
total_load_time: builtins.int = ...,
|
|
189
191
|
browser_info: Global___BrowserInfo | None = ...,
|
|
192
|
+
server_mode: builtins.str = ...,
|
|
190
193
|
) -> None: ...
|
|
191
194
|
_HasFieldArgType: typing_extensions.TypeAlias = typing.Literal["browser_info", b"browser_info"]
|
|
192
195
|
def HasField(self, field_name: _HasFieldArgType) -> builtins.bool: ...
|
|
193
|
-
_ClearFieldArgType: typing_extensions.TypeAlias = typing.Literal["active_theme", b"active_theme", "anonymous_id", b"anonymous_id", "app_id", b"app_id", "attributions", b"attributions", "branch", b"branch", "browser_info", b"browser_info", "commands", b"commands", "config", b"config", "context_locale", b"context_locale", "context_page_path", b"context_page_path", "context_page_referrer", b"context_page_referrer", "context_page_search", b"context_page_search", "context_page_title", b"context_page_title", "context_page_url", b"context_page_url", "context_user_agent", b"context_user_agent", "creator_id", b"creator_id", "dev", b"dev", "event", b"event", "exec_time", b"exec_time", "has_display", b"has_display", "headless", b"headless", "hosted_at", b"hosted_at", "is_fragment_run", b"is_fragment_run", "is_hello", b"is_hello", "is_webdriver", b"is_webdriver", "label", b"label", "machine_id_v3", b"machine_id_v3", "machine_id_v4", b"machine_id_v4", "main_module", b"main_module", "numPages", b"numPages", "os", b"os", "owner", b"owner", "page_script_hash", b"page_script_hash", "prep_time", b"prep_time", "python_version", b"python_version", "repo", b"repo", "report_hash", b"report_hash", "server_os", b"server_os", "session_id", b"session_id", "source", b"source", "streamlit_version", b"streamlit_version", "timezone", b"timezone", "total_load_time", b"total_load_time", "uncaught_exception", b"uncaught_exception"]
|
|
196
|
+
_ClearFieldArgType: typing_extensions.TypeAlias = typing.Literal["active_theme", b"active_theme", "anonymous_id", b"anonymous_id", "app_id", b"app_id", "attributions", b"attributions", "branch", b"branch", "browser_info", b"browser_info", "commands", b"commands", "config", b"config", "context_locale", b"context_locale", "context_page_path", b"context_page_path", "context_page_referrer", b"context_page_referrer", "context_page_search", b"context_page_search", "context_page_title", b"context_page_title", "context_page_url", b"context_page_url", "context_user_agent", b"context_user_agent", "creator_id", b"creator_id", "dev", b"dev", "event", b"event", "exec_time", b"exec_time", "has_display", b"has_display", "headless", b"headless", "hosted_at", b"hosted_at", "is_fragment_run", b"is_fragment_run", "is_hello", b"is_hello", "is_webdriver", b"is_webdriver", "label", b"label", "machine_id_v3", b"machine_id_v3", "machine_id_v4", b"machine_id_v4", "main_module", b"main_module", "numPages", b"numPages", "os", b"os", "owner", b"owner", "page_script_hash", b"page_script_hash", "prep_time", b"prep_time", "python_version", b"python_version", "repo", b"repo", "report_hash", b"report_hash", "server_mode", b"server_mode", "server_os", b"server_os", "session_id", b"session_id", "source", b"source", "streamlit_version", b"streamlit_version", "timezone", b"timezone", "total_load_time", b"total_load_time", "uncaught_exception", b"uncaught_exception"]
|
|
194
197
|
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
195
198
|
|
|
196
199
|
Global___MetricsEvent: typing_extensions.TypeAlias = MetricsEvent
|
|
@@ -14,7 +14,7 @@ _sym_db = _symbol_database.Default()
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!streamlit/proto/PageProfile.proto\"\
|
|
17
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!streamlit/proto/PageProfile.proto\"\xef\x01\n\x0bPageProfile\x12\x1a\n\x08\x63ommands\x18\x01 \x03(\x0b\x32\x08.Command\x12\x11\n\texec_time\x18\x02 \x01(\x03\x12\x11\n\tprep_time\x18\x03 \x01(\x03\x12\x0e\n\x06\x63onfig\x18\x05 \x03(\t\x12\x1a\n\x12uncaught_exception\x18\x06 \x01(\t\x12\x14\n\x0c\x61ttributions\x18\x07 \x03(\t\x12\n\n\x02os\x18\x08 \x01(\t\x12\x10\n\x08timezone\x18\t \x01(\t\x12\x10\n\x08headless\x18\n \x01(\x08\x12\x17\n\x0fis_fragment_run\x18\x0b \x01(\x08\x12\x13\n\x0bserver_mode\x18\x0c \x01(\t\"6\n\x08\x41rgument\x12\t\n\x01k\x18\x01 \x01(\t\x12\t\n\x01t\x18\x02 \x01(\t\x12\t\n\x01m\x18\x03 \x01(\t\x12\t\n\x01p\x18\x05 \x01(\x05\">\n\x07\x43ommand\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x04\x61rgs\x18\x02 \x03(\x0b\x32\t.Argument\x12\x0c\n\x04time\x18\x04 \x01(\x03\x42\x30\n\x1c\x63om.snowflake.apps.streamlitB\x10PageProfileProtob\x06proto3')
|
|
18
18
|
|
|
19
19
|
_globals = globals()
|
|
20
20
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -23,9 +23,9 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
23
23
|
_globals['DESCRIPTOR']._loaded_options = None
|
|
24
24
|
_globals['DESCRIPTOR']._serialized_options = b'\n\034com.snowflake.apps.streamlitB\020PageProfileProto'
|
|
25
25
|
_globals['_PAGEPROFILE']._serialized_start=38
|
|
26
|
-
_globals['_PAGEPROFILE']._serialized_end=
|
|
27
|
-
_globals['_ARGUMENT']._serialized_start=
|
|
28
|
-
_globals['_ARGUMENT']._serialized_end=
|
|
29
|
-
_globals['_COMMAND']._serialized_start=
|
|
30
|
-
_globals['_COMMAND']._serialized_end=
|
|
26
|
+
_globals['_PAGEPROFILE']._serialized_end=277
|
|
27
|
+
_globals['_ARGUMENT']._serialized_start=279
|
|
28
|
+
_globals['_ARGUMENT']._serialized_end=333
|
|
29
|
+
_globals['_COMMAND']._serialized_start=335
|
|
30
|
+
_globals['_COMMAND']._serialized_end=397
|
|
31
31
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -46,6 +46,7 @@ class PageProfile(google.protobuf.message.Message):
|
|
|
46
46
|
TIMEZONE_FIELD_NUMBER: builtins.int
|
|
47
47
|
HEADLESS_FIELD_NUMBER: builtins.int
|
|
48
48
|
IS_FRAGMENT_RUN_FIELD_NUMBER: builtins.int
|
|
49
|
+
SERVER_MODE_FIELD_NUMBER: builtins.int
|
|
49
50
|
exec_time: builtins.int
|
|
50
51
|
prep_time: builtins.int
|
|
51
52
|
uncaught_exception: builtins.str
|
|
@@ -53,6 +54,14 @@ class PageProfile(google.protobuf.message.Message):
|
|
|
53
54
|
timezone: builtins.str
|
|
54
55
|
headless: builtins.bool
|
|
55
56
|
is_fragment_run: builtins.bool
|
|
57
|
+
server_mode: builtins.str
|
|
58
|
+
"""The server mode used to run the Streamlit app:
|
|
59
|
+
- "tornado": Traditional Tornado server (streamlit run)
|
|
60
|
+
- "starlette-managed": Starlette server via server.useStarlette config
|
|
61
|
+
- "starlette-app": st.App started via streamlit run
|
|
62
|
+
- "asgi-server": st.App run directly with external ASGI server (uvicorn, gunicorn)
|
|
63
|
+
- "asgi-mounted": st.App mounted on another ASGI framework (FastAPI, Starlette)
|
|
64
|
+
"""
|
|
56
65
|
@property
|
|
57
66
|
def commands(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[Global___Command]: ...
|
|
58
67
|
@property
|
|
@@ -72,8 +81,9 @@ class PageProfile(google.protobuf.message.Message):
|
|
|
72
81
|
timezone: builtins.str = ...,
|
|
73
82
|
headless: builtins.bool = ...,
|
|
74
83
|
is_fragment_run: builtins.bool = ...,
|
|
84
|
+
server_mode: builtins.str = ...,
|
|
75
85
|
) -> None: ...
|
|
76
|
-
_ClearFieldArgType: typing_extensions.TypeAlias = typing.Literal["attributions", b"attributions", "commands", b"commands", "config", b"config", "exec_time", b"exec_time", "headless", b"headless", "is_fragment_run", b"is_fragment_run", "os", b"os", "prep_time", b"prep_time", "timezone", b"timezone", "uncaught_exception", b"uncaught_exception"]
|
|
86
|
+
_ClearFieldArgType: typing_extensions.TypeAlias = typing.Literal["attributions", b"attributions", "commands", b"commands", "config", b"config", "exec_time", b"exec_time", "headless", b"headless", "is_fragment_run", b"is_fragment_run", "os", b"os", "prep_time", b"prep_time", "server_mode", b"server_mode", "timezone", b"timezone", "uncaught_exception", b"uncaught_exception"]
|
|
77
87
|
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
78
88
|
|
|
79
89
|
Global___PageProfile: typing_extensions.TypeAlias = PageProfile
|
|
@@ -573,6 +573,10 @@ def create_page_profile_message(
|
|
|
573
573
|
|
|
574
574
|
page_profile.headless = config.get_option("server.headless")
|
|
575
575
|
|
|
576
|
+
# Include the server mode for metrics tracking
|
|
577
|
+
if config._server_mode:
|
|
578
|
+
page_profile.server_mode = config._server_mode
|
|
579
|
+
|
|
576
580
|
# Collect all config options that have been manually set
|
|
577
581
|
config_options: set[str] = set()
|
|
578
582
|
if config._config_options:
|
streamlit/runtime/runtime.py
CHANGED
|
@@ -232,6 +232,9 @@ class Runtime:
|
|
|
232
232
|
self._stats_mgr.register_provider(get_resource_cache_stats_provider())
|
|
233
233
|
if self._uploaded_file_mgr is not None:
|
|
234
234
|
self._stats_mgr.register_provider(self._uploaded_file_mgr)
|
|
235
|
+
# Register media file storage for stats if it implements StatsProvider
|
|
236
|
+
if isinstance(config.media_file_storage, StatsProvider):
|
|
237
|
+
self._stats_mgr.register_provider(config.media_file_storage)
|
|
235
238
|
self._stats_mgr.register_provider(SessionStateStatProvider(self._session_mgr))
|
|
236
239
|
|
|
237
240
|
# Register session manager for session event metrics if it implements StatsProvider
|
streamlit/starlette.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Starlette integration for Streamlit.
|
|
16
|
+
|
|
17
|
+
This module provides the ASGI-compatible App class for running Streamlit
|
|
18
|
+
applications with any ASGI server (uvicorn, hypercorn, etc.).
|
|
19
|
+
|
|
20
|
+
Example
|
|
21
|
+
-------
|
|
22
|
+
>>> from streamlit.starlette import App
|
|
23
|
+
>>> app = App("main.py")
|
|
24
|
+
|
|
25
|
+
Run with uvicorn:
|
|
26
|
+
|
|
27
|
+
.. code-block:: bash
|
|
28
|
+
|
|
29
|
+
uvicorn myapp:app --host 0.0.0.0 --port 8501
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from streamlit.web.server.starlette.starlette_app import App
|
|
33
|
+
|
|
34
|
+
__all__ = ["App"]
|
streamlit/static/index.html
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
<script>
|
|
38
38
|
window.prerenderReady = false
|
|
39
39
|
</script>
|
|
40
|
-
<script type="module" crossorigin src="./static/js/index.
|
|
40
|
+
<script type="module" crossorigin src="./static/js/index.BZBWLU1C.js"></script>
|
|
41
41
|
<link rel="stylesheet" crossorigin href="./static/css/index.BUP6fTcR.css">
|
|
42
42
|
</head>
|
|
43
43
|
<body>
|