streamlit-nightly 1.37.2.dev20240814__py2.py3-none-any.whl → 1.37.2.dev20240816__py2.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/commands/execution_control.py +1 -4
- streamlit/commands/experimental_query_params.py +1 -1
- streamlit/commands/logo.py +1 -1
- streamlit/commands/navigation.py +1 -1
- streamlit/commands/page_config.py +1 -1
- streamlit/components/v1/component_arrow.py +2 -2
- streamlit/components/v1/component_registry.py +1 -1
- streamlit/components/v1/custom_component.py +1 -1
- streamlit/cursor.py +1 -1
- streamlit/dataframe_util.py +184 -25
- streamlit/elements/arrow.py +1 -1
- streamlit/elements/json.py +13 -7
- streamlit/elements/lib/dialog.py +1 -1
- streamlit/elements/lib/mutable_status_container.py +1 -1
- streamlit/elements/lib/policies.py +1 -1
- streamlit/elements/media.py +3 -5
- streamlit/elements/plotly_chart.py +1 -1
- streamlit/elements/vega_charts.py +1 -1
- streamlit/elements/widgets/button.py +7 -4
- streamlit/elements/widgets/button_group.py +28 -9
- streamlit/elements/widgets/chat.py +1 -1
- streamlit/elements/widgets/data_editor.py +1 -1
- streamlit/elements/write.py +18 -3
- streamlit/error_util.py +10 -8
- streamlit/navigation/page.py +1 -1
- streamlit/platform.py +1 -1
- streamlit/runtime/caching/cache_data_api.py +1 -1
- streamlit/runtime/caching/cache_resource_api.py +1 -1
- streamlit/runtime/caching/cached_message_replay.py +1 -1
- streamlit/runtime/context.py +6 -5
- streamlit/runtime/forward_msg_queue.py +18 -1
- streamlit/runtime/fragment.py +7 -5
- streamlit/runtime/media_file_manager.py +3 -1
- streamlit/runtime/metrics_util.py +2 -7
- streamlit/runtime/scriptrunner/__init__.py +7 -4
- streamlit/runtime/scriptrunner/exec_code.py +6 -3
- streamlit/runtime/scriptrunner/script_runner.py +10 -9
- streamlit/runtime/scriptrunner_utils/__init__.py +19 -0
- streamlit/runtime/{scriptrunner → scriptrunner_utils}/exceptions.py +1 -1
- streamlit/runtime/{scriptrunner → scriptrunner_utils}/script_requests.py +61 -6
- streamlit/runtime/{scriptrunner → scriptrunner_utils}/script_run_context.py +1 -1
- streamlit/runtime/state/__init__.py +0 -2
- streamlit/runtime/state/common.py +1 -1
- streamlit/runtime/state/query_params.py +1 -6
- streamlit/runtime/state/session_state.py +1 -5
- streamlit/runtime/state/session_state_proxy.py +3 -1
- streamlit/runtime/state/widgets.py +0 -59
- streamlit/static/asset-manifest.json +17 -17
- streamlit/static/index.html +1 -1
- streamlit/static/static/js/{1168.2a7e18da.chunk.js → 1168.2a9806f0.chunk.js} +1 -1
- streamlit/static/static/js/{1451.3d44ca81.chunk.js → 1451.d93e956f.chunk.js} +1 -1
- streamlit/static/static/js/{178.7bea8c5d.chunk.js → 178.ddebe26b.chunk.js} +1 -1
- streamlit/static/static/js/2469.6217c5c3.chunk.js +1 -0
- streamlit/static/static/js/{2634.1249dc7a.chunk.js → 2634.4e2535ee.chunk.js} +1 -1
- streamlit/static/static/js/{2736.dcbc9141.chunk.js → 2736.3d50ec7f.chunk.js} +1 -1
- streamlit/static/static/js/{3301.45709e64.chunk.js → 3301.7379a9fd.chunk.js} +5 -5
- streamlit/static/static/js/4113.786b0142.chunk.js +1 -0
- streamlit/static/static/js/4500.d884c792.chunk.js +1 -0
- streamlit/static/static/js/6853.a1c4fa00.chunk.js +1 -0
- streamlit/static/static/js/{7602.2331daf7.chunk.js → 7602.33571c14.chunk.js} +1 -1
- streamlit/static/static/js/7805.ba32ae70.chunk.js +1 -0
- streamlit/static/static/js/8148.b905db99.chunk.js +1 -0
- streamlit/static/static/js/8427.b1a68937.chunk.js +1 -0
- streamlit/static/static/js/{9330.2b4c99e0.chunk.js → 9330.32e8a53a.chunk.js} +1 -1
- streamlit/static/static/js/main.90c4efd0.js +28 -0
- streamlit/testing/v1/local_script_runner.py +1 -1
- streamlit/type_util.py +17 -47
- streamlit/user_info.py +4 -2
- streamlit/web/server/stats_request_handler.py +1 -3
- streamlit/web/server/websocket_headers.py +1 -1
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240816.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240816.dist-info}/RECORD +77 -76
- streamlit/static/static/js/2469.4bb197dd.chunk.js +0 -1
- streamlit/static/static/js/4113.ca4d2d7b.chunk.js +0 -1
- streamlit/static/static/js/4500.c007e274.chunk.js +0 -1
- streamlit/static/static/js/6853.5d19f25b.chunk.js +0 -1
- streamlit/static/static/js/7805.f7c8d475.chunk.js +0 -1
- streamlit/static/static/js/8148.7805e73f.chunk.js +0 -1
- streamlit/static/static/js/8427.69ce2c45.chunk.js +0 -1
- streamlit/static/static/js/main.b519dd78.js +0 -28
- /streamlit/static/static/js/{main.b519dd78.js.LICENSE.txt → main.90c4efd0.js.LICENSE.txt} +0 -0
- {streamlit_nightly-1.37.2.dev20240814.data → streamlit_nightly-1.37.2.dev20240816.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240816.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240816.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.37.2.dev20240814.dist-info → streamlit_nightly-1.37.2.dev20240816.dist-info}/top_level.txt +0 -0
@@ -23,11 +23,9 @@ from typing import (
|
|
23
23
|
Sequence,
|
24
24
|
TypeVar,
|
25
25
|
cast,
|
26
|
-
|
26
|
+
overload,
|
27
27
|
)
|
28
28
|
|
29
|
-
from typing_extensions import TypeAlias
|
30
|
-
|
31
29
|
from streamlit.elements.form_utils import current_form_id
|
32
30
|
from streamlit.elements.lib.options_selector_utils import (
|
33
31
|
convert_to_sequence_and_check_comparable,
|
@@ -43,7 +41,7 @@ from streamlit.elements.widgets.multiselect import MultiSelectSerde
|
|
43
41
|
from streamlit.errors import StreamlitAPIException
|
44
42
|
from streamlit.proto.ButtonGroup_pb2 import ButtonGroup as ButtonGroupProto
|
45
43
|
from streamlit.runtime.metrics_util import gather_metrics
|
46
|
-
from streamlit.runtime.
|
44
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
47
45
|
from streamlit.runtime.state import register_widget
|
48
46
|
from streamlit.runtime.state.common import (
|
49
47
|
RegisterWidgetResult,
|
@@ -80,8 +78,6 @@ _STAR_ICON: Final = ":material/star:"
|
|
80
78
|
# in base64 format and send it over the wire as an image.
|
81
79
|
_SELECTED_STAR_ICON: Final = ":material/star_filled:"
|
82
80
|
|
83
|
-
_FeedbackOptions: TypeAlias = Literal["thumbs", "faces", "stars"]
|
84
|
-
|
85
81
|
|
86
82
|
class FeedbackSerde:
|
87
83
|
"""Uses the MultiSelectSerde under-the-hood, but accepts a single index value
|
@@ -114,7 +110,7 @@ class FeedbackSerde:
|
|
114
110
|
|
115
111
|
|
116
112
|
def get_mapped_options(
|
117
|
-
feedback_option:
|
113
|
+
feedback_option: Literal["thumbs", "faces", "stars"],
|
118
114
|
) -> tuple[list[ButtonGroupProto.Option], list[int]]:
|
119
115
|
# options object understandable by the web app
|
120
116
|
options: list[ButtonGroupProto.Option] = []
|
@@ -168,10 +164,33 @@ def _build_proto(
|
|
168
164
|
|
169
165
|
|
170
166
|
class ButtonGroupMixin:
|
167
|
+
@overload # These overloads are not documented in the docstring, at least not at this time, on the theory that most people won't know what it means. And the Literals here are a subclass of int anyway.
|
168
|
+
# Usually, we would make a type alias for Literal["thumbs", "faces", "stars"]; but, in this case, we don't use it in too many other places, and it's a more helpful autocomplete if we just enumerate the values explicitly, so a decision has been made to keep it as not an alias.
|
169
|
+
def feedback(
|
170
|
+
self,
|
171
|
+
options: Literal["thumbs"] = ...,
|
172
|
+
*,
|
173
|
+
key: str | None = None,
|
174
|
+
disabled: bool = False,
|
175
|
+
on_change: WidgetCallback | None = None,
|
176
|
+
args: Any | None = None,
|
177
|
+
kwargs: Any | None = None,
|
178
|
+
) -> Literal[0, 1] | None: ...
|
179
|
+
@overload
|
180
|
+
def feedback(
|
181
|
+
self,
|
182
|
+
options: Literal["faces", "stars"] = ...,
|
183
|
+
*,
|
184
|
+
key: str | None = None,
|
185
|
+
disabled: bool = False,
|
186
|
+
on_change: WidgetCallback | None = None,
|
187
|
+
args: Any | None = None,
|
188
|
+
kwargs: Any | None = None,
|
189
|
+
) -> Literal[0, 1, 2, 3, 4] | None: ...
|
171
190
|
@gather_metrics("feedback")
|
172
191
|
def feedback(
|
173
192
|
self,
|
174
|
-
options:
|
193
|
+
options: Literal["thumbs", "faces", "stars"] = "thumbs",
|
175
194
|
*,
|
176
195
|
key: str | None = None,
|
177
196
|
disabled: bool = False,
|
@@ -262,7 +281,7 @@ class ButtonGroupMixin:
|
|
262
281
|
|
263
282
|
"""
|
264
283
|
|
265
|
-
if
|
284
|
+
if options not in ["thumbs", "faces", "stars"]:
|
266
285
|
raise StreamlitAPIException(
|
267
286
|
"The options argument to st.feedback must be one of "
|
268
287
|
"['thumbs', 'faces', 'stars']. "
|
@@ -30,7 +30,7 @@ from streamlit.proto.ChatInput_pb2 import ChatInput as ChatInputProto
|
|
30
30
|
from streamlit.proto.Common_pb2 import StringTriggerValue as StringTriggerValueProto
|
31
31
|
from streamlit.proto.RootContainer_pb2 import RootContainer
|
32
32
|
from streamlit.runtime.metrics_util import gather_metrics
|
33
|
-
from streamlit.runtime.
|
33
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
34
34
|
from streamlit.runtime.state import (
|
35
35
|
WidgetArgs,
|
36
36
|
WidgetCallback,
|
@@ -59,7 +59,7 @@ from streamlit.elements.lib.utils import Key, to_key
|
|
59
59
|
from streamlit.errors import StreamlitAPIException
|
60
60
|
from streamlit.proto.Arrow_pb2 import Arrow as ArrowProto
|
61
61
|
from streamlit.runtime.metrics_util import gather_metrics
|
62
|
-
from streamlit.runtime.
|
62
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
63
63
|
from streamlit.runtime.state import (
|
64
64
|
WidgetArgs,
|
65
65
|
WidgetCallback,
|
streamlit/elements/write.py
CHANGED
@@ -18,6 +18,7 @@ import dataclasses
|
|
18
18
|
import inspect
|
19
19
|
import types
|
20
20
|
from collections import ChainMap, UserDict, UserList
|
21
|
+
from collections.abc import ItemsView, KeysView, ValuesView
|
21
22
|
from io import StringIO
|
22
23
|
from typing import (
|
23
24
|
TYPE_CHECKING,
|
@@ -258,13 +259,13 @@ class WriteMixin:
|
|
258
259
|
- write(string) : Prints the formatted Markdown string, with
|
259
260
|
support for LaTeX expression, emoji shortcodes, and colored text.
|
260
261
|
See docs for st.markdown for more.
|
261
|
-
- write(
|
262
|
-
|
262
|
+
- write(dataframe) : Displays any dataframe-like object in a table.
|
263
|
+
- write(dict) : Displays dict-like in an interactive viewer.
|
264
|
+
- write(list) : Displays list-like in an interactive viewer.
|
263
265
|
- write(error) : Prints an exception specially.
|
264
266
|
- write(func) : Displays information about a function.
|
265
267
|
- write(module) : Displays information about the module.
|
266
268
|
- write(class) : Displays information about a class.
|
267
|
-
- write(dict) : Displays dict in an interactive widget.
|
268
269
|
- write(mpl_fig) : Displays a Matplotlib figure.
|
269
270
|
- write(generator) : Streams the output of a generator.
|
270
271
|
- write(openai.Stream) : Streams the output of an OpenAI stream.
|
@@ -276,8 +277,10 @@ class WriteMixin:
|
|
276
277
|
- write(bokeh_fig) : Displays a Bokeh figure.
|
277
278
|
- write(sympy_expr) : Prints SymPy expression using LaTeX.
|
278
279
|
- write(htmlable) : Prints _repr_html_() for the object if available.
|
280
|
+
- write(db_cursor) : Displays DB API 2.0 cursor results in a table.
|
279
281
|
- write(obj) : Prints str(obj) if otherwise unknown.
|
280
282
|
|
283
|
+
|
281
284
|
unsafe_allow_html : bool
|
282
285
|
Whether to render HTML within ``*args``. This only applies to
|
283
286
|
strings or objects falling back on ``_repr_html_()``. If this is
|
@@ -457,10 +460,14 @@ class WriteMixin:
|
|
457
460
|
UserDict,
|
458
461
|
ChainMap,
|
459
462
|
UserList,
|
463
|
+
ItemsView,
|
464
|
+
KeysView,
|
465
|
+
ValuesView,
|
460
466
|
),
|
461
467
|
)
|
462
468
|
or type_util.is_custom_dict(arg)
|
463
469
|
or type_util.is_namedtuple(arg)
|
470
|
+
or type_util.is_pydantic_model(arg)
|
464
471
|
):
|
465
472
|
flush_buffer()
|
466
473
|
self.dg.json(arg)
|
@@ -495,6 +502,14 @@ class WriteMixin:
|
|
495
502
|
):
|
496
503
|
# We either explicitly allow HTML or infer it's not HTML
|
497
504
|
self.dg.markdown(repr_html, unsafe_allow_html=unsafe_allow_html)
|
505
|
+
elif type_util.has_callable_attr(
|
506
|
+
arg, "to_pandas"
|
507
|
+
) or type_util.has_callable_attr(arg, "__dataframe__"):
|
508
|
+
# This object can very likely be converted to a DataFrame
|
509
|
+
# using the to_pandas, to_arrow, or the dataframe interchange
|
510
|
+
# protocol.
|
511
|
+
flush_buffer()
|
512
|
+
self.dg.dataframe(arg)
|
498
513
|
else:
|
499
514
|
stringified_arg = str(arg)
|
500
515
|
|
streamlit/error_util.py
CHANGED
@@ -16,7 +16,7 @@ from __future__ import annotations
|
|
16
16
|
|
17
17
|
from typing import Final
|
18
18
|
|
19
|
-
import streamlit
|
19
|
+
import streamlit
|
20
20
|
from streamlit import config
|
21
21
|
from streamlit.errors import UncaughtAppException
|
22
22
|
from streamlit.logger import get_logger
|
@@ -52,9 +52,6 @@ def _print_rich_exception(e: BaseException) -> None:
|
|
52
52
|
tab_size=8,
|
53
53
|
)
|
54
54
|
|
55
|
-
# Import script_runner here to prevent circular import
|
56
|
-
import streamlit.runtime.scriptrunner.script_runner as script_runner
|
57
|
-
|
58
55
|
# Print exception via rich
|
59
56
|
console.print(
|
60
57
|
rich_traceback.Traceback.from_exception(
|
@@ -66,11 +63,16 @@ def _print_rich_exception(e: BaseException) -> None:
|
|
66
63
|
max_frames=100,
|
67
64
|
word_wrap=False,
|
68
65
|
extra_lines=3,
|
69
|
-
suppress=[
|
66
|
+
suppress=[streamlit],
|
70
67
|
)
|
71
68
|
)
|
72
69
|
|
73
70
|
|
71
|
+
def _show_exception(ex: BaseException) -> None:
|
72
|
+
"""Show the exception on the frontend."""
|
73
|
+
streamlit.exception(ex)
|
74
|
+
|
75
|
+
|
74
76
|
def handle_uncaught_app_exception(ex: BaseException) -> None:
|
75
77
|
"""Handle an exception that originated from a user app.
|
76
78
|
|
@@ -78,6 +80,7 @@ def handle_uncaught_app_exception(ex: BaseException) -> None:
|
|
78
80
|
if the user has disabled client error details, we display a generic
|
79
81
|
warning in the frontend instead.
|
80
82
|
"""
|
83
|
+
|
81
84
|
error_logged = False
|
82
85
|
|
83
86
|
if config.get_option("logger.enableRich"):
|
@@ -95,12 +98,11 @@ def handle_uncaught_app_exception(ex: BaseException) -> None:
|
|
95
98
|
|
96
99
|
if config.get_option("client.showErrorDetails"):
|
97
100
|
if not error_logged:
|
98
|
-
# TODO: Clean up the stack trace, so it doesn't include ScriptRunner.
|
99
101
|
_LOGGER.warning("Uncaught app exception", exc_info=ex)
|
100
|
-
|
102
|
+
_show_exception(ex)
|
101
103
|
else:
|
102
104
|
if not error_logged:
|
103
105
|
# Use LOGGER.error, rather than LOGGER.debug, since we don't
|
104
106
|
# show debug logs by default.
|
105
107
|
_LOGGER.error("Uncaught app exception", exc_info=ex)
|
106
|
-
|
108
|
+
_show_exception(UncaughtAppException(ex))
|
streamlit/navigation/page.py
CHANGED
@@ -20,7 +20,7 @@ from typing import Callable
|
|
20
20
|
|
21
21
|
from streamlit.errors import StreamlitAPIException
|
22
22
|
from streamlit.runtime.metrics_util import gather_metrics
|
23
|
-
from streamlit.runtime.
|
23
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
24
24
|
from streamlit.source_util import page_icon_and_name
|
25
25
|
from streamlit.string_util import validate_icon_or_emoji
|
26
26
|
from streamlit.util import calc_md5
|
streamlit/platform.py
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
from __future__ import annotations
|
18
18
|
|
19
19
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
20
|
-
from streamlit.runtime.
|
20
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
21
21
|
|
22
22
|
|
23
23
|
def post_parent_message(message: str) -> None:
|
@@ -66,7 +66,7 @@ from streamlit.runtime.caching.storage.dummy_cache_storage import (
|
|
66
66
|
MemoryCacheStorageManager,
|
67
67
|
)
|
68
68
|
from streamlit.runtime.metrics_util import gather_metrics
|
69
|
-
from streamlit.runtime.
|
69
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
70
70
|
from streamlit.runtime.stats import CacheStat, CacheStatsProvider, group_stats
|
71
71
|
from streamlit.time_util import time_to_seconds
|
72
72
|
|
@@ -43,7 +43,7 @@ from streamlit.runtime.caching.cached_message_replay import (
|
|
43
43
|
show_widget_replay_deprecation,
|
44
44
|
)
|
45
45
|
from streamlit.runtime.metrics_util import gather_metrics
|
46
|
-
from streamlit.runtime.
|
46
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
47
47
|
from streamlit.runtime.stats import CacheStat, CacheStatsProvider, group_stats
|
48
48
|
from streamlit.time_util import time_to_seconds
|
49
49
|
|
@@ -25,7 +25,7 @@ from streamlit import runtime, util
|
|
25
25
|
from streamlit.deprecation_util import show_deprecation_warning
|
26
26
|
from streamlit.runtime.caching.cache_errors import CacheReplayClosureError
|
27
27
|
from streamlit.runtime.caching.hashing import update_hash
|
28
|
-
from streamlit.runtime.
|
28
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
29
29
|
ScriptRunContext,
|
30
30
|
get_script_run_ctx,
|
31
31
|
)
|
streamlit/runtime/context.py
CHANGED
@@ -20,8 +20,7 @@ from typing import TYPE_CHECKING, Any, Iterable, Iterator, Mapping, cast
|
|
20
20
|
|
21
21
|
from streamlit import runtime
|
22
22
|
from streamlit.runtime.metrics_util import gather_metrics
|
23
|
-
from streamlit.runtime.
|
24
|
-
from streamlit.type_util import is_type
|
23
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
25
24
|
|
26
25
|
if TYPE_CHECKING:
|
27
26
|
from http.cookies import Morsel
|
@@ -42,11 +41,13 @@ def _get_request() -> HTTPServerRequest | None:
|
|
42
41
|
# We return websocket request only if session_client is an instance of
|
43
42
|
# BrowserWebSocketHandler (which is True for the Streamlit open-source
|
44
43
|
# implementation). For any other implementation, we return None.
|
45
|
-
|
46
|
-
|
47
|
-
"
|
44
|
+
# We are not using `type_util.is_type` here to avoid circular import.
|
45
|
+
if (
|
46
|
+
f"{type(session_client).__module__}.{type(session_client).__qualname__}"
|
47
|
+
!= "streamlit.web.server.browser_websocket_handler.BrowserWebSocketHandler"
|
48
48
|
):
|
49
49
|
return None
|
50
|
+
|
50
51
|
return cast("RequestHandler", session_client).request
|
51
52
|
|
52
53
|
|
@@ -94,7 +94,7 @@ class ForwardMsgQueue:
|
|
94
94
|
self._queue = []
|
95
95
|
else:
|
96
96
|
self._queue = [
|
97
|
-
msg
|
97
|
+
_update_script_finished_message(msg)
|
98
98
|
for msg in self._queue
|
99
99
|
if msg.WhichOneof("type")
|
100
100
|
in {
|
@@ -166,3 +166,20 @@ def _maybe_compose_deltas(old_delta: Delta, new_delta: Delta) -> Delta | None:
|
|
166
166
|
return new_delta
|
167
167
|
|
168
168
|
return None
|
169
|
+
|
170
|
+
|
171
|
+
def _update_script_finished_message(msg: ForwardMsg) -> ForwardMsg:
|
172
|
+
"""
|
173
|
+
When we are here, the message queue is cleared from non-lifecycle messages
|
174
|
+
before they were flushed to the browser.
|
175
|
+
|
176
|
+
If there were no non-lifecycle messages in the queue, changing the type here
|
177
|
+
should not matter for the frontend anyways, so we optimistically change the
|
178
|
+
`script_finished` message to `FINISHED_EARLY_FOR_RERUN`. This indicates to
|
179
|
+
the frontend that the previous run was interrupted by a new script start.
|
180
|
+
Otherwise, a `FINISHED_SUCCESSFULLY` message might trigger a reset of widget
|
181
|
+
states on the frontend.
|
182
|
+
"""
|
183
|
+
if msg.WhichOneof("type") == "script_finished":
|
184
|
+
msg.script_finished = ForwardMsg.ScriptFinishedStatus.FINISHED_EARLY_FOR_RERUN
|
185
|
+
return msg
|
streamlit/runtime/fragment.py
CHANGED
@@ -30,8 +30,11 @@ from streamlit.error_util import handle_uncaught_app_exception
|
|
30
30
|
from streamlit.errors import FragmentHandledException, FragmentStorageKeyError
|
31
31
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
32
32
|
from streamlit.runtime.metrics_util import gather_metrics
|
33
|
-
from streamlit.runtime.
|
34
|
-
|
33
|
+
from streamlit.runtime.scriptrunner_utils.exceptions import (
|
34
|
+
RerunException,
|
35
|
+
StopException,
|
36
|
+
)
|
37
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
35
38
|
from streamlit.time_util import time_to_seconds
|
36
39
|
|
37
40
|
if TYPE_CHECKING:
|
@@ -160,7 +163,7 @@ def _fragment(
|
|
160
163
|
|
161
164
|
ctx = get_script_run_ctx()
|
162
165
|
if ctx is None:
|
163
|
-
return
|
166
|
+
return None
|
164
167
|
|
165
168
|
cursors_snapshot = deepcopy(ctx.cursors)
|
166
169
|
dg_stack_snapshot = deepcopy(context_dg_stack.get())
|
@@ -265,8 +268,7 @@ def _fragment(
|
|
265
268
|
ctx.current_fragment_id = prev_fragment_id
|
266
269
|
ctx.current_fragment_delta_path = []
|
267
270
|
|
268
|
-
|
269
|
-
ctx.fragment_storage.set(fragment_id, wrapped_fragment)
|
271
|
+
ctx.fragment_storage.set(fragment_id, wrapped_fragment)
|
270
272
|
|
271
273
|
if run_every:
|
272
274
|
msg = ForwardMsg()
|
@@ -28,7 +28,9 @@ _LOGGER: Final = get_logger(__name__)
|
|
28
28
|
|
29
29
|
def _get_session_id() -> str:
|
30
30
|
"""Get the active AppSession's session_id."""
|
31
|
-
from streamlit.runtime.
|
31
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
32
|
+
get_script_run_ctx,
|
33
|
+
)
|
32
34
|
|
33
35
|
ctx = get_script_run_ctx()
|
34
36
|
if ctx is None:
|
@@ -29,6 +29,8 @@ from streamlit import config, util
|
|
29
29
|
from streamlit.logger import get_logger
|
30
30
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
31
31
|
from streamlit.proto.PageProfile_pb2 import Argument, Command
|
32
|
+
from streamlit.runtime.scriptrunner_utils.exceptions import RerunException
|
33
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
32
34
|
|
33
35
|
_LOGGER: Final = get_logger(__name__)
|
34
36
|
|
@@ -364,10 +366,6 @@ def gather_metrics(name: str, func: F | None = None) -> Callable[[F], F] | F:
|
|
364
366
|
from timeit import default_timer as timer
|
365
367
|
|
366
368
|
exec_start = timer()
|
367
|
-
# Local imports to prevent circular dependencies
|
368
|
-
from streamlit.runtime.scriptrunner import get_script_run_ctx
|
369
|
-
from streamlit.runtime.scriptrunner.exceptions import RerunException
|
370
|
-
|
371
369
|
ctx = get_script_run_ctx(suppress_warning=True)
|
372
370
|
|
373
371
|
tracking_activated = (
|
@@ -444,9 +442,6 @@ def create_page_profile_message(
|
|
444
442
|
uncaught_exception: str | None = None,
|
445
443
|
) -> ForwardMsg:
|
446
444
|
"""Create and return the full PageProfile ForwardMsg."""
|
447
|
-
# Local import to prevent circular dependencies
|
448
|
-
from streamlit.runtime.scriptrunner import get_script_run_ctx
|
449
|
-
|
450
445
|
msg = ForwardMsg()
|
451
446
|
page_profile = msg.page_profile
|
452
447
|
|
@@ -12,15 +12,18 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
from streamlit.runtime.scriptrunner.
|
16
|
-
from streamlit.runtime.
|
17
|
-
|
15
|
+
from streamlit.runtime.scriptrunner.script_runner import ScriptRunner, ScriptRunnerEvent
|
16
|
+
from streamlit.runtime.scriptrunner_utils.exceptions import (
|
17
|
+
RerunException,
|
18
|
+
StopException,
|
19
|
+
)
|
20
|
+
from streamlit.runtime.scriptrunner_utils.script_requests import RerunData
|
21
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
18
22
|
ScriptRunContext,
|
19
23
|
add_script_run_ctx,
|
20
24
|
enqueue_message,
|
21
25
|
get_script_run_ctx,
|
22
26
|
)
|
23
|
-
from streamlit.runtime.scriptrunner.script_runner import ScriptRunner, ScriptRunnerEvent
|
24
27
|
|
25
28
|
__all__ = [
|
26
29
|
"RerunData",
|
@@ -22,11 +22,14 @@ from streamlit.delta_generator_singletons import (
|
|
22
22
|
)
|
23
23
|
from streamlit.error_util import handle_uncaught_app_exception
|
24
24
|
from streamlit.errors import FragmentHandledException
|
25
|
-
from streamlit.runtime.
|
25
|
+
from streamlit.runtime.scriptrunner_utils.exceptions import (
|
26
|
+
RerunException,
|
27
|
+
StopException,
|
28
|
+
)
|
26
29
|
|
27
30
|
if TYPE_CHECKING:
|
28
|
-
from streamlit.runtime.
|
29
|
-
from streamlit.runtime.
|
31
|
+
from streamlit.runtime.scriptrunner_utils.script_requests import RerunData
|
32
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import ScriptRunContext
|
30
33
|
|
31
34
|
|
32
35
|
def exec_func_with_error_handling(
|
@@ -30,15 +30,22 @@ from streamlit.errors import FragmentStorageKeyError
|
|
30
30
|
from streamlit.logger import get_logger
|
31
31
|
from streamlit.proto.ClientState_pb2 import ClientState
|
32
32
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
33
|
-
from streamlit.runtime.
|
33
|
+
from streamlit.runtime.metrics_util import (
|
34
|
+
create_page_profile_message,
|
35
|
+
to_microseconds,
|
36
|
+
)
|
34
37
|
from streamlit.runtime.scriptrunner.exec_code import exec_func_with_error_handling
|
35
38
|
from streamlit.runtime.scriptrunner.script_cache import ScriptCache
|
36
|
-
from streamlit.runtime.
|
39
|
+
from streamlit.runtime.scriptrunner_utils.exceptions import (
|
40
|
+
RerunException,
|
41
|
+
StopException,
|
42
|
+
)
|
43
|
+
from streamlit.runtime.scriptrunner_utils.script_requests import (
|
37
44
|
RerunData,
|
38
45
|
ScriptRequests,
|
39
46
|
ScriptRequestType,
|
40
47
|
)
|
41
|
-
from streamlit.runtime.
|
48
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
42
49
|
ScriptRunContext,
|
43
50
|
add_script_run_ctx,
|
44
51
|
get_script_run_ctx,
|
@@ -612,12 +619,6 @@ class ScriptRunner:
|
|
612
619
|
|
613
620
|
if ctx.gather_usage_stats:
|
614
621
|
try:
|
615
|
-
# Prevent issues with circular import
|
616
|
-
from streamlit.runtime.metrics_util import (
|
617
|
-
create_page_profile_message,
|
618
|
-
to_microseconds,
|
619
|
-
)
|
620
|
-
|
621
622
|
# Create and send page profile information
|
622
623
|
ctx.enqueue(
|
623
624
|
create_page_profile_message(
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2024)
|
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
|
+
"""The modules in this package are separated from
|
16
|
+
the scriptrunner-package, because they are more or less
|
17
|
+
standalone and other modules import them quite frequently.
|
18
|
+
This separation helps us to remove dependency cycles.
|
19
|
+
"""
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
from streamlit.runtime.
|
15
|
+
from streamlit.runtime.scriptrunner_utils.script_requests import RerunData
|
16
16
|
from streamlit.util import repr_
|
17
17
|
|
18
18
|
|
@@ -17,13 +17,11 @@ from __future__ import annotations
|
|
17
17
|
import threading
|
18
18
|
from dataclasses import dataclass, field, replace
|
19
19
|
from enum import Enum
|
20
|
-
from typing import
|
20
|
+
from typing import cast
|
21
21
|
|
22
22
|
from streamlit import util
|
23
|
-
from streamlit.
|
24
|
-
|
25
|
-
if TYPE_CHECKING:
|
26
|
-
from streamlit.proto.WidgetStates_pb2 import WidgetStates
|
23
|
+
from streamlit.proto.Common_pb2 import StringTriggerValue as StringTriggerValueProto
|
24
|
+
from streamlit.proto.WidgetStates_pb2 import WidgetState, WidgetStates
|
27
25
|
|
28
26
|
|
29
27
|
class ScriptRequestType(Enum):
|
@@ -91,6 +89,63 @@ def _fragment_run_should_not_preempt_script(
|
|
91
89
|
return bool(fragment_id_queue) and not is_fragment_scoped_rerun
|
92
90
|
|
93
91
|
|
92
|
+
def _coalesce_widget_states(
|
93
|
+
old_states: WidgetStates | None, new_states: WidgetStates | None
|
94
|
+
) -> WidgetStates | None:
|
95
|
+
"""Coalesce an older WidgetStates into a newer one, and return a new
|
96
|
+
WidgetStates containing the result.
|
97
|
+
|
98
|
+
For most widget values, we just take the latest version.
|
99
|
+
|
100
|
+
However, any trigger_values (which are set by buttons) that are True in
|
101
|
+
`old_states` will be set to True in the coalesced result, so that button
|
102
|
+
presses don't go missing.
|
103
|
+
"""
|
104
|
+
if not old_states and not new_states:
|
105
|
+
return None
|
106
|
+
elif not old_states:
|
107
|
+
return new_states
|
108
|
+
elif not new_states:
|
109
|
+
return old_states
|
110
|
+
|
111
|
+
states_by_id: dict[str, WidgetState] = {
|
112
|
+
wstate.id: wstate for wstate in new_states.widgets
|
113
|
+
}
|
114
|
+
|
115
|
+
trigger_value_types = [
|
116
|
+
("trigger_value", False),
|
117
|
+
("string_trigger_value", StringTriggerValueProto(data=None)),
|
118
|
+
]
|
119
|
+
for old_state in old_states.widgets:
|
120
|
+
for trigger_value_type, unset_value in trigger_value_types:
|
121
|
+
if (
|
122
|
+
old_state.WhichOneof("value") == trigger_value_type
|
123
|
+
and getattr(old_state, trigger_value_type) != unset_value
|
124
|
+
):
|
125
|
+
new_trigger_val = states_by_id.get(old_state.id)
|
126
|
+
# It should nearly always be the case that new_trigger_val is None
|
127
|
+
# here as trigger values are deleted from the client's WidgetStateManager
|
128
|
+
# as soon as a rerun_script BackMsg is sent to the server. Since it's
|
129
|
+
# impossible to test that the client sends us state in the expected
|
130
|
+
# format in a unit test, we test for this behavior in
|
131
|
+
# e2e_playwright/test_fragment_queue_test.py
|
132
|
+
if not new_trigger_val or (
|
133
|
+
# Ensure the corresponding new_state is also a trigger;
|
134
|
+
# otherwise, a widget that was previously a button/chat_input but no
|
135
|
+
# longer is could get a bad value.
|
136
|
+
new_trigger_val.WhichOneof("value") == trigger_value_type
|
137
|
+
# We only want to take the value of old_state if new_trigger_val is
|
138
|
+
# unset as the old value may be stale if a newer one was entered.
|
139
|
+
and getattr(new_trigger_val, trigger_value_type) == unset_value
|
140
|
+
):
|
141
|
+
states_by_id[old_state.id] = old_state
|
142
|
+
|
143
|
+
coalesced = WidgetStates()
|
144
|
+
coalesced.widgets.extend(states_by_id.values())
|
145
|
+
|
146
|
+
return coalesced
|
147
|
+
|
148
|
+
|
94
149
|
class ScriptRequests:
|
95
150
|
"""An interface for communicating with a ScriptRunner. Thread-safe.
|
96
151
|
|
@@ -146,7 +201,7 @@ class ScriptRequests:
|
|
146
201
|
# We already have an existing Rerun request, so we can coalesce the new
|
147
202
|
# rerun request into the existing one.
|
148
203
|
|
149
|
-
coalesced_states =
|
204
|
+
coalesced_states = _coalesce_widget_states(
|
150
205
|
self._rerun_data.widget_states, new_data.widget_states
|
151
206
|
)
|
152
207
|
|
@@ -31,7 +31,7 @@ if TYPE_CHECKING:
|
|
31
31
|
from streamlit.proto.PageProfile_pb2 import Command
|
32
32
|
from streamlit.runtime.fragment import FragmentStorage
|
33
33
|
from streamlit.runtime.pages_manager import PagesManager
|
34
|
-
from streamlit.runtime.
|
34
|
+
from streamlit.runtime.scriptrunner_utils.script_requests import ScriptRequests
|
35
35
|
from streamlit.runtime.state import SafeSessionState
|
36
36
|
from streamlit.runtime.uploaded_file_manager import UploadedFileManager
|
37
37
|
_LOGGER: Final = get_logger(__name__)
|
@@ -26,7 +26,6 @@ from streamlit.runtime.state.session_state_proxy import (
|
|
26
26
|
)
|
27
27
|
from streamlit.runtime.state.widgets import (
|
28
28
|
NoValue,
|
29
|
-
coalesce_widget_states,
|
30
29
|
register_widget,
|
31
30
|
)
|
32
31
|
|
@@ -42,6 +41,5 @@ __all__ = [
|
|
42
41
|
"SessionStateProxy",
|
43
42
|
"get_session_state",
|
44
43
|
"NoValue",
|
45
|
-
"coalesce_widget_states",
|
46
44
|
"register_widget",
|
47
45
|
]
|
@@ -66,7 +66,7 @@ from streamlit.util import HASHLIB_KWARGS
|
|
66
66
|
if TYPE_CHECKING:
|
67
67
|
from builtins import ellipsis
|
68
68
|
|
69
|
-
from streamlit.runtime.
|
69
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import ScriptRunContext
|
70
70
|
from streamlit.runtime.state.widgets import NoValue
|
71
71
|
|
72
72
|
|