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
@@ -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)",
@@ -14,7 +14,9 @@
14
14
 
15
15
  """Runtime-related utility functions"""
16
16
 
17
- from typing import Any, Optional
17
+ from __future__ import annotations
18
+
19
+ from typing import Any
18
20
 
19
21
  from streamlit import config
20
22
  from streamlit.errors import MarkdownFormattedException
@@ -27,7 +29,7 @@ class MessageSizeError(MarkdownFormattedException):
27
29
 
28
30
  def __init__(self, failed_msg_str: Any):
29
31
  msg = self._get_message(failed_msg_str)
30
- super(MessageSizeError, self).__init__(msg)
32
+ super().__init__(msg)
31
33
 
32
34
  def _get_message(self, failed_msg_str: Any) -> str:
33
35
  # This needs to have zero indentation otherwise the markdown will render incorrectly.
@@ -82,7 +84,7 @@ def serialize_forward_msg(msg: ForwardMsg) -> bytes:
82
84
 
83
85
  # This needs to be initialized lazily to avoid calling config.get_option() and
84
86
  # thus initializing config options when this file is first imported.
85
- _max_message_size_bytes: Optional[int] = None
87
+ _max_message_size_bytes: int | None = None
86
88
 
87
89
 
88
90
  def get_max_message_size_bytes() -> int:
@@ -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 os
16
18
  from dataclasses import dataclass, field
17
19
 
@@ -12,9 +12,10 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import ast
15
+ from __future__ import annotations
16
16
 
17
- from typing_extensions import Final
17
+ import ast
18
+ from typing import Any, Final
18
19
 
19
20
  from streamlit import config
20
21
 
@@ -24,7 +25,7 @@ from streamlit import config
24
25
  MAGIC_MODULE_NAME: Final = "__streamlitmagic__"
25
26
 
26
27
 
27
- def add_magic(code, script_path):
28
+ def add_magic(code: str, script_path: str) -> Any:
28
29
  """Modifies the code to support magic Streamlit commands.
29
30
 
30
31
  Parameters
@@ -51,7 +52,10 @@ def add_magic(code, script_path):
51
52
 
52
53
 
53
54
  def _modify_ast_subtree(
54
- tree, body_attr="body", is_root=False, file_ends_in_semicolon=False
55
+ tree: Any,
56
+ body_attr: str = "body",
57
+ is_root: bool = False,
58
+ file_ends_in_semicolon: bool = False,
55
59
  ):
56
60
  """Parses magic commands and modifies the given AST (sub)tree."""
57
61
 
@@ -118,7 +122,7 @@ def _modify_ast_subtree(
118
122
  return tree
119
123
 
120
124
 
121
- def _insert_import_statement(tree):
125
+ def _insert_import_statement(tree: Any) -> None:
122
126
  """Insert Streamlit import statement at the top(ish) of the tree."""
123
127
 
124
128
  st_import = _build_st_import_statement()
@@ -226,11 +230,11 @@ def _get_st_write_from_expr(
226
230
  return st_write
227
231
 
228
232
 
229
- def _is_string_constant_node(node):
233
+ def _is_string_constant_node(node) -> bool:
230
234
  return type(node) is ast.Constant and type(node.value) is str
231
235
 
232
236
 
233
- def _is_docstring_node(node, node_index, parent_type):
237
+ def _is_docstring_node(node, node_index, parent_type) -> bool:
234
238
  return (
235
239
  node_index == 0
236
240
  and _is_string_constant_node(node)
@@ -238,7 +242,7 @@ def _is_docstring_node(node, node_index, parent_type):
238
242
  )
239
243
 
240
244
 
241
- def _does_file_end_in_semicolon(tree, code):
245
+ def _does_file_end_in_semicolon(tree, code: str) -> bool:
242
246
  file_ends_in_semicolon = False
243
247
 
244
248
  # Avoid spending time with this operation if magic.displayLastExprIfNoSemicolon is
@@ -247,13 +251,15 @@ def _does_file_end_in_semicolon(tree, code):
247
251
  last_line_num = getattr(tree.body[-1], "end_lineno", None)
248
252
 
249
253
  if last_line_num is not None:
250
- last_line_str = code.split("\n")[last_line_num - 1]
254
+ last_line_str: str = code.split("\n")[last_line_num - 1]
251
255
  file_ends_in_semicolon = last_line_str.strip(" ").endswith(";")
252
256
 
253
257
  return file_ends_in_semicolon
254
258
 
255
259
 
256
- def _is_displayable_last_expr(is_root, is_last_expr, file_ends_in_semicolon):
260
+ def _is_displayable_last_expr(
261
+ is_root: bool, is_last_expr: bool, file_ends_in_semicolon: bool
262
+ ) -> bool:
257
263
  return (
258
264
  # This is a "displayable last expression" if...
259
265
  # ...it's actually the last expression...
@@ -267,5 +273,5 @@ def _is_displayable_last_expr(is_root, is_last_expr, file_ends_in_semicolon):
267
273
  )
268
274
 
269
275
 
270
- def _should_display_docstring_like_node_anyway(is_root):
276
+ def _should_display_docstring_like_node_anyway(is_root: bool) -> bool:
271
277
  return config.get_option("magic.displayRootDocString") and is_root
@@ -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
  from typing import Any
16
18
 
17
19
  from streamlit.runtime.metrics_util import gather_metrics
@@ -12,10 +12,12 @@
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 threading
16
18
  from dataclasses import dataclass
17
19
  from enum import Enum
18
- from typing import Optional, cast
20
+ from typing import cast
19
21
 
20
22
  from streamlit import util
21
23
  from streamlit.proto.WidgetStates_pb2 import WidgetStates
@@ -41,7 +43,7 @@ class RerunData:
41
43
  """Data attached to RERUN requests. Immutable."""
42
44
 
43
45
  query_string: str = ""
44
- widget_states: Optional[WidgetStates] = None
46
+ widget_states: WidgetStates | None = None
45
47
  page_script_hash: str = ""
46
48
  page_name: str = ""
47
49
 
@@ -54,7 +56,7 @@ class ScriptRequest:
54
56
  """A STOP or RERUN request and associated data."""
55
57
 
56
58
  type: ScriptRequestType
57
- _rerun_data: Optional[RerunData] = None
59
+ _rerun_data: RerunData | None = None
58
60
 
59
61
  @property
60
62
  def rerun_data(self) -> RerunData:
@@ -141,7 +143,7 @@ class ScriptRequests:
141
143
  # We'll never get here
142
144
  raise RuntimeError(f"Unrecognized ScriptRunnerState: {self._state}")
143
145
 
144
- def on_scriptrunner_yield(self) -> Optional[ScriptRequest]:
146
+ def on_scriptrunner_yield(self) -> ScriptRequest | None:
145
147
  """Called by the ScriptRunner when it's at a yield point.
146
148
 
147
149
  If we have no request, return None.
@@ -12,14 +12,16 @@
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 collections
16
18
  import contextvars
17
19
  import threading
18
20
  from dataclasses import dataclass, field
19
- from typing import Callable, Counter, Dict, List, Optional, Set, Tuple
21
+ from typing import Callable, Counter, Dict, Final, Union
20
22
  from urllib import parse
21
23
 
22
- from typing_extensions import Final, TypeAlias
24
+ from typing_extensions import TypeAlias
23
25
 
24
26
  from streamlit import runtime
25
27
  from streamlit.errors import StreamlitAPIException
@@ -30,16 +32,16 @@ from streamlit.runtime.scriptrunner.script_requests import ScriptRequests
30
32
  from streamlit.runtime.state import SafeSessionState
31
33
  from streamlit.runtime.uploaded_file_manager import UploadedFileManager
32
34
 
33
- LOGGER: Final = get_logger(__name__)
35
+ _LOGGER: Final = get_logger(__name__)
34
36
 
35
- UserInfo: TypeAlias = Dict[str, Optional[str]]
37
+ UserInfo: TypeAlias = Dict[str, Union[str, None]]
36
38
 
37
39
 
38
40
  # The dg_stack tracks the currently active DeltaGenerator, and is pushed to when
39
41
  # a DeltaGenerator is entered via a `with` block. This is implemented as a ContextVar
40
42
  # so that different threads or async tasks can have their own stacks.
41
43
  dg_stack: contextvars.ContextVar[
42
- Tuple["streamlit.delta_generator.DeltaGenerator", ...]
44
+ tuple["streamlit.delta_generator.DeltaGenerator", ...]
43
45
  ] = contextvars.ContextVar("dg_stack", default=tuple())
44
46
 
45
47
 
@@ -69,15 +71,15 @@ class ScriptRunContext:
69
71
 
70
72
  gather_usage_stats: bool = False
71
73
  command_tracking_deactivated: bool = False
72
- tracked_commands: List[Command] = field(default_factory=list)
74
+ tracked_commands: list[Command] = field(default_factory=list)
73
75
  tracked_commands_counter: Counter[str] = field(default_factory=collections.Counter)
74
76
  _set_page_config_allowed: bool = True
75
77
  _has_script_started: bool = False
76
- widget_ids_this_run: Set[str] = field(default_factory=set)
77
- widget_user_keys_this_run: Set[str] = field(default_factory=set)
78
- form_ids_this_run: Set[str] = field(default_factory=set)
79
- cursors: Dict[int, "streamlit.cursor.RunningCursor"] = field(default_factory=dict)
80
- script_requests: Optional[ScriptRequests] = None
78
+ widget_ids_this_run: set[str] = field(default_factory=set)
79
+ widget_user_keys_this_run: set[str] = field(default_factory=set)
80
+ form_ids_this_run: set[str] = field(default_factory=set)
81
+ cursors: dict[int, "streamlit.cursor.RunningCursor"] = field(default_factory=dict)
82
+ script_requests: ScriptRequests | None = None
81
83
 
82
84
  # TODO(willhuang1997): Remove this variable when experimental query params are removed
83
85
  _experimental_query_params_used = False
@@ -153,7 +155,7 @@ SCRIPT_RUN_CONTEXT_ATTR_NAME: Final = "streamlit_script_run_ctx"
153
155
 
154
156
 
155
157
  def add_script_run_ctx(
156
- thread: Optional[threading.Thread] = None, ctx: Optional[ScriptRunContext] = None
158
+ thread: threading.Thread | None = None, ctx: ScriptRunContext | None = None
157
159
  ):
158
160
  """Adds the current ScriptRunContext to a newly-created thread.
159
161
 
@@ -183,7 +185,7 @@ def add_script_run_ctx(
183
185
  return thread
184
186
 
185
187
 
186
- def get_script_run_ctx(suppress_warning: bool = False) -> Optional[ScriptRunContext]:
188
+ def get_script_run_ctx(suppress_warning: bool = False) -> ScriptRunContext | None:
187
189
  """
188
190
  Parameters
189
191
  ----------
@@ -196,15 +198,13 @@ def get_script_run_ctx(suppress_warning: bool = False) -> Optional[ScriptRunCont
196
198
 
197
199
  """
198
200
  thread = threading.current_thread()
199
- ctx: Optional[ScriptRunContext] = getattr(
200
- thread, SCRIPT_RUN_CONTEXT_ATTR_NAME, None
201
- )
201
+ ctx: ScriptRunContext | None = getattr(thread, SCRIPT_RUN_CONTEXT_ATTR_NAME, None)
202
202
  if ctx is None and runtime.exists() and not suppress_warning:
203
203
  # Only warn about a missing ScriptRunContext if suppress_warning is False, and
204
204
  # we were started via `streamlit run`. Otherwise, the user is likely running a
205
205
  # script "bare", and doesn't need to be warned about streamlit
206
206
  # bits that are irrelevant when not connected to a session.
207
- LOGGER.warning("Thread '%s': missing ScriptRunContext", thread.name)
207
+ _LOGGER.warning("Thread '%s': missing ScriptRunContext", thread.name)
208
208
 
209
209
  return ctx
210
210
 
@@ -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 gc
16
18
  import sys
17
19
  import threading
@@ -19,7 +21,7 @@ import types
19
21
  from contextlib import contextmanager
20
22
  from enum import Enum
21
23
  from timeit import default_timer as timer
22
- from typing import Callable, Dict, Optional
24
+ from typing import Callable, Final
23
25
 
24
26
  from blinker import Signal
25
27
 
@@ -47,7 +49,7 @@ from streamlit.runtime.state import (
47
49
  from streamlit.runtime.uploaded_file_manager import UploadedFileManager
48
50
  from streamlit.vendor.ipython.modified_sys_path import modified_sys_path
49
51
 
50
- _LOGGER = get_logger(__name__)
52
+ _LOGGER: Final = get_logger(__name__)
51
53
 
52
54
 
53
55
  class ScriptRunnerEvent(Enum):
@@ -103,7 +105,7 @@ class ScriptRunner:
103
105
  uploaded_file_mgr: UploadedFileManager,
104
106
  script_cache: ScriptCache,
105
107
  initial_rerun_data: RerunData,
106
- user_info: Dict[str, Optional[str]],
108
+ user_info: dict[str, str | None],
107
109
  ):
108
110
  """Initialize the ScriptRunner.
109
111
 
@@ -181,7 +183,7 @@ class ScriptRunner:
181
183
  self._execing = False
182
184
 
183
185
  # This is initialized in start()
184
- self._script_thread: Optional[threading.Thread] = None
186
+ self._script_thread: threading.Thread | None = None
185
187
 
186
188
  def __repr__(self) -> str:
187
189
  return util.repr_(self)
@@ -493,7 +495,7 @@ class ScriptRunner:
493
495
 
494
496
  # This will be set to a RerunData instance if our execution
495
497
  # is interrupted by a RerunException.
496
- rerun_exception_data: Optional[RerunData] = None
498
+ rerun_exception_data: RerunData | None = None
497
499
 
498
500
  # If the script stops early, we don't want to remove unseen widgets,
499
501
  # so we track this to potentially skip session state cleanup later.