streamlit-nightly 1.31.2.dev20240213__py2.py3-none-any.whl → 1.31.2.dev20240214__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/case_converters.py +9 -4
- streamlit/cli_util.py +2 -0
- streamlit/code_util.py +5 -2
- streamlit/color_util.py +2 -0
- streamlit/column_config.py +2 -0
- streamlit/commands/execution_control.py +4 -2
- streamlit/commands/experimental_query_params.py +7 -4
- streamlit/commands/page_config.py +11 -9
- streamlit/components/v1/components.py +23 -16
- streamlit/config.py +3 -5
- streamlit/config_option.py +12 -11
- streamlit/connections/base_connection.py +4 -2
- streamlit/connections/snowflake_connection.py +4 -4
- streamlit/connections/snowpark_connection.py +3 -3
- streamlit/connections/sql_connection.py +6 -6
- streamlit/connections/util.py +8 -5
- streamlit/constants.py +2 -0
- streamlit/cursor.py +16 -14
- streamlit/delta_generator.py +10 -13
- streamlit/deprecation_util.py +4 -3
- streamlit/echo.py +5 -3
- streamlit/elements/alert.py +16 -14
- streamlit/elements/altair_utils.py +8 -6
- streamlit/elements/arrow.py +4 -4
- streamlit/elements/arrow_altair.py +24 -34
- streamlit/elements/arrow_vega_lite.py +9 -14
- streamlit/elements/balloons.py +4 -2
- streamlit/elements/bokeh_chart.py +7 -7
- streamlit/elements/code.py +6 -4
- streamlit/elements/deck_gl_json_chart.py +8 -8
- streamlit/elements/doc_string.py +5 -9
- streamlit/elements/empty.py +4 -2
- streamlit/elements/exception.py +10 -10
- streamlit/elements/form.py +1 -3
- streamlit/elements/graphviz_chart.py +5 -6
- streamlit/elements/heading.py +16 -14
- streamlit/elements/iframe.py +14 -12
- streamlit/elements/image.py +8 -8
- streamlit/elements/json.py +6 -4
- streamlit/elements/layouts.py +12 -10
- streamlit/elements/lib/column_config_utils.py +2 -2
- streamlit/elements/lib/column_types.py +23 -23
- streamlit/elements/lib/dicttools.py +10 -6
- streamlit/elements/lib/mutable_status_container.py +7 -7
- streamlit/elements/lib/pandas_styler_utils.py +6 -6
- streamlit/elements/lib/streamlit_plotly_theme.py +2 -0
- streamlit/elements/map.py +11 -22
- streamlit/elements/markdown.py +16 -14
- streamlit/elements/media.py +16 -16
- streamlit/elements/metric.py +9 -7
- streamlit/elements/plotly_chart.py +5 -5
- streamlit/elements/progress.py +6 -6
- streamlit/elements/pyplot.py +10 -13
- streamlit/elements/snow.py +4 -2
- streamlit/elements/spinner.py +2 -0
- streamlit/elements/text.py +7 -5
- streamlit/elements/toast.py +6 -4
- streamlit/elements/utils.py +15 -28
- streamlit/elements/widgets/button.py +39 -39
- streamlit/elements/widgets/camera_input.py +21 -17
- streamlit/elements/widgets/chat.py +6 -7
- streamlit/elements/widgets/checkbox.py +21 -19
- streamlit/elements/widgets/color_picker.py +18 -16
- streamlit/elements/widgets/data_editor.py +7 -7
- streamlit/elements/widgets/file_uploader.py +59 -55
- streamlit/elements/widgets/multiselect.py +33 -42
- streamlit/elements/widgets/number_input.py +10 -5
- streamlit/elements/widgets/radio.py +1 -1
- streamlit/elements/widgets/select_slider.py +25 -34
- streamlit/elements/widgets/selectbox.py +1 -1
- streamlit/elements/widgets/slider.py +28 -36
- streamlit/elements/widgets/text_widgets.py +6 -6
- streamlit/elements/widgets/time_widgets.py +13 -13
- streamlit/elements/write.py +8 -19
- streamlit/env_util.py +5 -3
- streamlit/error_util.py +7 -3
- streamlit/errors.py +3 -1
- streamlit/external/langchain/streamlit_callback_handler.py +26 -24
- streamlit/file_util.py +18 -14
- streamlit/folder_black_list.py +3 -1
- streamlit/git_util.py +5 -3
- streamlit/js_number.py +10 -13
- streamlit/logger.py +5 -5
- streamlit/net_util.py +14 -11
- streamlit/platform.py +2 -0
- streamlit/runtime/__init__.py +2 -0
- streamlit/runtime/app_session.py +42 -42
- streamlit/runtime/caching/__init__.py +4 -4
- streamlit/runtime/caching/cache_data_api.py +3 -3
- streamlit/runtime/caching/cache_errors.py +5 -3
- streamlit/runtime/caching/cache_type.py +2 -0
- streamlit/runtime/caching/cache_utils.py +2 -4
- streamlit/runtime/caching/cached_message_replay.py +12 -5
- streamlit/runtime/caching/storage/cache_storage_protocol.py +1 -2
- streamlit/runtime/caching/storage/local_disk_cache_storage.py +6 -5
- streamlit/runtime/connection_factory.py +8 -8
- streamlit/runtime/forward_msg_cache.py +20 -18
- streamlit/runtime/forward_msg_queue.py +8 -9
- streamlit/runtime/legacy_caching/caching.py +32 -42
- streamlit/runtime/media_file_manager.py +16 -14
- streamlit/runtime/media_file_storage.py +8 -8
- streamlit/runtime/memory_media_file_storage.py +12 -14
- streamlit/runtime/memory_session_storage.py +4 -3
- streamlit/runtime/memory_uploaded_file_manager.py +9 -10
- streamlit/runtime/metrics_util.py +20 -20
- streamlit/runtime/runtime.py +25 -27
- streamlit/runtime/runtime_util.py +5 -3
- streamlit/runtime/script_data.py +2 -0
- streamlit/runtime/scriptrunner/magic.py +17 -11
- streamlit/runtime/scriptrunner/magic_funcs.py +2 -0
- streamlit/runtime/scriptrunner/script_requests.py +6 -4
- streamlit/runtime/scriptrunner/script_run_context.py +17 -17
- streamlit/runtime/scriptrunner/script_runner.py +7 -5
- streamlit/runtime/secrets.py +4 -6
- streamlit/runtime/session_manager.py +14 -14
- streamlit/runtime/state/common.py +5 -4
- streamlit/runtime/state/query_params.py +8 -6
- streamlit/runtime/state/query_params_proxy.py +7 -5
- streamlit/runtime/state/safe_session_state.py +7 -5
- streamlit/runtime/state/session_state.py +3 -4
- streamlit/runtime/state/session_state_proxy.py +5 -5
- streamlit/runtime/state/widgets.py +20 -18
- streamlit/runtime/uploaded_file_manager.py +6 -5
- streamlit/runtime/websocket_session_manager.py +14 -14
- streamlit/source_util.py +13 -11
- streamlit/string_util.py +13 -9
- streamlit/temporary_directory.py +3 -1
- streamlit/testing/v1/element_tree.py +1 -2
- streamlit/type_util.py +21 -25
- streamlit/url_util.py +6 -4
- streamlit/user_info.py +8 -6
- streamlit/util.py +23 -37
- streamlit/watcher/event_based_path_watcher.py +10 -10
- streamlit/watcher/local_sources_watcher.py +15 -13
- streamlit/watcher/path_watcher.py +0 -3
- streamlit/watcher/polling_path_watcher.py +9 -8
- streamlit/watcher/util.py +3 -2
- streamlit/web/cache_storage_manager_config.py +2 -0
- streamlit/web/server/app_static_file_handler.py +6 -5
- streamlit/web/server/browser_websocket_handler.py +10 -8
- streamlit/web/server/component_request_handler.py +7 -4
- streamlit/web/server/media_file_handler.py +5 -4
- streamlit/web/server/routes.py +6 -3
- streamlit/web/server/server.py +31 -31
- streamlit/web/server/server_util.py +4 -2
- streamlit/web/server/upload_file_request_handler.py +7 -8
- streamlit/web/server/websocket_headers.py +2 -2
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/RECORD +153 -153
- {streamlit_nightly-1.31.2.dev20240213.data → streamlit_nightly-1.31.2.dev20240214.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/top_level.txt +0 -0
streamlit/runtime/app_session.py
CHANGED
@@ -11,11 +11,14 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
|
14
17
|
import asyncio
|
15
18
|
import sys
|
16
19
|
import uuid
|
17
20
|
from enum import Enum
|
18
|
-
from typing import TYPE_CHECKING, Callable,
|
21
|
+
from typing import TYPE_CHECKING, Callable, Final
|
19
22
|
|
20
23
|
import streamlit.elements.exception as exception_utils
|
21
24
|
from streamlit import config, runtime, source_util
|
@@ -44,10 +47,11 @@ from streamlit.runtime.uploaded_file_manager import UploadedFileManager
|
|
44
47
|
from streamlit.version import STREAMLIT_VERSION_STRING
|
45
48
|
from streamlit.watcher import LocalSourcesWatcher
|
46
49
|
|
47
|
-
LOGGER = get_logger(__name__)
|
48
50
|
if TYPE_CHECKING:
|
49
51
|
from streamlit.runtime.state import SessionState
|
50
52
|
|
53
|
+
_LOGGER: Final = get_logger(__name__)
|
54
|
+
|
51
55
|
|
52
56
|
class AppSessionState(Enum):
|
53
57
|
APP_NOT_RUNNING = "APP_NOT_RUNNING"
|
@@ -77,10 +81,10 @@ class AppSession:
|
|
77
81
|
script_data: ScriptData,
|
78
82
|
uploaded_file_manager: UploadedFileManager,
|
79
83
|
script_cache: ScriptCache,
|
80
|
-
message_enqueued_callback:
|
84
|
+
message_enqueued_callback: Callable[[], None] | None,
|
81
85
|
local_sources_watcher: LocalSourcesWatcher,
|
82
|
-
user_info:
|
83
|
-
session_id_override:
|
86
|
+
user_info: dict[str, str | None],
|
87
|
+
session_id_override: str | None = None,
|
84
88
|
) -> None:
|
85
89
|
"""Initialize the AppSession.
|
86
90
|
|
@@ -139,17 +143,15 @@ class AppSession:
|
|
139
143
|
# due to the source code changing we need to pass in the previous client state.
|
140
144
|
self._client_state = ClientState()
|
141
145
|
|
142
|
-
self._local_sources_watcher:
|
143
|
-
|
144
|
-
] =
|
145
|
-
self._stop_config_listener: Optional[Callable[[], bool]] = None
|
146
|
-
self._stop_pages_listener: Optional[Callable[[], bool]] = None
|
146
|
+
self._local_sources_watcher: LocalSourcesWatcher | None = local_sources_watcher
|
147
|
+
self._stop_config_listener: Callable[[], bool] | None = None
|
148
|
+
self._stop_pages_listener: Callable[[], None] | None = None
|
147
149
|
|
148
150
|
self.register_file_watchers()
|
149
151
|
|
150
152
|
self._run_on_save = config.get_option("server.runOnSave")
|
151
153
|
|
152
|
-
self._scriptrunner:
|
154
|
+
self._scriptrunner: ScriptRunner | None = None
|
153
155
|
|
154
156
|
# This needs to be lazily imported to avoid a dependency cycle.
|
155
157
|
from streamlit.runtime.state import SessionState
|
@@ -157,9 +159,9 @@ class AppSession:
|
|
157
159
|
self._session_state = SessionState()
|
158
160
|
self._user_info = user_info
|
159
161
|
|
160
|
-
self._debug_last_backmsg_id:
|
162
|
+
self._debug_last_backmsg_id: str | None = None
|
161
163
|
|
162
|
-
|
164
|
+
_LOGGER.debug("AppSession initialized (id=%s)", self.id)
|
163
165
|
|
164
166
|
def __del__(self) -> None:
|
165
167
|
"""Ensure that we call shutdown() when an AppSession is garbage collected."""
|
@@ -210,7 +212,7 @@ class AppSession:
|
|
210
212
|
self._stop_config_listener = None
|
211
213
|
self._stop_pages_listener = None
|
212
214
|
|
213
|
-
def flush_browser_queue(self) ->
|
215
|
+
def flush_browser_queue(self) -> list[ForwardMsg]:
|
214
216
|
"""Clear the forward message queue and return the messages it contained.
|
215
217
|
|
216
218
|
The Server calls this periodically to deliver new messages
|
@@ -232,7 +234,7 @@ class AppSession:
|
|
232
234
|
|
233
235
|
"""
|
234
236
|
if self._state != AppSessionState.SHUTDOWN_REQUESTED:
|
235
|
-
|
237
|
+
_LOGGER.debug("Shutting down (id=%s)", self.id)
|
236
238
|
# Clear any unused session files in upload file manager and media
|
237
239
|
# file manager
|
238
240
|
self._uploaded_file_mgr.remove_session_files(self.id)
|
@@ -298,10 +300,10 @@ class AppSession:
|
|
298
300
|
elif msg_type == "file_urls_request":
|
299
301
|
self._handle_file_urls_request(msg.file_urls_request)
|
300
302
|
else:
|
301
|
-
|
303
|
+
_LOGGER.warning('No handler for "%s"', msg_type)
|
302
304
|
|
303
305
|
except Exception as ex:
|
304
|
-
|
306
|
+
_LOGGER.error(ex)
|
305
307
|
self.handle_backmsg_exception(ex)
|
306
308
|
|
307
309
|
def handle_backmsg_exception(self, e: BaseException) -> None:
|
@@ -333,7 +335,7 @@ class AppSession:
|
|
333
335
|
lambda: self._enqueue_forward_msg(self._create_exception_message(e))
|
334
336
|
)
|
335
337
|
|
336
|
-
def request_rerun(self, client_state:
|
338
|
+
def request_rerun(self, client_state: ClientState | None) -> None:
|
337
339
|
"""Signal that we're interested in running the script.
|
338
340
|
|
339
341
|
If the script is not already running, it will be started immediately.
|
@@ -347,7 +349,7 @@ class AppSession:
|
|
347
349
|
|
348
350
|
"""
|
349
351
|
if self._state == AppSessionState.SHUTDOWN_REQUESTED:
|
350
|
-
|
352
|
+
_LOGGER.warning("Discarding rerun request after shutdown")
|
351
353
|
return
|
352
354
|
|
353
355
|
if client_state:
|
@@ -403,7 +405,7 @@ class AppSession:
|
|
403
405
|
self._scriptrunner.start()
|
404
406
|
|
405
407
|
@property
|
406
|
-
def session_state(self) ->
|
408
|
+
def session_state(self) -> SessionState:
|
407
409
|
return self._session_state
|
408
410
|
|
409
411
|
def _should_rerun_on_file_change(self, filepath: str) -> bool:
|
@@ -421,7 +423,7 @@ class AppSession:
|
|
421
423
|
|
422
424
|
return True
|
423
425
|
|
424
|
-
def _on_source_file_changed(self, filepath:
|
426
|
+
def _on_source_file_changed(self, filepath: str | None = None) -> None:
|
425
427
|
"""One of our source files changed. Clear the cache and schedule a rerun if appropriate."""
|
426
428
|
self._script_cache.clear()
|
427
429
|
|
@@ -456,12 +458,12 @@ class AppSession:
|
|
456
458
|
|
457
459
|
def _on_scriptrunner_event(
|
458
460
|
self,
|
459
|
-
sender:
|
461
|
+
sender: ScriptRunner | None,
|
460
462
|
event: ScriptRunnerEvent,
|
461
|
-
forward_msg:
|
462
|
-
exception:
|
463
|
-
client_state:
|
464
|
-
page_script_hash:
|
463
|
+
forward_msg: ForwardMsg | None = None,
|
464
|
+
exception: BaseException | None = None,
|
465
|
+
client_state: ClientState | None = None,
|
466
|
+
page_script_hash: str | None = None,
|
465
467
|
) -> None:
|
466
468
|
"""Called when our ScriptRunner emits an event.
|
467
469
|
|
@@ -477,12 +479,12 @@ class AppSession:
|
|
477
479
|
|
478
480
|
def _handle_scriptrunner_event_on_event_loop(
|
479
481
|
self,
|
480
|
-
sender:
|
482
|
+
sender: ScriptRunner | None,
|
481
483
|
event: ScriptRunnerEvent,
|
482
|
-
forward_msg:
|
483
|
-
exception:
|
484
|
-
client_state:
|
485
|
-
page_script_hash:
|
484
|
+
forward_msg: ForwardMsg | None = None,
|
485
|
+
exception: BaseException | None = None,
|
486
|
+
client_state: ClientState | None = None,
|
487
|
+
page_script_hash: str | None = None,
|
486
488
|
) -> None:
|
487
489
|
"""Handle a ScriptRunner event.
|
488
490
|
|
@@ -525,7 +527,7 @@ class AppSession:
|
|
525
527
|
# rerun request, for example) while another ScriptRunner is still
|
526
528
|
# shutting down. The shutting-down ScriptRunner may still
|
527
529
|
# emit events.
|
528
|
-
|
530
|
+
_LOGGER.debug("Ignoring event from non-current ScriptRunner: %s", event)
|
529
531
|
return
|
530
532
|
|
531
533
|
prev_state = self._state
|
@@ -663,7 +665,7 @@ class AppSession:
|
|
663
665
|
return msg
|
664
666
|
|
665
667
|
def _create_script_finished_message(
|
666
|
-
self, status:
|
668
|
+
self, status: ForwardMsg.ScriptFinishedStatus.ValueType
|
667
669
|
) -> ForwardMsg:
|
668
670
|
"""Create and return a script_finished ForwardMsg."""
|
669
671
|
msg = ForwardMsg()
|
@@ -712,10 +714,10 @@ class AppSession:
|
|
712
714
|
except Exception as ex:
|
713
715
|
# Users may never even install Git in the first place, so this
|
714
716
|
# error requires no action. It can be useful for debugging.
|
715
|
-
|
717
|
+
_LOGGER.debug("Obtaining Git information produced an error", exc_info=ex)
|
716
718
|
|
717
719
|
def _handle_rerun_script_request(
|
718
|
-
self, client_state:
|
720
|
+
self, client_state: ClientState | None = None
|
719
721
|
) -> None:
|
720
722
|
"""Tell the ScriptRunner to re-run its script.
|
721
723
|
|
@@ -794,10 +796,10 @@ class AppSession:
|
|
794
796
|
# This field will be available at runtime as of protobuf 3.20.1, but
|
795
797
|
# we are using an older version.
|
796
798
|
# For details, see: https://github.com/protocolbuffers/protobuf/issues/8175
|
797
|
-
def _get_toolbar_mode() ->
|
799
|
+
def _get_toolbar_mode() -> Config.ToolbarMode.ValueType:
|
798
800
|
config_key = "client.toolbarMode"
|
799
801
|
config_value = config.get_option(config_key)
|
800
|
-
enum_value:
|
802
|
+
enum_value: Config.ToolbarMode.ValueType | None = getattr(
|
801
803
|
Config.ToolbarMode, config_value.upper()
|
802
804
|
)
|
803
805
|
if enum_value is None:
|
@@ -844,7 +846,7 @@ def _populate_theme_msg(msg: CustomThemeConfig) -> None:
|
|
844
846
|
base = theme_opts["base"]
|
845
847
|
if base is not None:
|
846
848
|
if base not in base_map:
|
847
|
-
|
849
|
+
_LOGGER.warning(
|
848
850
|
f'"{base}" is an invalid value for theme.base.'
|
849
851
|
f" Allowed values include {list(base_map.keys())}."
|
850
852
|
' Setting theme.base to "light".'
|
@@ -860,7 +862,7 @@ def _populate_theme_msg(msg: CustomThemeConfig) -> None:
|
|
860
862
|
font = theme_opts["font"]
|
861
863
|
if font is not None:
|
862
864
|
if font not in font_map:
|
863
|
-
|
865
|
+
_LOGGER.warning(
|
864
866
|
f'"{font}" is an invalid value for theme.font.'
|
865
867
|
f" Allowed values include {list(font_map.keys())}."
|
866
868
|
' Setting theme.font to "sans serif".'
|
@@ -874,9 +876,7 @@ def _populate_user_info_msg(msg: UserInfo) -> None:
|
|
874
876
|
msg.installation_id_v3 = Installation.instance().installation_id_v3
|
875
877
|
|
876
878
|
|
877
|
-
def _populate_app_pages(
|
878
|
-
msg: Union[NewSession, PagesChanged], main_script_path: str
|
879
|
-
) -> None:
|
879
|
+
def _populate_app_pages(msg: NewSession | PagesChanged, main_script_path: str) -> None:
|
880
880
|
for page_script_hash, page_info in source_util.get_pages(main_script_path).items():
|
881
881
|
page_proto = msg.app_pages.add()
|
882
882
|
|
@@ -12,8 +12,10 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
from __future__ import annotations
|
16
|
+
|
15
17
|
import contextlib
|
16
|
-
from typing import Any, Iterator
|
18
|
+
from typing import Any, Iterator
|
17
19
|
|
18
20
|
from google.protobuf.message import Message
|
19
21
|
|
@@ -77,9 +79,7 @@ def save_widget_metadata(metadata: WidgetMetadata[Any]) -> None:
|
|
77
79
|
CACHE_RESOURCE_MESSAGE_REPLAY_CTX.save_widget_metadata(metadata)
|
78
80
|
|
79
81
|
|
80
|
-
def save_media_data(
|
81
|
-
image_data: Union[bytes, str], mimetype: str, image_id: str
|
82
|
-
) -> None:
|
82
|
+
def save_media_data(image_data: bytes | str, mimetype: str, image_id: str) -> None:
|
83
83
|
CACHE_DATA_MESSAGE_REPLAY_CTX.save_image_data(image_data, mimetype, image_id)
|
84
84
|
CACHE_RESOURCE_MESSAGE_REPLAY_CTX.save_image_data(image_data, mimetype, image_id)
|
85
85
|
|
@@ -20,9 +20,9 @@ import pickle
|
|
20
20
|
import threading
|
21
21
|
import types
|
22
22
|
from datetime import timedelta
|
23
|
-
from typing import Any, Callable, TypeVar, Union, cast, overload
|
23
|
+
from typing import Any, Callable, Final, Literal, TypeVar, Union, cast, overload
|
24
24
|
|
25
|
-
from typing_extensions import
|
25
|
+
from typing_extensions import TypeAlias
|
26
26
|
|
27
27
|
import streamlit as st
|
28
28
|
from streamlit import runtime
|
@@ -62,7 +62,7 @@ from streamlit.runtime.metrics_util import gather_metrics
|
|
62
62
|
from streamlit.runtime.scriptrunner.script_run_context import get_script_run_ctx
|
63
63
|
from streamlit.runtime.stats import CacheStat, CacheStatsProvider, group_stats
|
64
64
|
|
65
|
-
_LOGGER = get_logger(__name__)
|
65
|
+
_LOGGER: Final = get_logger(__name__)
|
66
66
|
|
67
67
|
CACHE_DATA_MESSAGE_REPLAY_CTX = CachedMessageReplayContext(CacheType.DATA)
|
68
68
|
|
@@ -12,8 +12,10 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
from __future__ import annotations
|
16
|
+
|
15
17
|
import types
|
16
|
-
from typing import Any
|
18
|
+
from typing import Any
|
17
19
|
|
18
20
|
from streamlit import type_util
|
19
21
|
from streamlit.errors import (
|
@@ -50,7 +52,7 @@ class UnhashableParamError(StreamlitAPIException):
|
|
50
52
|
self,
|
51
53
|
cache_type: CacheType,
|
52
54
|
func: types.FunctionType,
|
53
|
-
arg_name:
|
55
|
+
arg_name: str | None,
|
54
56
|
arg_value: Any,
|
55
57
|
orig_exc: BaseException,
|
56
58
|
):
|
@@ -62,7 +64,7 @@ class UnhashableParamError(StreamlitAPIException):
|
|
62
64
|
def _create_message(
|
63
65
|
cache_type: CacheType,
|
64
66
|
func: types.FunctionType,
|
65
|
-
arg_name:
|
67
|
+
arg_name: str | None,
|
66
68
|
arg_value: Any,
|
67
69
|
) -> str:
|
68
70
|
arg_name_str = arg_name if arg_name is not None else "(unnamed)"
|
@@ -26,9 +26,7 @@ import types
|
|
26
26
|
from abc import abstractmethod
|
27
27
|
from collections import defaultdict
|
28
28
|
from datetime import timedelta
|
29
|
-
from typing import Any, Callable, overload
|
30
|
-
|
31
|
-
from typing_extensions import Literal
|
29
|
+
from typing import Any, Callable, Final, Literal, overload
|
32
30
|
|
33
31
|
from streamlit import type_util
|
34
32
|
from streamlit.elements.spinner import spinner
|
@@ -53,7 +51,7 @@ from streamlit.runtime.caching.cached_message_replay import (
|
|
53
51
|
from streamlit.runtime.caching.hashing import HashFuncsDict, update_hash
|
54
52
|
from streamlit.util import HASHLIB_KWARGS
|
55
53
|
|
56
|
-
_LOGGER = get_logger(__name__)
|
54
|
+
_LOGGER: Final = get_logger(__name__)
|
57
55
|
|
58
56
|
# The timer function we use with TTLCache. This is the default timer func, but
|
59
57
|
# is exposed here as a constant so that it can be patched in unit tests.
|
@@ -19,10 +19,17 @@ import hashlib
|
|
19
19
|
import threading
|
20
20
|
import types
|
21
21
|
from dataclasses import dataclass
|
22
|
-
from typing import
|
22
|
+
from typing import (
|
23
|
+
TYPE_CHECKING,
|
24
|
+
Any,
|
25
|
+
Final,
|
26
|
+
Iterator,
|
27
|
+
Protocol,
|
28
|
+
Union,
|
29
|
+
runtime_checkable,
|
30
|
+
)
|
23
31
|
|
24
32
|
from google.protobuf.message import Message
|
25
|
-
from typing_extensions import Protocol, runtime_checkable
|
26
33
|
|
27
34
|
import streamlit as st
|
28
35
|
from streamlit import runtime, util
|
@@ -45,7 +52,7 @@ from streamlit.util import HASHLIB_KWARGS
|
|
45
52
|
if TYPE_CHECKING:
|
46
53
|
from streamlit.delta_generator import DeltaGenerator
|
47
54
|
|
48
|
-
_LOGGER = get_logger(__name__)
|
55
|
+
_LOGGER: Final = get_logger(__name__)
|
49
56
|
|
50
57
|
|
51
58
|
@runtime_checkable
|
@@ -369,7 +376,7 @@ class CachedMessageReplayContext(threading.local):
|
|
369
376
|
|
370
377
|
def maybe_show_cached_st_function_warning(
|
371
378
|
self,
|
372
|
-
dg:
|
379
|
+
dg: DeltaGenerator,
|
373
380
|
st_func_name: str,
|
374
381
|
) -> None:
|
375
382
|
"""If appropriate, warn about calling st.foo inside @memo.
|
@@ -401,7 +408,7 @@ class CachedMessageReplayContext(threading.local):
|
|
401
408
|
|
402
409
|
def _show_cached_st_function_warning(
|
403
410
|
self,
|
404
|
-
dg:
|
411
|
+
dg: DeltaGenerator,
|
405
412
|
st_func_name: str,
|
406
413
|
cached_func: types.FunctionType,
|
407
414
|
) -> None:
|
@@ -61,6 +61,7 @@ from __future__ import annotations
|
|
61
61
|
import math
|
62
62
|
import os
|
63
63
|
import shutil
|
64
|
+
from typing import Final
|
64
65
|
|
65
66
|
from streamlit import util
|
66
67
|
from streamlit.file_util import get_streamlit_file_path, streamlit_read, streamlit_write
|
@@ -76,16 +77,16 @@ from streamlit.runtime.caching.storage.in_memory_cache_storage_wrapper import (
|
|
76
77
|
InMemoryCacheStorageWrapper,
|
77
78
|
)
|
78
79
|
|
80
|
+
_LOGGER: Final = get_logger(__name__)
|
81
|
+
|
79
82
|
# Streamlit directory where persisted @st.cache_data objects live.
|
80
83
|
# (This is the same directory that @st.cache persisted objects live.
|
81
84
|
# But @st.cache_data uses a different extension, so they don't overlap.)
|
82
|
-
_CACHE_DIR_NAME = "cache"
|
85
|
+
_CACHE_DIR_NAME: Final = "cache"
|
83
86
|
|
84
87
|
# The extension for our persisted @st.cache_data objects.
|
85
88
|
# (`@st.cache_data` was originally called `@st.memo`)
|
86
|
-
_CACHED_FILE_EXTENSION = "memo"
|
87
|
-
|
88
|
-
_LOGGER = get_logger(__name__)
|
89
|
+
_CACHED_FILE_EXTENSION: Final = "memo"
|
89
90
|
|
90
91
|
|
91
92
|
class LocalDiskCacheStorageManager(CacheStorageManager):
|
@@ -168,7 +169,7 @@ class LocalDiskCacheStorage(CacheStorage):
|
|
168
169
|
# Clean up file so we don't leave zero byte files.
|
169
170
|
try:
|
170
171
|
os.remove(path)
|
171
|
-
except (FileNotFoundError,
|
172
|
+
except (FileNotFoundError, OSError):
|
172
173
|
# If we can't remove the file, it's not a big deal.
|
173
174
|
pass
|
174
175
|
raise CacheStorageError("Unable to write to cache") from e
|
@@ -14,13 +14,10 @@
|
|
14
14
|
|
15
15
|
from __future__ import annotations
|
16
16
|
|
17
|
-
import importlib
|
18
17
|
import os
|
19
18
|
import re
|
20
19
|
from datetime import timedelta
|
21
|
-
from typing import Any,
|
22
|
-
|
23
|
-
from typing_extensions import Final, Literal
|
20
|
+
from typing import Any, Final, Literal, TypeVar, overload
|
24
21
|
|
25
22
|
from streamlit.connections import (
|
26
23
|
BaseConnection,
|
@@ -45,7 +42,7 @@ FIRST_PARTY_CONNECTIONS = {
|
|
45
42
|
"sql": SQLConnection,
|
46
43
|
}
|
47
44
|
MODULE_EXTRACTION_REGEX = re.compile(r"No module named \'(.+)\'")
|
48
|
-
MODULES_TO_PYPI_PACKAGES: Final[
|
45
|
+
MODULES_TO_PYPI_PACKAGES: Final[dict[str, str]] = {
|
49
46
|
"MySQLdb": "mysqlclient",
|
50
47
|
"psycopg2": "psycopg2-binary",
|
51
48
|
"sqlalchemy": "sqlalchemy",
|
@@ -63,7 +60,7 @@ ConnectionClass = TypeVar("ConnectionClass", bound=BaseConnection[Any])
|
|
63
60
|
@gather_metrics("connection")
|
64
61
|
def _create_connection(
|
65
62
|
name: str,
|
66
|
-
connection_class:
|
63
|
+
connection_class: type[ConnectionClass],
|
67
64
|
max_entries: int | None = None,
|
68
65
|
ttl: float | timedelta | None = None,
|
69
66
|
**kwargs,
|
@@ -77,7 +74,7 @@ def _create_connection(
|
|
77
74
|
"""
|
78
75
|
|
79
76
|
def __create_connection(
|
80
|
-
name: str, connection_class:
|
77
|
+
name: str, connection_class: type[ConnectionClass], **kwargs
|
81
78
|
) -> ConnectionClass:
|
82
79
|
return connection_class(connection_name=name, **kwargs)
|
83
80
|
|
@@ -184,7 +181,7 @@ def connection_factory(
|
|
184
181
|
@overload
|
185
182
|
def connection_factory(
|
186
183
|
name: str,
|
187
|
-
type:
|
184
|
+
type: type[ConnectionClass],
|
188
185
|
max_entries: int | None = None,
|
189
186
|
ttl: float | timedelta | None = None,
|
190
187
|
**kwargs,
|
@@ -312,6 +309,9 @@ def connection_factory(
|
|
312
309
|
if "." in connection_class:
|
313
310
|
parts = connection_class.split(".")
|
314
311
|
classname = parts.pop()
|
312
|
+
|
313
|
+
import importlib
|
314
|
+
|
315
315
|
connection_module = importlib.import_module(".".join(parts))
|
316
316
|
connection_class = getattr(connection_module, classname)
|
317
317
|
else:
|
@@ -12,8 +12,10 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
from __future__ import annotations
|
16
|
+
|
15
17
|
import hashlib
|
16
|
-
from typing import TYPE_CHECKING,
|
18
|
+
from typing import TYPE_CHECKING, Final, MutableMapping
|
17
19
|
from weakref import WeakKeyDictionary
|
18
20
|
|
19
21
|
from streamlit import config, util
|
@@ -25,7 +27,7 @@ from streamlit.util import HASHLIB_KWARGS
|
|
25
27
|
if TYPE_CHECKING:
|
26
28
|
from streamlit.runtime.app_session import AppSession
|
27
29
|
|
28
|
-
|
30
|
+
_LOGGER: Final = get_logger(__name__)
|
29
31
|
|
30
32
|
|
31
33
|
def populate_hash_if_needed(msg: ForwardMsg) -> str:
|
@@ -107,16 +109,16 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
107
109
|
|
108
110
|
"""
|
109
111
|
|
110
|
-
def __init__(self, msg:
|
112
|
+
def __init__(self, msg: ForwardMsg | None):
|
111
113
|
self.msg = msg
|
112
114
|
self._session_script_run_counts: MutableMapping[
|
113
|
-
|
115
|
+
AppSession, int
|
114
116
|
] = WeakKeyDictionary()
|
115
117
|
|
116
118
|
def __repr__(self) -> str:
|
117
119
|
return util.repr_(self)
|
118
120
|
|
119
|
-
def add_session_ref(self, session:
|
121
|
+
def add_session_ref(self, session: AppSession, script_run_count: int) -> None:
|
120
122
|
"""Adds a reference to a AppSession that has referenced
|
121
123
|
this Entry's message.
|
122
124
|
|
@@ -129,18 +131,18 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
129
131
|
"""
|
130
132
|
prev_run_count = self._session_script_run_counts.get(session, 0)
|
131
133
|
if script_run_count < prev_run_count:
|
132
|
-
|
134
|
+
_LOGGER.error(
|
133
135
|
"New script_run_count (%s) is < prev_run_count (%s). "
|
134
136
|
"This should never happen!" % (script_run_count, prev_run_count)
|
135
137
|
)
|
136
138
|
script_run_count = prev_run_count
|
137
139
|
self._session_script_run_counts[session] = script_run_count
|
138
140
|
|
139
|
-
def has_session_ref(self, session:
|
141
|
+
def has_session_ref(self, session: AppSession) -> bool:
|
140
142
|
return session in self._session_script_run_counts
|
141
143
|
|
142
144
|
def get_session_ref_age(
|
143
|
-
self, session:
|
145
|
+
self, session: AppSession, script_run_count: int
|
144
146
|
) -> int:
|
145
147
|
"""The age of the given session's reference to the Entry,
|
146
148
|
given a new script_run_count.
|
@@ -148,7 +150,7 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
148
150
|
"""
|
149
151
|
return script_run_count - self._session_script_run_counts[session]
|
150
152
|
|
151
|
-
def remove_session_ref(self, session:
|
153
|
+
def remove_session_ref(self, session: AppSession) -> None:
|
152
154
|
del self._session_script_run_counts[session]
|
153
155
|
|
154
156
|
def has_refs(self) -> bool:
|
@@ -159,13 +161,13 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
159
161
|
return len(self._session_script_run_counts) > 0
|
160
162
|
|
161
163
|
def __init__(self):
|
162
|
-
self._entries:
|
164
|
+
self._entries: dict[str, ForwardMsgCache.Entry] = {}
|
163
165
|
|
164
166
|
def __repr__(self) -> str:
|
165
167
|
return util.repr_(self)
|
166
168
|
|
167
169
|
def add_message(
|
168
|
-
self, msg: ForwardMsg, session:
|
170
|
+
self, msg: ForwardMsg, session: AppSession, script_run_count: int
|
169
171
|
) -> None:
|
170
172
|
"""Add a ForwardMsg to the cache.
|
171
173
|
|
@@ -191,7 +193,7 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
191
193
|
self._entries[msg.hash] = entry
|
192
194
|
entry.add_session_ref(session, script_run_count)
|
193
195
|
|
194
|
-
def get_message(self, hash: str) ->
|
196
|
+
def get_message(self, hash: str) -> ForwardMsg | None:
|
195
197
|
"""Return the message with the given ID if it exists in the cache.
|
196
198
|
|
197
199
|
Parameters
|
@@ -208,7 +210,7 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
208
210
|
return entry.msg if entry else None
|
209
211
|
|
210
212
|
def has_message_reference(
|
211
|
-
self, msg: ForwardMsg, session:
|
213
|
+
self, msg: ForwardMsg, session: AppSession, script_run_count: int
|
212
214
|
) -> bool:
|
213
215
|
"""Return True if a session has a reference to a message."""
|
214
216
|
populate_hash_if_needed(msg)
|
@@ -221,7 +223,7 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
221
223
|
age = entry.get_session_ref_age(session, script_run_count)
|
222
224
|
return age <= int(config.get_option("global.maxCachedMessageAge"))
|
223
225
|
|
224
|
-
def remove_refs_for_session(self, session:
|
226
|
+
def remove_refs_for_session(self, session: AppSession) -> None:
|
225
227
|
"""Remove refs for all entries for the given session.
|
226
228
|
|
227
229
|
This should be called when an AppSession is disconnected or closed.
|
@@ -243,7 +245,7 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
243
245
|
del self._entries[msg_hash]
|
244
246
|
|
245
247
|
def remove_expired_entries_for_session(
|
246
|
-
self, session:
|
248
|
+
self, session: AppSession, script_run_count: int
|
247
249
|
) -> None:
|
248
250
|
"""Remove any cached messages that have expired from the given session.
|
249
251
|
|
@@ -266,7 +268,7 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
266
268
|
|
267
269
|
age = entry.get_session_ref_age(session, script_run_count)
|
268
270
|
if age > max_age:
|
269
|
-
|
271
|
+
_LOGGER.debug(
|
270
272
|
"Removing expired entry [session=%s, hash=%s, age=%s]",
|
271
273
|
id(session),
|
272
274
|
msg_hash,
|
@@ -282,8 +284,8 @@ class ForwardMsgCache(CacheStatsProvider):
|
|
282
284
|
"""Remove all entries from the cache"""
|
283
285
|
self._entries.clear()
|
284
286
|
|
285
|
-
def get_stats(self) ->
|
286
|
-
stats:
|
287
|
+
def get_stats(self) -> list[CacheStat]:
|
288
|
+
stats: list[CacheStat] = []
|
287
289
|
for entry_hash, entry in self._entries.items():
|
288
290
|
stats.append(
|
289
291
|
CacheStat(
|