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.
Files changed (153) hide show
  1. streamlit/case_converters.py +9 -4
  2. streamlit/cli_util.py +2 -0
  3. streamlit/code_util.py +5 -2
  4. streamlit/color_util.py +2 -0
  5. streamlit/column_config.py +2 -0
  6. streamlit/commands/execution_control.py +4 -2
  7. streamlit/commands/experimental_query_params.py +7 -4
  8. streamlit/commands/page_config.py +11 -9
  9. streamlit/components/v1/components.py +23 -16
  10. streamlit/config.py +3 -5
  11. streamlit/config_option.py +12 -11
  12. streamlit/connections/base_connection.py +4 -2
  13. streamlit/connections/snowflake_connection.py +4 -4
  14. streamlit/connections/snowpark_connection.py +3 -3
  15. streamlit/connections/sql_connection.py +6 -6
  16. streamlit/connections/util.py +8 -5
  17. streamlit/constants.py +2 -0
  18. streamlit/cursor.py +16 -14
  19. streamlit/delta_generator.py +10 -13
  20. streamlit/deprecation_util.py +4 -3
  21. streamlit/echo.py +5 -3
  22. streamlit/elements/alert.py +16 -14
  23. streamlit/elements/altair_utils.py +8 -6
  24. streamlit/elements/arrow.py +4 -4
  25. streamlit/elements/arrow_altair.py +24 -34
  26. streamlit/elements/arrow_vega_lite.py +9 -14
  27. streamlit/elements/balloons.py +4 -2
  28. streamlit/elements/bokeh_chart.py +7 -7
  29. streamlit/elements/code.py +6 -4
  30. streamlit/elements/deck_gl_json_chart.py +8 -8
  31. streamlit/elements/doc_string.py +5 -9
  32. streamlit/elements/empty.py +4 -2
  33. streamlit/elements/exception.py +10 -10
  34. streamlit/elements/form.py +1 -3
  35. streamlit/elements/graphviz_chart.py +5 -6
  36. streamlit/elements/heading.py +16 -14
  37. streamlit/elements/iframe.py +14 -12
  38. streamlit/elements/image.py +8 -8
  39. streamlit/elements/json.py +6 -4
  40. streamlit/elements/layouts.py +12 -10
  41. streamlit/elements/lib/column_config_utils.py +2 -2
  42. streamlit/elements/lib/column_types.py +23 -23
  43. streamlit/elements/lib/dicttools.py +10 -6
  44. streamlit/elements/lib/mutable_status_container.py +7 -7
  45. streamlit/elements/lib/pandas_styler_utils.py +6 -6
  46. streamlit/elements/lib/streamlit_plotly_theme.py +2 -0
  47. streamlit/elements/map.py +11 -22
  48. streamlit/elements/markdown.py +16 -14
  49. streamlit/elements/media.py +16 -16
  50. streamlit/elements/metric.py +9 -7
  51. streamlit/elements/plotly_chart.py +5 -5
  52. streamlit/elements/progress.py +6 -6
  53. streamlit/elements/pyplot.py +10 -13
  54. streamlit/elements/snow.py +4 -2
  55. streamlit/elements/spinner.py +2 -0
  56. streamlit/elements/text.py +7 -5
  57. streamlit/elements/toast.py +6 -4
  58. streamlit/elements/utils.py +15 -28
  59. streamlit/elements/widgets/button.py +39 -39
  60. streamlit/elements/widgets/camera_input.py +21 -17
  61. streamlit/elements/widgets/chat.py +6 -7
  62. streamlit/elements/widgets/checkbox.py +21 -19
  63. streamlit/elements/widgets/color_picker.py +18 -16
  64. streamlit/elements/widgets/data_editor.py +7 -7
  65. streamlit/elements/widgets/file_uploader.py +59 -55
  66. streamlit/elements/widgets/multiselect.py +33 -42
  67. streamlit/elements/widgets/number_input.py +10 -5
  68. streamlit/elements/widgets/radio.py +1 -1
  69. streamlit/elements/widgets/select_slider.py +25 -34
  70. streamlit/elements/widgets/selectbox.py +1 -1
  71. streamlit/elements/widgets/slider.py +28 -36
  72. streamlit/elements/widgets/text_widgets.py +6 -6
  73. streamlit/elements/widgets/time_widgets.py +13 -13
  74. streamlit/elements/write.py +8 -19
  75. streamlit/env_util.py +5 -3
  76. streamlit/error_util.py +7 -3
  77. streamlit/errors.py +3 -1
  78. streamlit/external/langchain/streamlit_callback_handler.py +26 -24
  79. streamlit/file_util.py +18 -14
  80. streamlit/folder_black_list.py +3 -1
  81. streamlit/git_util.py +5 -3
  82. streamlit/js_number.py +10 -13
  83. streamlit/logger.py +5 -5
  84. streamlit/net_util.py +14 -11
  85. streamlit/platform.py +2 -0
  86. streamlit/runtime/__init__.py +2 -0
  87. streamlit/runtime/app_session.py +42 -42
  88. streamlit/runtime/caching/__init__.py +4 -4
  89. streamlit/runtime/caching/cache_data_api.py +3 -3
  90. streamlit/runtime/caching/cache_errors.py +5 -3
  91. streamlit/runtime/caching/cache_type.py +2 -0
  92. streamlit/runtime/caching/cache_utils.py +2 -4
  93. streamlit/runtime/caching/cached_message_replay.py +12 -5
  94. streamlit/runtime/caching/storage/cache_storage_protocol.py +1 -2
  95. streamlit/runtime/caching/storage/local_disk_cache_storage.py +6 -5
  96. streamlit/runtime/connection_factory.py +8 -8
  97. streamlit/runtime/forward_msg_cache.py +20 -18
  98. streamlit/runtime/forward_msg_queue.py +8 -9
  99. streamlit/runtime/legacy_caching/caching.py +32 -42
  100. streamlit/runtime/media_file_manager.py +16 -14
  101. streamlit/runtime/media_file_storage.py +8 -8
  102. streamlit/runtime/memory_media_file_storage.py +12 -14
  103. streamlit/runtime/memory_session_storage.py +4 -3
  104. streamlit/runtime/memory_uploaded_file_manager.py +9 -10
  105. streamlit/runtime/metrics_util.py +20 -20
  106. streamlit/runtime/runtime.py +25 -27
  107. streamlit/runtime/runtime_util.py +5 -3
  108. streamlit/runtime/script_data.py +2 -0
  109. streamlit/runtime/scriptrunner/magic.py +17 -11
  110. streamlit/runtime/scriptrunner/magic_funcs.py +2 -0
  111. streamlit/runtime/scriptrunner/script_requests.py +6 -4
  112. streamlit/runtime/scriptrunner/script_run_context.py +17 -17
  113. streamlit/runtime/scriptrunner/script_runner.py +7 -5
  114. streamlit/runtime/secrets.py +4 -6
  115. streamlit/runtime/session_manager.py +14 -14
  116. streamlit/runtime/state/common.py +5 -4
  117. streamlit/runtime/state/query_params.py +8 -6
  118. streamlit/runtime/state/query_params_proxy.py +7 -5
  119. streamlit/runtime/state/safe_session_state.py +7 -5
  120. streamlit/runtime/state/session_state.py +3 -4
  121. streamlit/runtime/state/session_state_proxy.py +5 -5
  122. streamlit/runtime/state/widgets.py +20 -18
  123. streamlit/runtime/uploaded_file_manager.py +6 -5
  124. streamlit/runtime/websocket_session_manager.py +14 -14
  125. streamlit/source_util.py +13 -11
  126. streamlit/string_util.py +13 -9
  127. streamlit/temporary_directory.py +3 -1
  128. streamlit/testing/v1/element_tree.py +1 -2
  129. streamlit/type_util.py +21 -25
  130. streamlit/url_util.py +6 -4
  131. streamlit/user_info.py +8 -6
  132. streamlit/util.py +23 -37
  133. streamlit/watcher/event_based_path_watcher.py +10 -10
  134. streamlit/watcher/local_sources_watcher.py +15 -13
  135. streamlit/watcher/path_watcher.py +0 -3
  136. streamlit/watcher/polling_path_watcher.py +9 -8
  137. streamlit/watcher/util.py +3 -2
  138. streamlit/web/cache_storage_manager_config.py +2 -0
  139. streamlit/web/server/app_static_file_handler.py +6 -5
  140. streamlit/web/server/browser_websocket_handler.py +10 -8
  141. streamlit/web/server/component_request_handler.py +7 -4
  142. streamlit/web/server/media_file_handler.py +5 -4
  143. streamlit/web/server/routes.py +6 -3
  144. streamlit/web/server/server.py +31 -31
  145. streamlit/web/server/server_util.py +4 -2
  146. streamlit/web/server/upload_file_request_handler.py +7 -8
  147. streamlit/web/server/websocket_headers.py +2 -2
  148. {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/METADATA +1 -1
  149. {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/RECORD +153 -153
  150. {streamlit_nightly-1.31.2.dev20240213.data → streamlit_nightly-1.31.2.dev20240214.data}/scripts/streamlit.cmd +0 -0
  151. {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/WHEEL +0 -0
  152. {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/entry_points.txt +0 -0
  153. {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/top_level.txt +0 -0
@@ -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, Dict, List, Optional, Union
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: Optional[Callable[[], None]],
84
+ message_enqueued_callback: Callable[[], None] | None,
81
85
  local_sources_watcher: LocalSourcesWatcher,
82
- user_info: Dict[str, Optional[str]],
83
- session_id_override: Optional[str] = None,
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: Optional[
143
- LocalSourcesWatcher
144
- ] = local_sources_watcher
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: Optional[ScriptRunner] = None
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: Optional[str] = None
162
+ self._debug_last_backmsg_id: str | None = None
161
163
 
162
- LOGGER.debug("AppSession initialized (id=%s)", self.id)
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) -> List[ForwardMsg]:
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
- LOGGER.debug("Shutting down (id=%s)", self.id)
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
- LOGGER.warning('No handler for "%s"', msg_type)
303
+ _LOGGER.warning('No handler for "%s"', msg_type)
302
304
 
303
305
  except Exception as ex:
304
- LOGGER.error(ex)
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: Optional[ClientState]) -> None:
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
- LOGGER.warning("Discarding rerun request after shutdown")
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) -> "SessionState":
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: Optional[str] = None) -> None:
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: Optional[ScriptRunner],
461
+ sender: ScriptRunner | None,
460
462
  event: ScriptRunnerEvent,
461
- forward_msg: Optional[ForwardMsg] = None,
462
- exception: Optional[BaseException] = None,
463
- client_state: Optional[ClientState] = None,
464
- page_script_hash: Optional[str] = None,
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: Optional[ScriptRunner],
482
+ sender: ScriptRunner | None,
481
483
  event: ScriptRunnerEvent,
482
- forward_msg: Optional[ForwardMsg] = None,
483
- exception: Optional[BaseException] = None,
484
- client_state: Optional[ClientState] = None,
485
- page_script_hash: Optional[str] = None,
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
- LOGGER.debug("Ignoring event from non-current ScriptRunner: %s", event)
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: "ForwardMsg.ScriptFinishedStatus.ValueType"
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
- LOGGER.debug("Obtaining Git information produced an error", exc_info=ex)
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: Optional[ClientState] = None
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() -> "Config.ToolbarMode.ValueType":
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: Optional["Config.ToolbarMode.ValueType"] = getattr(
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
- LOGGER.warning(
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
- LOGGER.warning(
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, Union
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 Literal, TypeAlias
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, Optional
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: Optional[str],
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: Optional[str],
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)"
@@ -12,6 +12,8 @@
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 enum
16
18
 
17
19
 
@@ -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 TYPE_CHECKING, Any, Iterator, Union
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: "DeltaGenerator",
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: "DeltaGenerator",
411
+ dg: DeltaGenerator,
405
412
  st_func_name: str,
406
413
  cached_func: types.FunctionType,
407
414
  ) -> None:
@@ -57,8 +57,7 @@ from __future__ import annotations
57
57
 
58
58
  from abc import abstractmethod
59
59
  from dataclasses import dataclass
60
-
61
- from typing_extensions import Literal, Protocol
60
+ from typing import Literal, Protocol
62
61
 
63
62
 
64
63
  class CacheStorageError(Exception):
@@ -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, IOError, OSError):
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, Dict, Type, TypeVar, overload
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[Dict[str, str]] = {
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: Type[ConnectionClass],
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: Type[ConnectionClass], **kwargs
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: Type[ConnectionClass],
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, Dict, List, MutableMapping, Optional
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
- LOGGER = get_logger(__name__)
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: Optional[ForwardMsg]):
112
+ def __init__(self, msg: ForwardMsg | None):
111
113
  self.msg = msg
112
114
  self._session_script_run_counts: MutableMapping[
113
- "AppSession", int
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: "AppSession", script_run_count: int) -> None:
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
- LOGGER.error(
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: "AppSession") -> bool:
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: "AppSession", script_run_count: int
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: "AppSession") -> None:
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: Dict[str, "ForwardMsgCache.Entry"] = {}
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: "AppSession", script_run_count: int
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) -> Optional[ForwardMsg]:
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: "AppSession", script_run_count: int
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: "AppSession") -> None:
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: "AppSession", script_run_count: int
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
- LOGGER.debug(
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) -> List[CacheStat]:
286
- stats: List[CacheStat] = []
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(