streamlit-nightly 1.31.2.dev20240212__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 (184) 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 +21 -29
  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/hashing.py +29 -21
  95. streamlit/runtime/caching/storage/cache_storage_protocol.py +1 -2
  96. streamlit/runtime/caching/storage/local_disk_cache_storage.py +6 -5
  97. streamlit/runtime/connection_factory.py +8 -8
  98. streamlit/runtime/forward_msg_cache.py +20 -18
  99. streamlit/runtime/forward_msg_queue.py +8 -9
  100. streamlit/runtime/legacy_caching/caching.py +32 -42
  101. streamlit/runtime/legacy_caching/hashing.py +29 -25
  102. streamlit/runtime/media_file_manager.py +16 -14
  103. streamlit/runtime/media_file_storage.py +8 -8
  104. streamlit/runtime/memory_media_file_storage.py +12 -14
  105. streamlit/runtime/memory_session_storage.py +4 -3
  106. streamlit/runtime/memory_uploaded_file_manager.py +9 -10
  107. streamlit/runtime/metrics_util.py +20 -20
  108. streamlit/runtime/runtime.py +25 -27
  109. streamlit/runtime/runtime_util.py +5 -3
  110. streamlit/runtime/script_data.py +2 -0
  111. streamlit/runtime/scriptrunner/magic.py +17 -11
  112. streamlit/runtime/scriptrunner/magic_funcs.py +2 -0
  113. streamlit/runtime/scriptrunner/script_requests.py +6 -4
  114. streamlit/runtime/scriptrunner/script_run_context.py +17 -17
  115. streamlit/runtime/scriptrunner/script_runner.py +7 -5
  116. streamlit/runtime/secrets.py +4 -6
  117. streamlit/runtime/session_manager.py +14 -14
  118. streamlit/runtime/state/common.py +5 -4
  119. streamlit/runtime/state/query_params.py +8 -6
  120. streamlit/runtime/state/query_params_proxy.py +7 -5
  121. streamlit/runtime/state/safe_session_state.py +7 -5
  122. streamlit/runtime/state/session_state.py +3 -4
  123. streamlit/runtime/state/session_state_proxy.py +5 -5
  124. streamlit/runtime/state/widgets.py +20 -18
  125. streamlit/runtime/stats.py +13 -15
  126. streamlit/runtime/uploaded_file_manager.py +6 -5
  127. streamlit/runtime/websocket_session_manager.py +14 -14
  128. streamlit/source_util.py +13 -11
  129. streamlit/static/asset-manifest.json +13 -13
  130. streamlit/static/index.html +1 -1
  131. streamlit/static/static/css/2411.8b8f33d6.chunk.css +1 -0
  132. streamlit/static/static/css/43.e3b876c5.chunk.css +1 -0
  133. streamlit/static/static/css/6692.65519639.chunk.css +1 -0
  134. streamlit/static/static/js/{3075.76725a14.chunk.js → 2411.714d213e.chunk.js} +2 -2
  135. streamlit/static/static/js/4185.21ca0590.chunk.js +1 -0
  136. streamlit/static/static/js/43.36939bb1.chunk.js +1 -0
  137. streamlit/static/static/js/{5117.6a701db1.chunk.js → 5117.04bfe5d3.chunk.js} +1 -1
  138. streamlit/static/static/js/{5791.30b01ee8.chunk.js → 5791.c5138157.chunk.js} +1 -1
  139. streamlit/static/static/js/656.8c998bc8.chunk.js +2 -0
  140. streamlit/static/static/js/{6692.6ac4ea6f.chunk.js → 6692.6496cbc2.chunk.js} +1 -1
  141. streamlit/static/static/js/7142.400eefdd.chunk.js +1 -0
  142. streamlit/static/static/js/main.2737c0f9.js +2 -0
  143. streamlit/static/static/js/{main.043d802e.js.LICENSE.txt → main.2737c0f9.js.LICENSE.txt} +23 -25
  144. streamlit/string_util.py +13 -9
  145. streamlit/temporary_directory.py +3 -1
  146. streamlit/testing/v1/element_tree.py +1 -2
  147. streamlit/testing/v1/util.py +7 -3
  148. streamlit/type_util.py +30 -25
  149. streamlit/url_util.py +6 -4
  150. streamlit/user_info.py +8 -6
  151. streamlit/util.py +23 -37
  152. streamlit/version.py +16 -9
  153. streamlit/watcher/event_based_path_watcher.py +10 -10
  154. streamlit/watcher/local_sources_watcher.py +15 -13
  155. streamlit/watcher/path_watcher.py +0 -3
  156. streamlit/watcher/polling_path_watcher.py +9 -8
  157. streamlit/watcher/util.py +3 -2
  158. streamlit/web/cache_storage_manager_config.py +2 -0
  159. streamlit/web/server/app_static_file_handler.py +6 -5
  160. streamlit/web/server/browser_websocket_handler.py +10 -8
  161. streamlit/web/server/component_request_handler.py +7 -4
  162. streamlit/web/server/media_file_handler.py +5 -4
  163. streamlit/web/server/routes.py +6 -3
  164. streamlit/web/server/server.py +41 -34
  165. streamlit/web/server/server_util.py +8 -3
  166. streamlit/web/server/stats_request_handler.py +14 -5
  167. streamlit/web/server/upload_file_request_handler.py +7 -8
  168. streamlit/web/server/websocket_headers.py +2 -2
  169. {streamlit_nightly-1.31.2.dev20240212.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/METADATA +1 -1
  170. {streamlit_nightly-1.31.2.dev20240212.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/RECORD +176 -176
  171. streamlit/static/static/css/3075.81b3d18f.chunk.css +0 -1
  172. streamlit/static/static/css/43.c24b25fa.chunk.css +0 -1
  173. streamlit/static/static/css/6692.bb444a79.chunk.css +0 -1
  174. streamlit/static/static/js/1215.baf3721f.chunk.js +0 -2
  175. streamlit/static/static/js/4185.90e929dc.chunk.js +0 -1
  176. streamlit/static/static/js/43.8ca4bc8a.chunk.js +0 -1
  177. streamlit/static/static/js/7142.a359ed63.chunk.js +0 -1
  178. streamlit/static/static/js/main.043d802e.js +0 -2
  179. /streamlit/static/static/js/{3075.76725a14.chunk.js.LICENSE.txt → 2411.714d213e.chunk.js.LICENSE.txt} +0 -0
  180. /streamlit/static/static/js/{1215.baf3721f.chunk.js.LICENSE.txt → 656.8c998bc8.chunk.js.LICENSE.txt} +0 -0
  181. {streamlit_nightly-1.31.2.dev20240212.data → streamlit_nightly-1.31.2.dev20240214.data}/scripts/streamlit.cmd +0 -0
  182. {streamlit_nightly-1.31.2.dev20240212.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/WHEEL +0 -0
  183. {streamlit_nightly-1.31.2.dev20240212.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/entry_points.txt +0 -0
  184. {streamlit_nightly-1.31.2.dev20240212.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/top_level.txt +0 -0
@@ -14,14 +14,16 @@
14
14
 
15
15
  """Provides global MediaFileManager object as `media_file_manager`."""
16
16
 
17
+ from __future__ import annotations
18
+
17
19
  import collections
18
20
  import threading
19
- from typing import Dict, Optional, Set, Union
21
+ from typing import Final
20
22
 
21
23
  from streamlit.logger import get_logger
22
24
  from streamlit.runtime.media_file_storage import MediaFileKind, MediaFileStorage
23
25
 
24
- LOGGER = get_logger(__name__)
26
+ _LOGGER: Final = get_logger(__name__)
25
27
 
26
28
 
27
29
  def _get_session_id() -> str:
@@ -80,11 +82,11 @@ class MediaFileManager:
80
82
  self._storage = storage
81
83
 
82
84
  # Dict of [file_id -> MediaFileMetadata]
83
- self._file_metadata: Dict[str, MediaFileMetadata] = dict()
85
+ self._file_metadata: dict[str, MediaFileMetadata] = dict()
84
86
 
85
87
  # Dict[session ID][coordinates] -> file_id.
86
- self._files_by_session_and_coord: Dict[
87
- str, Dict[str, str]
88
+ self._files_by_session_and_coord: dict[
89
+ str, dict[str, str]
88
90
  ] = collections.defaultdict(dict)
89
91
 
90
92
  # MediaFileManager is used from multiple threads, so all operations
@@ -92,7 +94,7 @@ class MediaFileManager:
92
94
  # means taking it multiple times from the same thread will deadlock.)
93
95
  self._lock = threading.Lock()
94
96
 
95
- def _get_inactive_file_ids(self) -> Set[str]:
97
+ def _get_inactive_file_ids(self) -> set[str]:
96
98
  """Compute the set of files that are stored in the manager, but are
97
99
  not referenced by any active session. These are files that can be
98
100
  safely deleted.
@@ -113,7 +115,7 @@ class MediaFileManager:
113
115
 
114
116
  Safe to call from any thread.
115
117
  """
116
- LOGGER.debug("Removing orphaned files...")
118
+ _LOGGER.debug("Removing orphaned files...")
117
119
 
118
120
  with self._lock:
119
121
  for file_id in self._get_inactive_file_ids():
@@ -132,11 +134,11 @@ class MediaFileManager:
132
134
 
133
135
  Thread safety: callers must hold `self._lock`.
134
136
  """
135
- LOGGER.debug("Deleting File: %s", file_id)
137
+ _LOGGER.debug("Deleting File: %s", file_id)
136
138
  self._storage.delete_file(file_id)
137
139
  del self._file_metadata[file_id]
138
140
 
139
- def clear_session_refs(self, session_id: Optional[str] = None) -> None:
141
+ def clear_session_refs(self, session_id: str | None = None) -> None:
140
142
  """Remove the given session's file references.
141
143
 
142
144
  (This does not remove any files from the manager - you must call
@@ -149,17 +151,17 @@ class MediaFileManager:
149
151
  if session_id is None:
150
152
  session_id = _get_session_id()
151
153
 
152
- LOGGER.debug("Disconnecting files for session with ID %s", session_id)
154
+ _LOGGER.debug("Disconnecting files for session with ID %s", session_id)
153
155
 
154
156
  with self._lock:
155
157
  if session_id in self._files_by_session_and_coord:
156
158
  del self._files_by_session_and_coord[session_id]
157
159
 
158
- LOGGER.debug(
160
+ _LOGGER.debug(
159
161
  "Sessions still active: %r", self._files_by_session_and_coord.keys()
160
162
  )
161
163
 
162
- LOGGER.debug(
164
+ _LOGGER.debug(
163
165
  "Files: %s; Sessions with files: %s",
164
166
  len(self._file_metadata),
165
167
  len(self._files_by_session_and_coord),
@@ -167,10 +169,10 @@ class MediaFileManager:
167
169
 
168
170
  def add(
169
171
  self,
170
- path_or_data: Union[bytes, str],
172
+ path_or_data: bytes | str,
171
173
  mimetype: str,
172
174
  coordinates: str,
173
- file_name: Optional[str] = None,
175
+ file_name: str | None = None,
174
176
  is_for_static_download: bool = False,
175
177
  ) -> str:
176
178
  """Add a new MediaFile with the given parameters and return its URL.
@@ -12,11 +12,11 @@
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
  from abc import abstractmethod
16
18
  from enum import Enum
17
- from typing import Optional, Union
18
-
19
- from typing_extensions import Protocol
19
+ from typing import Protocol
20
20
 
21
21
 
22
22
  class MediaFileKind(Enum):
@@ -43,17 +43,17 @@ class MediaFileStorage(Protocol):
43
43
  @abstractmethod
44
44
  def load_and_get_id(
45
45
  self,
46
- path_or_data: Union[str, bytes],
46
+ path_or_data: str | bytes,
47
47
  mimetype: str,
48
48
  kind: MediaFileKind,
49
- filename: Optional[str] = None,
49
+ filename: str | None = None,
50
50
  ) -> str:
51
51
  """Load the given file path or bytes into the manager and return
52
52
  an ID that uniquely identifies it.
53
53
 
54
- Its an error to pass a URL to this function. (Media stored at
54
+ It's an error to pass a URL to this function. (Media stored at
55
55
  external URLs can be served directly to the Streamlit frontend;
56
- theres no need to store this data in MediaFileStorage.)
56
+ there's no need to store this data in MediaFileStorage.)
57
57
 
58
58
  Parameters
59
59
  ----------
@@ -61,7 +61,7 @@ class MediaFileStorage(Protocol):
61
61
  A path to a file, or the file's raw data as bytes.
62
62
 
63
63
  mimetype
64
- The medias mimetype. Used to set the Content-Type header when
64
+ The media's mimetype. Used to set the Content-Type header when
65
65
  serving the media over HTTP.
66
66
 
67
67
  kind
@@ -14,13 +14,13 @@
14
14
 
15
15
  """MediaFileStorage implementation that stores files in memory."""
16
16
 
17
+ from __future__ import annotations
18
+
17
19
  import contextlib
18
20
  import hashlib
19
21
  import mimetypes
20
22
  import os.path
21
- from typing import Dict, List, NamedTuple, Optional, Union
22
-
23
- from typing_extensions import Final
23
+ from typing import Final, NamedTuple
24
24
 
25
25
  from streamlit.logger import get_logger
26
26
  from streamlit.runtime.media_file_storage import (
@@ -31,7 +31,7 @@ from streamlit.runtime.media_file_storage import (
31
31
  from streamlit.runtime.stats import CacheStat, CacheStatsProvider, group_stats
32
32
  from streamlit.util import HASHLIB_KWARGS
33
33
 
34
- LOGGER = get_logger(__name__)
34
+ _LOGGER: Final = get_logger(__name__)
35
35
 
36
36
  # Mimetype -> filename extension map for the `get_extension_for_mimetype`
37
37
  # function. We use Python's `mimetypes.guess_extension` for most mimetypes,
@@ -42,9 +42,7 @@ PREFERRED_MIMETYPE_EXTENSION_MAP: Final = {
42
42
  }
43
43
 
44
44
 
45
- def _calculate_file_id(
46
- data: bytes, mimetype: str, filename: Optional[str] = None
47
- ) -> str:
45
+ def _calculate_file_id(data: bytes, mimetype: str, filename: str | None = None) -> str:
48
46
  """Hash data, mimetype, and an optional filename to generate a stable file ID.
49
47
 
50
48
  Parameters
@@ -83,7 +81,7 @@ class MemoryFile(NamedTuple):
83
81
  content: bytes
84
82
  mimetype: str
85
83
  kind: MediaFileKind
86
- filename: Optional[str]
84
+ filename: str | None
87
85
 
88
86
  @property
89
87
  def content_size(self) -> int:
@@ -100,15 +98,15 @@ class MemoryMediaFileStorage(MediaFileStorage, CacheStatsProvider):
100
98
  The name of the local endpoint that media is served from.
101
99
  This endpoint should start with a forward-slash (e.g. "/media").
102
100
  """
103
- self._files_by_id: Dict[str, MemoryFile] = {}
101
+ self._files_by_id: dict[str, MemoryFile] = {}
104
102
  self._media_endpoint = media_endpoint
105
103
 
106
104
  def load_and_get_id(
107
105
  self,
108
- path_or_data: Union[str, bytes],
106
+ path_or_data: str | bytes,
109
107
  mimetype: str,
110
108
  kind: MediaFileKind,
111
- filename: Optional[str] = None,
109
+ filename: str | None = None,
112
110
  ) -> str:
113
111
  """Add a file to the manager and return its ID."""
114
112
  file_data: bytes
@@ -121,7 +119,7 @@ class MemoryMediaFileStorage(MediaFileStorage, CacheStatsProvider):
121
119
  # given ID, we don't need to create a new one.
122
120
  file_id = _calculate_file_id(file_data, mimetype, filename)
123
121
  if file_id not in self._files_by_id:
124
- LOGGER.debug("Adding media file %s", file_id)
122
+ _LOGGER.debug("Adding media file %s", file_id)
125
123
  media_file = MemoryFile(
126
124
  content=file_data, mimetype=mimetype, kind=kind, filename=filename
127
125
  )
@@ -167,12 +165,12 @@ class MemoryMediaFileStorage(MediaFileStorage, CacheStatsProvider):
167
165
  except Exception as ex:
168
166
  raise MediaFileStorageError(f"Error opening '{filename}'") from ex
169
167
 
170
- def get_stats(self) -> List[CacheStat]:
168
+ def get_stats(self) -> list[CacheStat]:
171
169
  # We operate on a copy of our dict, to avoid race conditions
172
170
  # with other threads that may be manipulating the cache.
173
171
  files_by_id = self._files_by_id.copy()
174
172
 
175
- stats: List[CacheStat] = []
173
+ stats: list[CacheStat] = []
176
174
  for file_id, file in files_by_id.items():
177
175
  stats.append(
178
176
  CacheStat(
@@ -12,8 +12,9 @@
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
15
16
 
16
- from typing import List, MutableMapping, Optional
17
+ from typing import MutableMapping
17
18
 
18
19
  from streamlit.runtime.session_manager import SessionInfo, SessionStorage
19
20
  from streamlit.util import TimedCleanupCache
@@ -59,7 +60,7 @@ class MemorySessionStorage(SessionStorage):
59
60
  maxsize=maxsize, ttl=ttl_seconds
60
61
  )
61
62
 
62
- def get(self, session_id: str) -> Optional[SessionInfo]:
63
+ def get(self, session_id: str) -> SessionInfo | None:
63
64
  return self._cache.get(session_id, None)
64
65
 
65
66
  def save(self, session_info: SessionInfo) -> None:
@@ -68,5 +69,5 @@ class MemorySessionStorage(SessionStorage):
68
69
  def delete(self, session_id: str) -> None:
69
70
  del self._cache[session_id]
70
71
 
71
- def list(self) -> List[SessionInfo]:
72
+ def list(self) -> list[SessionInfo]:
72
73
  return list(self._cache.values())
@@ -12,12 +12,13 @@
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 uuid
16
18
  from collections import defaultdict
17
- from typing import Dict, List, Sequence
19
+ from typing import Sequence
18
20
 
19
21
  from streamlit import util
20
- from streamlit.logger import get_logger
21
22
  from streamlit.runtime.stats import CacheStat, group_stats
22
23
  from streamlit.runtime.uploaded_file_manager import (
23
24
  UploadedFileManager,
@@ -25,8 +26,6 @@ from streamlit.runtime.uploaded_file_manager import (
25
26
  UploadFileUrlInfo,
26
27
  )
27
28
 
28
- LOGGER = get_logger(__name__)
29
-
30
29
 
31
30
  class MemoryUploadedFileManager(UploadedFileManager):
32
31
  """Holds files uploaded by users of the running Streamlit app.
@@ -34,12 +33,12 @@ class MemoryUploadedFileManager(UploadedFileManager):
34
33
  """
35
34
 
36
35
  def __init__(self, upload_endpoint: str):
37
- self.file_storage: Dict[str, Dict[str, UploadedFileRec]] = defaultdict(dict)
36
+ self.file_storage: dict[str, dict[str, UploadedFileRec]] = defaultdict(dict)
38
37
  self.endpoint = upload_endpoint
39
38
 
40
39
  def get_files(
41
40
  self, session_id: str, file_ids: Sequence[str]
42
- ) -> List[UploadedFileRec]:
41
+ ) -> list[UploadedFileRec]:
43
42
  """Return a list of UploadedFileRec for a given sequence of file_ids.
44
43
 
45
44
  Parameters
@@ -97,7 +96,7 @@ class MemoryUploadedFileManager(UploadedFileManager):
97
96
 
98
97
  def get_upload_urls(
99
98
  self, session_id: str, file_names: Sequence[str]
100
- ) -> List[UploadFileUrlInfo]:
99
+ ) -> list[UploadFileUrlInfo]:
101
100
  """Return a list of UploadFileUrlInfo for a given sequence of file_names."""
102
101
  result = []
103
102
  for _ in file_names:
@@ -111,13 +110,13 @@ class MemoryUploadedFileManager(UploadedFileManager):
111
110
  )
112
111
  return result
113
112
 
114
- def get_stats(self) -> List[CacheStat]:
113
+ def get_stats(self) -> list[CacheStat]:
115
114
  """Return the manager's CacheStats.
116
115
 
117
116
  Safe to call from any thread.
118
117
  """
119
118
  # Flatten all files into a single list
120
- all_files: List[UploadedFileRec] = []
119
+ all_files: list[UploadedFileRec] = []
121
120
  # Make copy of self.file_storage for thread safety, to be sure
122
121
  # that main storage won't be changed form other thread
123
122
  file_storage_copy = self.file_storage.copy()
@@ -125,7 +124,7 @@ class MemoryUploadedFileManager(UploadedFileManager):
125
124
  for session_storage in file_storage_copy.values():
126
125
  all_files.extend(session_storage.values())
127
126
 
128
- stats: List[CacheStat] = [
127
+ stats: list[CacheStat] = [
129
128
  CacheStat(
130
129
  category_name="UploadedFileManager",
131
130
  cache_name="",
@@ -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 contextlib
16
18
  import inspect
17
19
  import os
@@ -21,17 +23,14 @@ import time
21
23
  import uuid
22
24
  from collections.abc import Sized
23
25
  from functools import wraps
24
- from timeit import default_timer as timer
25
- from typing import Any, Callable, List, Optional, Set, TypeVar, Union, cast, overload
26
-
27
- from typing_extensions import Final
26
+ from typing import Any, Callable, Final, TypeVar, cast, overload
28
27
 
29
28
  from streamlit import config, util
30
29
  from streamlit.logger import get_logger
31
30
  from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
32
31
  from streamlit.proto.PageProfile_pb2 import Argument, Command
33
32
 
34
- _LOGGER = get_logger(__name__)
33
+ _LOGGER: Final = get_logger(__name__)
35
34
 
36
35
  # Limit the number of commands to keep the page profile message small
37
36
  # since Segment allows only a maximum of 32kb per event.
@@ -161,11 +160,11 @@ def _get_machine_id_v3() -> str:
161
160
 
162
161
  machine_id = str(uuid.getnode())
163
162
  if os.path.isfile(_ETC_MACHINE_ID_PATH):
164
- with open(_ETC_MACHINE_ID_PATH, "r") as f:
163
+ with open(_ETC_MACHINE_ID_PATH) as f:
165
164
  machine_id = f.read()
166
165
 
167
166
  elif os.path.isfile(_DBUS_MACHINE_ID_PATH):
168
- with open(_DBUS_MACHINE_ID_PATH, "r") as f:
167
+ with open(_DBUS_MACHINE_ID_PATH) as f:
169
168
  machine_id = f.read()
170
169
 
171
170
  return machine_id
@@ -173,10 +172,10 @@ def _get_machine_id_v3() -> str:
173
172
 
174
173
  class Installation:
175
174
  _instance_lock = threading.Lock()
176
- _instance: Optional["Installation"] = None
175
+ _instance: Installation | None = None
177
176
 
178
177
  @classmethod
179
- def instance(cls) -> "Installation":
178
+ def instance(cls) -> Installation:
180
179
  """Returns the singleton Installation"""
181
180
  # We use a double-checked locking optimization to avoid the overhead
182
181
  # of acquiring the lock in the common case:
@@ -228,7 +227,7 @@ def _get_top_level_module(func: Callable[..., Any]) -> str:
228
227
  return module.__name__.split(".")[0]
229
228
 
230
229
 
231
- def _get_arg_metadata(arg: object) -> Optional[str]:
230
+ def _get_arg_metadata(arg: object) -> str | None:
232
231
  """Get metadata information related to the value of the given object."""
233
232
  with contextlib.suppress(Exception):
234
233
  if isinstance(arg, (bool)):
@@ -245,8 +244,8 @@ def _get_command_telemetry(
245
244
  ) -> Command:
246
245
  """Get telemetry information for the given callable and its arguments."""
247
246
  arg_keywords = inspect.getfullargspec(_command_func).args
248
- self_arg: Optional[Any] = None
249
- arguments: List[Argument] = []
247
+ self_arg: Any | None = None
248
+ arguments: list[Argument] = []
250
249
  is_method = inspect.ismethod(_command_func)
251
250
  name = _command_name
252
251
 
@@ -315,7 +314,7 @@ def gather_metrics(
315
314
  ...
316
315
 
317
316
 
318
- def gather_metrics(name: str, func: Optional[F] = None) -> Union[Callable[[F], F], F]:
317
+ def gather_metrics(name: str, func: F | None = None) -> Callable[[F], F] | F:
319
318
  """Function decorator to add telemetry tracking to commands.
320
319
 
321
320
  Parameters
@@ -351,11 +350,13 @@ def gather_metrics(name: str, func: Optional[F] = None) -> Union[Callable[[F], F
351
350
 
352
351
  return wrapper
353
352
  else:
354
- # To make mypy type narrow Optional[F] -> F
353
+ # To make mypy type narrow F | None -> F
355
354
  non_optional_func = func
356
355
 
357
356
  @wraps(non_optional_func)
358
357
  def wrapped_func(*args, **kwargs):
358
+ from timeit import default_timer as timer
359
+
359
360
  exec_start = timer()
360
361
  # Local imports to prevent circular dependencies
361
362
  from streamlit.runtime.scriptrunner import get_script_run_ctx
@@ -371,8 +372,7 @@ def gather_metrics(name: str, func: Optional[F] = None) -> Union[Callable[[F], F
371
372
  < _MAX_TRACKED_COMMANDS # Prevent too much memory usage
372
373
  )
373
374
 
374
- deferred_exception: Optional[RerunException] = None
375
- command_telemetry: Optional[Command] = None
375
+ command_telemetry: Command | None = None
376
376
 
377
377
  if ctx and tracking_activated:
378
378
  try:
@@ -421,10 +421,10 @@ def gather_metrics(name: str, func: Optional[F] = None) -> Union[Callable[[F], F
421
421
 
422
422
 
423
423
  def create_page_profile_message(
424
- commands: List[Command],
424
+ commands: list[Command],
425
425
  exec_time: int,
426
426
  prep_time: int,
427
- uncaught_exception: Optional[str] = None,
427
+ uncaught_exception: str | None = None,
428
428
  ) -> ForwardMsg:
429
429
  """Create and return the full PageProfile ForwardMsg."""
430
430
  msg = ForwardMsg()
@@ -435,7 +435,7 @@ def create_page_profile_message(
435
435
  msg.page_profile.headless = config.get_option("server.headless")
436
436
 
437
437
  # Collect all config options that have been manually set
438
- config_options: Set[str] = set()
438
+ config_options: set[str] = set()
439
439
  if config._config_options:
440
440
  for option_name in config._config_options.keys():
441
441
  if not config.is_manually_set(option_name):
@@ -450,7 +450,7 @@ def create_page_profile_message(
450
450
  msg.page_profile.config.extend(config_options)
451
451
 
452
452
  # Check the predefined set of modules for attribution
453
- attributions: Set[str] = {
453
+ attributions: set[str] = {
454
454
  attribution
455
455
  for attribution in _ATTRIBUTIONS_TO_CHECK
456
456
  if attribution in sys.modules
@@ -19,9 +19,7 @@ import time
19
19
  import traceback
20
20
  from dataclasses import dataclass, field
21
21
  from enum import Enum
22
- from typing import TYPE_CHECKING, Awaitable, Dict, NamedTuple, Optional, Tuple, Type
23
-
24
- from typing_extensions import Final
22
+ from typing import TYPE_CHECKING, Awaitable, Final, NamedTuple
25
23
 
26
24
  from streamlit import config
27
25
  from streamlit.logger import get_logger
@@ -69,7 +67,7 @@ if TYPE_CHECKING:
69
67
  # Wait for the script run result for 60s and if no result is available give up
70
68
  SCRIPT_RUN_CHECK_TIMEOUT: Final = 60
71
69
 
72
- LOGGER: Final = get_logger(__name__)
70
+ _LOGGER: Final = get_logger(__name__)
73
71
 
74
72
 
75
73
  class RuntimeStoppedError(Exception):
@@ -85,7 +83,7 @@ class RuntimeConfig:
85
83
 
86
84
  # DEPRECATED: We need to keep this field around for compatibility reasons, but we no
87
85
  # longer use this anywhere.
88
- command_line: Optional[str]
86
+ command_line: str | None
89
87
 
90
88
  # The storage backend for Streamlit's MediaFileManager.
91
89
  media_file_storage: MediaFileStorage
@@ -99,7 +97,7 @@ class RuntimeConfig:
99
97
  )
100
98
 
101
99
  # The SessionManager class to be used.
102
- session_manager_class: Type[SessionManager] = WebsocketSessionManager
100
+ session_manager_class: type[SessionManager] = WebsocketSessionManager
103
101
 
104
102
  # The SessionStorage instance for the SessionManager to use.
105
103
  session_storage: SessionStorage = field(default_factory=MemorySessionStorage)
@@ -141,7 +139,7 @@ class AsyncObjects(NamedTuple):
141
139
 
142
140
 
143
141
  class Runtime:
144
- _instance: Optional[Runtime] = None
142
+ _instance: Runtime | None = None
145
143
 
146
144
  @classmethod
147
145
  def instance(cls) -> Runtime:
@@ -179,11 +177,11 @@ class Runtime:
179
177
  Runtime._instance = self
180
178
 
181
179
  # Will be created when we start.
182
- self._async_objs: Optional[AsyncObjects] = None
180
+ self._async_objs: AsyncObjects | None = None
183
181
 
184
182
  # The task that runs our main loop. We need to save a reference
185
183
  # to it so that it doesn't get garbage collected while running.
186
- self._loop_coroutine_task: Optional[asyncio.Task[None]] = None
184
+ self._loop_coroutine_task: asyncio.Task[None] | None = None
187
185
 
188
186
  self._main_script_path = config.script_path
189
187
  self._is_hello = config.is_hello
@@ -247,7 +245,7 @@ class Runtime:
247
245
  # happen to be threadsafe. This may change with future SessionManager implementations,
248
246
  # at which point we'll need to formalize our thread safety rules for each
249
247
  # SessionManager method.
250
- def get_client(self, session_id: str) -> Optional[SessionClient]:
248
+ def get_client(self, session_id: str) -> SessionClient | None:
251
249
  """Get the SessionClient for the given session_id, or None
252
250
  if no such session exists.
253
251
 
@@ -304,7 +302,7 @@ class Runtime:
304
302
  if self._state in (RuntimeState.STOPPING, RuntimeState.STOPPED):
305
303
  return
306
304
 
307
- LOGGER.debug("Runtime stopping...")
305
+ _LOGGER.debug("Runtime stopping...")
308
306
  self._set_state(RuntimeState.STOPPING)
309
307
  async_objs.must_stop.set()
310
308
 
@@ -322,9 +320,9 @@ class Runtime:
322
320
  def connect_session(
323
321
  self,
324
322
  client: SessionClient,
325
- user_info: Dict[str, Optional[str]],
326
- existing_session_id: Optional[str] = None,
327
- session_id_override: Optional[str] = None,
323
+ user_info: dict[str, str | None],
324
+ existing_session_id: str | None = None,
325
+ session_id_override: str | None = None,
328
326
  ) -> str:
329
327
  """Create a new session (or connect to an existing one) and return its unique ID.
330
328
 
@@ -383,9 +381,9 @@ class Runtime:
383
381
  def create_session(
384
382
  self,
385
383
  client: SessionClient,
386
- user_info: Dict[str, Optional[str]],
387
- existing_session_id: Optional[str] = None,
388
- session_id_override: Optional[str] = None,
384
+ user_info: dict[str, str | None],
385
+ existing_session_id: str | None = None,
386
+ session_id_override: str | None = None,
389
387
  ) -> str:
390
388
  """Create a new session (or connect to an existing one) and return its unique ID.
391
389
 
@@ -394,7 +392,7 @@ class Runtime:
394
392
  This method is simply an alias for connect_session added for backwards
395
393
  compatibility.
396
394
  """
397
- LOGGER.warning("create_session is deprecated! Use connect_session instead.")
395
+ _LOGGER.warning("create_session is deprecated! Use connect_session instead.")
398
396
  return self.connect_session(
399
397
  client=client,
400
398
  user_info=user_info,
@@ -478,7 +476,7 @@ class Runtime:
478
476
 
479
477
  session_info = self._session_mgr.get_active_session_info(session_id)
480
478
  if session_info is None:
481
- LOGGER.debug(
479
+ _LOGGER.debug(
482
480
  "Discarding BackMsg for disconnected session (id=%s)", session_id
483
481
  )
484
482
  return
@@ -508,7 +506,7 @@ class Runtime:
508
506
 
509
507
  session_info = self._session_mgr.get_active_session_info(session_id)
510
508
  if session_info is None:
511
- LOGGER.debug(
509
+ _LOGGER.debug(
512
510
  "Discarding BackMsg Exception for disconnected session (id=%s)",
513
511
  session_id,
514
512
  )
@@ -517,7 +515,7 @@ class Runtime:
517
515
  session_info.session.handle_backmsg_exception(exc)
518
516
 
519
517
  @property
520
- async def is_ready_for_browser_connection(self) -> Tuple[bool, str]:
518
+ async def is_ready_for_browser_connection(self) -> tuple[bool, str]:
521
519
  if self._state not in (
522
520
  RuntimeState.INITIAL,
523
521
  RuntimeState.STOPPING,
@@ -527,7 +525,7 @@ class Runtime:
527
525
 
528
526
  return False, "unavailable"
529
527
 
530
- async def does_script_run_without_error(self) -> Tuple[bool, str]:
528
+ async def does_script_run_without_error(self) -> tuple[bool, str]:
531
529
  """Load and execute the app's script to verify it runs without an error.
532
530
 
533
531
  Returns
@@ -572,7 +570,7 @@ class Runtime:
572
570
  session.shutdown()
573
571
 
574
572
  def _set_state(self, new_state: RuntimeState) -> None:
575
- LOGGER.debug("Runtime state: %s -> %s", self._state, new_state)
573
+ _LOGGER.debug("Runtime state: %s -> %s", self._state, new_state)
576
574
  self._state = new_state
577
575
 
578
576
  async def _loop_coroutine(self) -> None:
@@ -655,7 +653,7 @@ class Runtime:
655
653
  except Exception as e:
656
654
  async_objs.stopped.set_exception(e)
657
655
  traceback.print_exc()
658
- LOGGER.info(
656
+ _LOGGER.info(
659
657
  """
660
658
  Please report this bug at https://github.com/streamlit/streamlit/issues.
661
659
  """
@@ -689,13 +687,13 @@ Please report this bug at https://github.com/streamlit/streamlit/issues.
689
687
  ):
690
688
  # This session has probably cached this message. Send
691
689
  # a reference instead.
692
- LOGGER.debug("Sending cached message ref (hash=%s)", msg.hash)
690
+ _LOGGER.debug("Sending cached message ref (hash=%s)", msg.hash)
693
691
  msg_to_send = create_reference_msg(msg)
694
692
 
695
693
  # Cache the message so it can be referenced in the future.
696
694
  # If the message is already cached, this will reset its
697
695
  # age.
698
- LOGGER.debug("Caching message (hash=%s)", msg.hash)
696
+ _LOGGER.debug("Caching message (hash=%s)", msg.hash)
699
697
  self._message_cache.add_message(
700
698
  msg, session_info.session, session_info.script_run_count
701
699
  )
@@ -706,7 +704,7 @@ Please report this bug at https://github.com/streamlit/streamlit/issues.
706
704
  msg.WhichOneof("type") == "script_finished"
707
705
  and msg.script_finished == ForwardMsg.FINISHED_SUCCESSFULLY
708
706
  ):
709
- LOGGER.debug(
707
+ _LOGGER.debug(
710
708
  "Script run finished successfully; "
711
709
  "removing expired entries from MessageCache "
712
710
  "(max_age=%s)",