streamlit 1.49.1__py3-none-any.whl → 1.51.0__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 (259) hide show
  1. streamlit/__init__.py +4 -1
  2. streamlit/column_config.py +2 -0
  3. streamlit/commands/navigation.py +7 -7
  4. streamlit/commands/page_config.py +4 -6
  5. streamlit/components/v1/custom_component.py +17 -42
  6. streamlit/components/v2/__init__.py +458 -0
  7. streamlit/components/v2/bidi_component/__init__.py +20 -0
  8. streamlit/components/v2/bidi_component/constants.py +29 -0
  9. streamlit/components/v2/bidi_component/main.py +386 -0
  10. streamlit/components/v2/bidi_component/serialization.py +265 -0
  11. streamlit/components/v2/bidi_component/state.py +92 -0
  12. streamlit/components/v2/component_definition_resolver.py +143 -0
  13. streamlit/components/v2/component_file_watcher.py +403 -0
  14. streamlit/components/v2/component_manager.py +431 -0
  15. streamlit/components/v2/component_manifest_handler.py +122 -0
  16. streamlit/components/v2/component_path_utils.py +245 -0
  17. streamlit/components/v2/component_registry.py +409 -0
  18. streamlit/components/v2/get_bidi_component_manager.py +51 -0
  19. streamlit/components/v2/manifest_scanner.py +615 -0
  20. streamlit/components/v2/presentation.py +198 -0
  21. streamlit/components/v2/types.py +324 -0
  22. streamlit/config.py +741 -32
  23. streamlit/config_option.py +4 -1
  24. streamlit/config_util.py +650 -1
  25. streamlit/connections/base_connection.py +4 -2
  26. streamlit/dataframe_util.py +18 -10
  27. streamlit/delta_generator.py +8 -7
  28. streamlit/delta_generator_singletons.py +3 -1
  29. streamlit/deprecation_util.py +17 -6
  30. streamlit/elements/arrow.py +90 -42
  31. streamlit/elements/deck_gl_json_chart.py +98 -39
  32. streamlit/elements/dialog_decorator.py +2 -1
  33. streamlit/elements/exception.py +3 -1
  34. streamlit/elements/form.py +6 -6
  35. streamlit/elements/graphviz_chart.py +24 -9
  36. streamlit/elements/heading.py +3 -5
  37. streamlit/elements/iframe.py +0 -2
  38. streamlit/elements/image.py +12 -13
  39. streamlit/elements/layouts.py +89 -22
  40. streamlit/elements/lib/built_in_chart_utils.py +95 -31
  41. streamlit/elements/lib/color_util.py +8 -18
  42. streamlit/elements/lib/column_config_utils.py +9 -8
  43. streamlit/elements/lib/column_types.py +595 -148
  44. streamlit/elements/lib/dialog.py +3 -2
  45. streamlit/elements/lib/image_utils.py +3 -5
  46. streamlit/elements/lib/layout_utils.py +50 -13
  47. streamlit/elements/lib/mutable_status_container.py +2 -2
  48. streamlit/elements/lib/options_selector_utils.py +2 -2
  49. streamlit/elements/lib/pandas_styler_utils.py +30 -14
  50. streamlit/elements/lib/utils.py +21 -9
  51. streamlit/elements/map.py +81 -40
  52. streamlit/elements/media.py +7 -7
  53. streamlit/elements/metric.py +11 -35
  54. streamlit/elements/pdf.py +2 -4
  55. streamlit/elements/plotly_chart.py +142 -26
  56. streamlit/elements/progress.py +2 -4
  57. streamlit/elements/pyplot.py +6 -6
  58. streamlit/elements/space.py +113 -0
  59. streamlit/elements/vega_charts.py +400 -143
  60. streamlit/elements/widgets/audio_input.py +52 -4
  61. streamlit/elements/widgets/button.py +29 -29
  62. streamlit/elements/widgets/button_group.py +33 -6
  63. streamlit/elements/widgets/camera_input.py +3 -4
  64. streamlit/elements/widgets/chat.py +7 -0
  65. streamlit/elements/widgets/checkbox.py +1 -0
  66. streamlit/elements/widgets/color_picker.py +1 -0
  67. streamlit/elements/widgets/data_editor.py +34 -29
  68. streamlit/elements/widgets/file_uploader.py +6 -10
  69. streamlit/elements/widgets/multiselect.py +14 -3
  70. streamlit/elements/widgets/number_input.py +5 -4
  71. streamlit/elements/widgets/radio.py +10 -2
  72. streamlit/elements/widgets/select_slider.py +8 -4
  73. streamlit/elements/widgets/selectbox.py +9 -2
  74. streamlit/elements/widgets/slider.py +38 -41
  75. streamlit/elements/widgets/text_widgets.py +6 -0
  76. streamlit/elements/widgets/time_widgets.py +15 -12
  77. streamlit/elements/write.py +28 -23
  78. streamlit/emojis.py +1 -1
  79. streamlit/errors.py +115 -0
  80. streamlit/git_util.py +65 -43
  81. streamlit/hello/hello.py +8 -0
  82. streamlit/hello/utils.py +2 -1
  83. streamlit/material_icon_names.py +1 -1
  84. streamlit/navigation/page.py +4 -1
  85. streamlit/proto/ArrowData_pb2.py +27 -0
  86. streamlit/proto/ArrowData_pb2.pyi +46 -0
  87. streamlit/proto/Arrow_pb2.py +10 -8
  88. streamlit/proto/Arrow_pb2.pyi +31 -2
  89. streamlit/proto/AudioInput_pb2.py +2 -2
  90. streamlit/proto/AudioInput_pb2.pyi +6 -2
  91. streamlit/proto/BidiComponent_pb2.py +34 -0
  92. streamlit/proto/BidiComponent_pb2.pyi +153 -0
  93. streamlit/proto/Block_pb2.py +11 -11
  94. streamlit/proto/Block_pb2.pyi +9 -1
  95. streamlit/proto/DeckGlJsonChart_pb2.py +10 -4
  96. streamlit/proto/DeckGlJsonChart_pb2.pyi +9 -3
  97. streamlit/proto/Element_pb2.py +5 -3
  98. streamlit/proto/Element_pb2.pyi +14 -4
  99. streamlit/proto/HeightConfig_pb2.py +2 -2
  100. streamlit/proto/HeightConfig_pb2.pyi +6 -3
  101. streamlit/proto/NewSession_pb2.py +18 -16
  102. streamlit/proto/NewSession_pb2.pyi +158 -6
  103. streamlit/proto/PlotlyChart_pb2.py +8 -6
  104. streamlit/proto/PlotlyChart_pb2.pyi +3 -1
  105. streamlit/proto/Space_pb2.py +27 -0
  106. streamlit/proto/Space_pb2.pyi +42 -0
  107. streamlit/proto/WidgetStates_pb2.py +2 -2
  108. streamlit/proto/WidgetStates_pb2.pyi +13 -3
  109. streamlit/proto/WidthConfig_pb2.py +2 -2
  110. streamlit/proto/WidthConfig_pb2.pyi +6 -3
  111. streamlit/runtime/app_session.py +45 -6
  112. streamlit/runtime/caching/cache_data_api.py +4 -4
  113. streamlit/runtime/caching/cache_errors.py +4 -1
  114. streamlit/runtime/caching/cache_resource_api.py +3 -2
  115. streamlit/runtime/caching/cache_utils.py +2 -1
  116. streamlit/runtime/caching/cached_message_replay.py +3 -3
  117. streamlit/runtime/caching/hashing.py +3 -4
  118. streamlit/runtime/caching/legacy_cache_api.py +2 -1
  119. streamlit/runtime/connection_factory.py +1 -3
  120. streamlit/runtime/forward_msg_queue.py +4 -1
  121. streamlit/runtime/fragment.py +2 -1
  122. streamlit/runtime/memory_media_file_storage.py +1 -1
  123. streamlit/runtime/metrics_util.py +6 -2
  124. streamlit/runtime/runtime.py +14 -0
  125. streamlit/runtime/scriptrunner/exec_code.py +2 -1
  126. streamlit/runtime/scriptrunner/script_runner.py +2 -2
  127. streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -6
  128. streamlit/runtime/secrets.py +2 -4
  129. streamlit/runtime/session_manager.py +3 -1
  130. streamlit/runtime/state/common.py +30 -5
  131. streamlit/runtime/state/presentation.py +85 -0
  132. streamlit/runtime/state/safe_session_state.py +2 -2
  133. streamlit/runtime/state/session_state.py +220 -16
  134. streamlit/runtime/state/widgets.py +19 -3
  135. streamlit/runtime/theme_util.py +148 -0
  136. streamlit/runtime/websocket_session_manager.py +3 -1
  137. streamlit/source_util.py +2 -2
  138. streamlit/static/index.html +2 -2
  139. streamlit/static/manifest.json +244 -227
  140. streamlit/static/static/css/{index.C8X8rNzw.css → index.BpABIXK9.css} +1 -1
  141. streamlit/static/static/css/index.DgR7E2CV.css +1 -0
  142. streamlit/static/static/js/{ErrorOutline.esm.DcGrhbBP.js → ErrorOutline.esm.YoJdlW1p.js} +1 -1
  143. streamlit/static/static/js/{FileDownload.esm.DgBvV6Pq.js → FileDownload.esm.Ddx8VEYy.js} +1 -1
  144. streamlit/static/static/js/{FileHelper.M6AAaeuA.js → FileHelper.90EtOmj9.js} +1 -1
  145. streamlit/static/static/js/{FormClearHelper.DHh1GFzm.js → FormClearHelper.BB1Km6eP.js} +1 -1
  146. streamlit/static/static/js/InputInstructions.jhH15PqV.js +1 -0
  147. streamlit/static/static/js/{Particles.DDVT-6Qc.js → Particles.DUsputn1.js} +1 -1
  148. streamlit/static/static/js/{ProgressBar.BEY0cXXV.js → ProgressBar.DLY8H6nE.js} +2 -2
  149. streamlit/static/static/js/Toolbar.D8nHCkuz.js +1 -0
  150. streamlit/static/static/js/{base-input.CK3UVGp1.js → base-input.CJGiNqed.js} +3 -3
  151. streamlit/static/static/js/{checkbox.D8W881TL.js → checkbox.Cpdd482O.js} +1 -1
  152. streamlit/static/static/js/{createSuper.B6W-Dh9S.js → createSuper.CuQIogbW.js} +1 -1
  153. streamlit/static/static/js/data-grid-overlay-editor.2Ufgxc6y.js +1 -0
  154. streamlit/static/static/js/{downloader.DiKpuU_S.js → downloader.CN0K7xlu.js} +1 -1
  155. streamlit/static/static/js/{es6.B8zRNPZ-.js → es6.BJcsVXQ0.js} +2 -2
  156. streamlit/static/static/js/{iframeResizer.contentWindow.DIewJmmh.js → iframeResizer.contentWindow.XzUvQqcZ.js} +1 -1
  157. streamlit/static/static/js/index.B1ZQh4P1.js +1 -0
  158. streamlit/static/static/js/index.BKstZk0M.js +27 -0
  159. streamlit/static/static/js/{index.Bte_9Lyq.js → index.BMcFsUee.js} +1 -1
  160. streamlit/static/static/js/{index.qhs54UAB.js → index.BR-IdcTb.js} +1 -1
  161. streamlit/static/static/js/{index.CejBxbg1.js → index.B_dWA3vd.js} +1 -1
  162. streamlit/static/static/js/{index.D5naqx-J.js → index.BgnZEMVh.js} +1 -1
  163. streamlit/static/static/js/{index.C7fRKRs4.js → index.BohqXifI.js} +1 -1
  164. streamlit/static/static/js/{index.cnnXF7xQ.js → index.Br5nxKNj.js} +1 -1
  165. streamlit/static/static/js/index.BrIKVbNc.js +3 -0
  166. streamlit/static/static/js/index.BtWUPzle.js +1 -0
  167. streamlit/static/static/js/index.C0RLraek.js +1 -0
  168. streamlit/static/static/js/{index.CP5TD2z1.js → index.CAIjskgG.js} +1 -1
  169. streamlit/static/static/js/{index.CD8HuT3N.js → index.CAj-7vWz.js} +135 -162
  170. streamlit/static/static/js/{index.DtYN2x4k.js → index.CMtEit2O.js} +1 -1
  171. streamlit/static/static/js/index.CkRlykEE.js +12 -0
  172. streamlit/static/static/js/{index.Ts_0SdB9.js → index.CmN3FXfI.js} +2 -2
  173. streamlit/static/static/js/{index.BnEpvLEz.js → index.CwbFI1_-.js} +1 -1
  174. streamlit/static/static/js/{index.CcJf6BCU.js → index.CxIUUfab.js} +27 -27
  175. streamlit/static/static/js/index.D2KPNy7e.js +1 -0
  176. streamlit/static/static/js/{index.Ch7MBCx0.js → index.D3GPA5k4.js} +47 -47
  177. streamlit/static/static/js/{index.ho6NIXGl.js → index.DGAh7DMq.js} +1 -1
  178. streamlit/static/static/js/index.DKb_NvmG.js +197 -0
  179. streamlit/static/static/js/{index.CvYYtxD_.js → index.DMqgUYKq.js} +1 -1
  180. streamlit/static/static/js/{index.zecpGxtj.js → index.DOFlg3dS.js} +1 -1
  181. streamlit/static/static/js/{index.B9mjBcgE.js → index.DPUXkcQL.js} +1 -1
  182. streamlit/static/static/js/index.DX1xY89g.js +1 -0
  183. streamlit/static/static/js/index.DYATBCsq.js +2 -0
  184. streamlit/static/static/js/{index.D2-atlaQ.js → index.DaSmGJ76.js} +3 -3
  185. streamlit/static/static/js/index.Dd7bMeLP.js +1 -0
  186. streamlit/static/static/js/{index.4eF4NxG2.js → index.DjmmgI5U.js} +1 -1
  187. streamlit/static/static/js/index.Dq56CyM2.js +1 -0
  188. streamlit/static/static/js/index.DuiXaS5_.js +7 -0
  189. streamlit/static/static/js/index.DvFidMLe.js +2 -0
  190. streamlit/static/static/js/{index.452cqrrL.js → index.DwkhC5Pc.js} +1 -1
  191. streamlit/static/static/js/{index.Dk4C7X3i.js → index.Q-3sFn1v.js} +1 -1
  192. streamlit/static/static/js/{index.CjXWwH-y.js → index.QJ5QO9sJ.js} +1 -1
  193. streamlit/static/static/js/{index.B6U8LQo3.js → index.VwTaeety.js} +1 -1
  194. streamlit/static/static/js/index.YOqQbeX8.js +1 -0
  195. streamlit/static/static/js/{input.nzVJphXi.js → input.D4MN_FzN.js} +1 -1
  196. streamlit/static/static/js/{memory.CjCgTQz3.js → memory.DrZjtdGT.js} +1 -1
  197. streamlit/static/static/js/{number-overlay-editor.DaRFzZEO.js → number-overlay-editor.DRwAw1In.js} +1 -1
  198. streamlit/static/static/js/{possibleConstructorReturn.DgiPnZ9N.js → possibleConstructorReturn.exeeJQEP.js} +1 -1
  199. streamlit/static/static/js/record.B-tDciZb.js +1 -0
  200. streamlit/static/static/js/{sandbox.mithfq7Z.js → sandbox.ClO3IuUr.js} +1 -1
  201. streamlit/static/static/js/{timepicker.Dbl5KFh6.js → timepicker.DAhu-vcF.js} +4 -4
  202. streamlit/static/static/js/{toConsumableArray.D-Dx88BQ.js → toConsumableArray.DNbljYEC.js} +1 -1
  203. streamlit/static/static/js/{uniqueId.Bh26R_3S.js → uniqueId.oG4Gvj1v.js} +1 -1
  204. streamlit/static/static/js/{useBasicWidgetState.DeK-QJpD.js → useBasicWidgetState.D6sOH6oI.js} +1 -1
  205. streamlit/static/static/js/{useTextInputAutoExpand.4iAdLWD-.js → useTextInputAutoExpand.4u3_GcuN.js} +2 -2
  206. streamlit/static/static/js/{useUpdateUiValue.CmT7_nJN.js → useUpdateUiValue.F2R3eTeR.js} +1 -1
  207. streamlit/static/static/js/wavesurfer.esm.vI8Eid4k.js +73 -0
  208. streamlit/static/static/js/withFullScreenWrapper.zothJIsI.js +1 -0
  209. streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
  210. streamlit/string_util.py +56 -1
  211. streamlit/testing/v1/app_test.py +2 -2
  212. streamlit/testing/v1/element_tree.py +23 -9
  213. streamlit/testing/v1/util.py +2 -2
  214. streamlit/type_util.py +3 -4
  215. streamlit/url_util.py +1 -3
  216. streamlit/user_info.py +1 -2
  217. streamlit/util.py +3 -1
  218. streamlit/watcher/event_based_path_watcher.py +23 -12
  219. streamlit/watcher/local_sources_watcher.py +11 -1
  220. streamlit/watcher/path_watcher.py +9 -6
  221. streamlit/watcher/polling_path_watcher.py +4 -1
  222. streamlit/watcher/util.py +2 -2
  223. streamlit/web/bootstrap.py +0 -31
  224. streamlit/web/cli.py +51 -22
  225. streamlit/web/server/bidi_component_request_handler.py +193 -0
  226. streamlit/web/server/component_file_utils.py +97 -0
  227. streamlit/web/server/component_request_handler.py +8 -21
  228. streamlit/web/server/oidc_mixin.py +3 -1
  229. streamlit/web/server/routes.py +18 -5
  230. streamlit/web/server/server.py +10 -0
  231. streamlit/web/server/server_util.py +3 -1
  232. streamlit/web/server/upload_file_request_handler.py +3 -1
  233. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/METADATA +4 -5
  234. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/RECORD +238 -209
  235. streamlit/static/static/css/index.COe1010n.css +0 -1
  236. streamlit/static/static/js/Hooks.DGu1od_L.js +0 -1
  237. streamlit/static/static/js/InputInstructions.z6sVgyYt.js +0 -1
  238. streamlit/static/static/js/Toolbar.DSnK1fUh.js +0 -1
  239. streamlit/static/static/js/data-grid-overlay-editor.DRTHOydk.js +0 -1
  240. streamlit/static/static/js/index.BXYmrqnf.js +0 -1
  241. streamlit/static/static/js/index.B_8AnktO.js +0 -1
  242. streamlit/static/static/js/index.Bl7zGQSh.js +0 -7
  243. streamlit/static/static/js/index.BnJIOYn9.js +0 -73
  244. streamlit/static/static/js/index.C1HcTl5K.js +0 -1
  245. streamlit/static/static/js/index.C7lSmSOP.js +0 -1
  246. streamlit/static/static/js/index.C_tmcx4B.js +0 -1
  247. streamlit/static/static/js/index.D3K5nOu9.js +0 -197
  248. streamlit/static/static/js/index.DkKT3LUI.js +0 -1
  249. streamlit/static/static/js/index.MTPPBDHk.js +0 -2
  250. streamlit/static/static/js/index.pqW9AMJD.js +0 -3
  251. streamlit/static/static/js/index.urHgTgMQ.js +0 -12
  252. streamlit/static/static/js/index.wzkv_11M.js +0 -1
  253. streamlit/static/static/js/index.yF5AncHY.js +0 -1
  254. streamlit/static/static/js/withFullScreenWrapper.DLp1ENGm.js +0 -1
  255. streamlit/static/static/media/MaterialSymbols-Rounded.CBxVaFdk.woff2 +0 -0
  256. {streamlit-1.49.1.data → streamlit-1.51.0.data}/scripts/streamlit.cmd +0 -0
  257. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/WHEEL +0 -0
  258. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/entry_points.txt +0 -0
  259. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/top_level.txt +0 -0
@@ -19,7 +19,6 @@ from textwrap import dedent
19
19
  from typing import (
20
20
  TYPE_CHECKING,
21
21
  Any,
22
- Callable,
23
22
  Generic,
24
23
  Literal,
25
24
  TypeVar,
@@ -64,7 +63,7 @@ from streamlit.type_util import (
64
63
  )
65
64
 
66
65
  if TYPE_CHECKING:
67
- from collections.abc import Sequence
66
+ from collections.abc import Callable, Sequence
68
67
 
69
68
  from streamlit.dataframe_util import OptionSequence
70
69
  from streamlit.delta_generator import DeltaGenerator
@@ -370,7 +369,9 @@ class MultiSelectMixin:
370
369
  Returns
371
370
  -------
372
371
  list
373
- A list with the selected options
372
+ A list of the selected options.
373
+
374
+ The list contains copies of the selected options, not the originals.
374
375
 
375
376
  Examples
376
377
  --------
@@ -492,6 +493,16 @@ class MultiSelectMixin:
492
493
  element_id = compute_and_register_element_id(
493
494
  widget_name,
494
495
  user_key=key,
496
+ # Treat the provided key as the main identity. Only include
497
+ # changes to the options, accept_new_options, and max_selections
498
+ # in the identity computation as those can invalidate the
499
+ # current selection.
500
+ key_as_main_identity={
501
+ "options",
502
+ "max_selections",
503
+ "accept_new_options",
504
+ "format_func",
505
+ },
495
506
  dg=self.dg,
496
507
  label=label,
497
508
  options=formatted_options,
@@ -17,9 +17,7 @@ from __future__ import annotations
17
17
  import numbers
18
18
  from dataclasses import dataclass
19
19
  from textwrap import dedent
20
- from typing import TYPE_CHECKING, Literal, TypeVar, Union, cast, overload
21
-
22
- from typing_extensions import TypeAlias
20
+ from typing import TYPE_CHECKING, Literal, TypeAlias, TypeVar, cast, overload
23
21
 
24
22
  from streamlit.elements.lib.form_utils import current_form_id
25
23
  from streamlit.elements.lib.js_number import JSNumber, JSNumberBoundsException
@@ -62,7 +60,7 @@ if TYPE_CHECKING:
62
60
  from streamlit.delta_generator import DeltaGenerator
63
61
 
64
62
 
65
- Number: TypeAlias = Union[int, float]
63
+ Number: TypeAlias = int | float
66
64
  IntOrNone = TypeVar("IntOrNone", int, None)
67
65
  FloatOrNone = TypeVar("FloatOrNone", float, None)
68
66
 
@@ -452,6 +450,9 @@ class NumberInputMixin:
452
450
  element_id = compute_and_register_element_id(
453
451
  "number_input",
454
452
  user_key=key,
453
+ # Ensure stable ID when key is provided; explicitly whitelist parameters
454
+ # that might invalidate the current widget state.
455
+ key_as_main_identity={"min_value", "max_value", "step"},
455
456
  dg=self.dg,
456
457
  label=label,
457
458
  min_value=min_value,
@@ -16,7 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  from dataclasses import dataclass
18
18
  from textwrap import dedent
19
- from typing import TYPE_CHECKING, Any, Callable, Generic, TypeVar, cast, overload
19
+ from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast, overload
20
20
 
21
21
  from typing_extensions import Never
22
22
 
@@ -56,7 +56,7 @@ from streamlit.type_util import (
56
56
  )
57
57
 
58
58
  if TYPE_CHECKING:
59
- from collections.abc import Sequence
59
+ from collections.abc import Callable, Sequence
60
60
 
61
61
  from streamlit.delta_generator import DeltaGenerator
62
62
 
@@ -272,6 +272,8 @@ class RadioMixin:
272
272
  any
273
273
  The selected option or ``None`` if no option is selected.
274
274
 
275
+ This is a copy of the selected option, not the original.
276
+
275
277
  Example
276
278
  -------
277
279
  >>> import streamlit as st
@@ -369,6 +371,12 @@ class RadioMixin:
369
371
  element_id = compute_and_register_element_id(
370
372
  "radio",
371
373
  user_key=key,
374
+ # Treat provided key as the main widget identity. Only include the
375
+ # following parameters in the identity computation since they can
376
+ # invalidate the current selection mapping.
377
+ # Changes to format_func also invalidate the current selection,
378
+ # but this is already handled via the `options` parameter below:
379
+ key_as_main_identity={"options"},
372
380
  dg=self.dg,
373
381
  label=label,
374
382
  options=[str(format_func(option)) for option in opt],
@@ -19,15 +19,13 @@ from textwrap import dedent
19
19
  from typing import (
20
20
  TYPE_CHECKING,
21
21
  Any,
22
- Callable,
23
22
  Generic,
23
+ TypeGuard,
24
24
  TypeVar,
25
25
  cast,
26
26
  overload,
27
27
  )
28
28
 
29
- from typing_extensions import TypeGuard
30
-
31
29
  from streamlit.dataframe_util import OptionSequence, convert_anything_to_list
32
30
  from streamlit.elements.lib.form_utils import current_form_id
33
31
  from streamlit.elements.lib.layout_utils import LayoutConfig, validate_width
@@ -61,7 +59,7 @@ from streamlit.runtime.state import (
61
59
  from streamlit.type_util import check_python_comparable
62
60
 
63
61
  if TYPE_CHECKING:
64
- from collections.abc import Sequence
62
+ from collections.abc import Callable, Sequence
65
63
 
66
64
  from streamlit.delta_generator import DeltaGenerator
67
65
  from streamlit.elements.lib.layout_utils import WidthWithoutContent
@@ -264,6 +262,8 @@ class SelectSliderMixin:
264
262
  The current value of the slider widget. The return type will match
265
263
  the data type of the value parameter.
266
264
 
265
+ This contains copies of the selected options, not the originals.
266
+
267
267
  Examples
268
268
  --------
269
269
  >>> import streamlit as st
@@ -377,6 +377,10 @@ class SelectSliderMixin:
377
377
  element_id = compute_and_register_element_id(
378
378
  "select_slider",
379
379
  user_key=key,
380
+ # Treat the provided key as the main identity; only include
381
+ # changes to the options (and implicitly their formatting) in the
382
+ # identity computation as those can invalidate the current value.
383
+ key_as_main_identity={"options", "format_func"},
380
384
  dg=self.dg,
381
385
  label=label,
382
386
  options=[str(format_func(option)) for option in opt],
@@ -17,7 +17,6 @@ from textwrap import dedent
17
17
  from typing import (
18
18
  TYPE_CHECKING,
19
19
  Any,
20
- Callable,
21
20
  Generic,
22
21
  Literal,
23
22
  TypeVar,
@@ -67,7 +66,7 @@ from streamlit.type_util import (
67
66
  )
68
67
 
69
68
  if TYPE_CHECKING:
70
- from collections.abc import Sequence
69
+ from collections.abc import Callable, Sequence
71
70
 
72
71
  from streamlit.delta_generator import DeltaGenerator
73
72
 
@@ -404,6 +403,8 @@ class SelectboxMixin:
404
403
  any
405
404
  The selected option or ``None`` if no option is selected.
406
405
 
406
+ This is a copy of the selected option, not the original.
407
+
407
408
  Examples
408
409
  --------
409
410
  **Example 1: Use a basic selectbox widget**
@@ -541,6 +542,12 @@ class SelectboxMixin:
541
542
  element_id = compute_and_register_element_id(
542
543
  "selectbox",
543
544
  user_key=key,
545
+ # Treat the provided key as the main identity. Only include
546
+ # the options and accept_new_options in the identity computation
547
+ # as those can invalidate the current selection.
548
+ # Changes to format_func also invalidate the current selection,
549
+ # but this is already handled via the `options` parameter below:
550
+ key_as_main_identity={"options", "accept_new_options"},
544
551
  dg=self.dg,
545
552
  label=label,
546
553
  options=formatted_options,
@@ -23,15 +23,13 @@ from typing import (
23
23
  TYPE_CHECKING,
24
24
  Any,
25
25
  Final,
26
+ TypeAlias,
26
27
  TypedDict,
27
28
  TypeVar,
28
- Union,
29
29
  cast,
30
30
  overload,
31
31
  )
32
32
 
33
- from typing_extensions import TypeAlias
34
-
35
33
  from streamlit.elements.lib.form_utils import current_form_id
36
34
  from streamlit.elements.lib.js_number import JSNumber, JSNumberBoundsException
37
35
  from streamlit.elements.lib.layout_utils import LayoutConfig, validate_width
@@ -69,48 +67,43 @@ if TYPE_CHECKING:
69
67
  SliderNumericT = TypeVar("SliderNumericT", int, float)
70
68
  SliderDatelikeT = TypeVar("SliderDatelikeT", date, time, datetime)
71
69
 
72
- SliderNumericSpanT: TypeAlias = Union[
73
- list[SliderNumericT],
74
- tuple[()],
75
- tuple[SliderNumericT],
76
- tuple[SliderNumericT, SliderNumericT],
77
- ]
78
- SliderDatelikeSpanT: TypeAlias = Union[
79
- list[SliderDatelikeT],
80
- tuple[()],
81
- tuple[SliderDatelikeT],
82
- tuple[SliderDatelikeT, SliderDatelikeT],
83
- ]
70
+ SliderNumericSpanT: TypeAlias = (
71
+ list[SliderNumericT]
72
+ | tuple[()]
73
+ | tuple[SliderNumericT]
74
+ | tuple[SliderNumericT, SliderNumericT]
75
+ )
76
+ SliderDatelikeSpanT: TypeAlias = (
77
+ list[SliderDatelikeT]
78
+ | tuple[()]
79
+ | tuple[SliderDatelikeT]
80
+ | tuple[SliderDatelikeT, SliderDatelikeT]
81
+ )
84
82
 
85
83
  StepNumericT: TypeAlias = SliderNumericT
86
84
  StepDatelikeT: TypeAlias = timedelta
87
85
 
88
- SliderStep: TypeAlias = Union[int, float, timedelta]
89
- SliderScalar: TypeAlias = Union[int, float, date, time, datetime]
86
+ SliderStep: TypeAlias = int | float | timedelta
87
+ SliderScalar: TypeAlias = int | float | date | time | datetime
90
88
  SliderValueT = TypeVar("SliderValueT", int, float, date, time, datetime)
91
- SliderValueGeneric: TypeAlias = Union[
92
- SliderValueT,
93
- Sequence[SliderValueT],
94
- ]
95
- SliderValue: TypeAlias = Union[
96
- SliderValueGeneric[int],
97
- SliderValueGeneric[float],
98
- SliderValueGeneric[date],
99
- SliderValueGeneric[time],
100
- SliderValueGeneric[datetime],
101
- ]
102
- SliderReturnGeneric: TypeAlias = Union[
103
- SliderValueT,
104
- tuple[SliderValueT],
105
- tuple[SliderValueT, SliderValueT],
106
- ]
107
- SliderReturn: TypeAlias = Union[
108
- SliderReturnGeneric[int],
109
- SliderReturnGeneric[float],
110
- SliderReturnGeneric[date],
111
- SliderReturnGeneric[time],
112
- SliderReturnGeneric[datetime],
113
- ]
89
+ SliderValueGeneric: TypeAlias = SliderValueT | Sequence[SliderValueT]
90
+ SliderValue: TypeAlias = (
91
+ SliderValueGeneric[int]
92
+ | SliderValueGeneric[float] # ty: ignore
93
+ | SliderValueGeneric[date]
94
+ | SliderValueGeneric[time]
95
+ | SliderValueGeneric[datetime]
96
+ )
97
+ SliderReturnGeneric: TypeAlias = (
98
+ SliderValueT | tuple[SliderValueT] | tuple[SliderValueT, SliderValueT]
99
+ )
100
+ SliderReturn: TypeAlias = (
101
+ SliderReturnGeneric[int]
102
+ | SliderReturnGeneric[float] # ty: ignore
103
+ | SliderReturnGeneric[date]
104
+ | SliderReturnGeneric[time]
105
+ | SliderReturnGeneric[datetime]
106
+ )
114
107
 
115
108
  SECONDS_TO_MICROS: Final = 1000 * 1000
116
109
  DAYS_TO_MICROS: Final = 24 * 60 * 60 * SECONDS_TO_MICROS
@@ -680,6 +673,10 @@ class SliderMixin:
680
673
  element_id = compute_and_register_element_id(
681
674
  "slider",
682
675
  user_key=key,
676
+ # Treat the provided key as the main identity; only include
677
+ # changes to the value-shaping arguments in the identity
678
+ # computation as those can invalidate the current value.
679
+ key_as_main_identity={"min_value", "max_value", "step"},
683
680
  dg=self.dg,
684
681
  label=label,
685
682
  min_value=min_value,
@@ -801,7 +798,7 @@ class SliderMixin:
801
798
  if data_type in (
802
799
  SliderProto.DATETIME,
803
800
  SliderProto.DATE,
804
- ) and max_value - min_value < timedelta(days=1):
801
+ ) and max_value - min_value < timedelta(days=1): # ty: ignore[unsupported-operator]
805
802
  step = timedelta(minutes=15)
806
803
  if format is None:
807
804
  format = cast("str", defaults[data_type]["format"]) # noqa: A001
@@ -328,6 +328,9 @@ class TextWidgetsMixin:
328
328
  element_id = compute_and_register_element_id(
329
329
  "text_input",
330
330
  user_key=key,
331
+ # Explicitly whitelist max_chars to make sure the ID changes when it changes
332
+ # since the widget value might become invalid based on a different max_chars
333
+ key_as_main_identity={"max_chars"},
331
334
  dg=self.dg,
332
335
  label=label,
333
336
  value=value,
@@ -642,6 +645,9 @@ class TextWidgetsMixin:
642
645
  element_id = compute_and_register_element_id(
643
646
  "text_area",
644
647
  user_key=key,
648
+ # Explicitly whitelist max_chars to make sure the ID changes when it changes
649
+ # since the widget value might become invalid based on a different max_chars
650
+ key_as_main_identity={"max_chars"},
645
651
  dg=self.dg,
646
652
  label=label,
647
653
  value=value,
@@ -23,13 +23,11 @@ from typing import (
23
23
  Any,
24
24
  Final,
25
25
  Literal,
26
- Union,
26
+ TypeAlias,
27
27
  cast,
28
28
  overload,
29
29
  )
30
30
 
31
- from typing_extensions import TypeAlias
32
-
33
31
  from streamlit.elements.lib.form_utils import current_form_id
34
32
  from streamlit.elements.lib.layout_utils import (
35
33
  LayoutConfig,
@@ -65,21 +63,17 @@ if TYPE_CHECKING:
65
63
  from streamlit.delta_generator import DeltaGenerator
66
64
 
67
65
  # Type for things that point to a specific time (even if a default time, though not None).
68
- TimeValue: TypeAlias = Union[time, datetime, str, Literal["now"]]
66
+ TimeValue: TypeAlias = time | datetime | str | Literal["now"]
69
67
 
70
68
  # Type for things that point to a specific date (even if a default date, including None).
71
- NullableScalarDateValue: TypeAlias = Union[date, datetime, str, Literal["today"], None]
69
+ NullableScalarDateValue: TypeAlias = date | datetime | str | Literal["today"] | None
72
70
 
73
71
  # The accepted input value for st.date_input. Can be a date scalar or a date range.
74
- DateValue: TypeAlias = Union[NullableScalarDateValue, Sequence[NullableScalarDateValue]]
72
+ DateValue: TypeAlias = NullableScalarDateValue | Sequence[NullableScalarDateValue]
75
73
 
76
74
  # The return value of st.date_input.
77
- DateWidgetRangeReturn: TypeAlias = Union[
78
- tuple[()],
79
- tuple[date],
80
- tuple[date, date],
81
- ]
82
- DateWidgetReturn: TypeAlias = Union[date, DateWidgetRangeReturn, None]
75
+ DateWidgetRangeReturn: TypeAlias = tuple[()] | tuple[date] | tuple[date, date]
76
+ DateWidgetReturn: TypeAlias = date | DateWidgetRangeReturn | None
83
77
 
84
78
 
85
79
  DEFAULT_STEP_MINUTES: Final = 15
@@ -529,6 +523,9 @@ class TimeWidgetsMixin:
529
523
  element_id = compute_and_register_element_id(
530
524
  "time_input",
531
525
  user_key=key,
526
+ # Ensure stable ID when key is provided; only whitelist step since it
527
+ # affects the selection granularity and available options.
528
+ key_as_main_identity={"step"},
532
529
  dg=self.dg,
533
530
  label=label,
534
531
  value=parsed_time if isinstance(value, (datetime, time)) else value,
@@ -911,6 +908,12 @@ class TimeWidgetsMixin:
911
908
  element_id = compute_and_register_element_id(
912
909
  "date_input",
913
910
  user_key=key,
911
+ # Ensure stable ID when key is provided; explicitly whitelist parameters
912
+ # that might invalidate the current widget state.
913
+ # format should be supported. However, there is a bug in baseweb where
914
+ # changing the format dynamically leads to a wrongly formatted date.
915
+ # So, we whitelist it for now until we migrate this away from baseweb.
916
+ key_as_main_identity={"min_value", "max_value", "format"},
914
917
  dg=self.dg,
915
918
  label=label,
916
919
  value=parsed,
@@ -20,6 +20,7 @@ import types
20
20
  from collections import ChainMap, UserDict, UserList
21
21
  from collections.abc import (
22
22
  AsyncGenerator,
23
+ Callable,
23
24
  Generator,
24
25
  ItemsView,
25
26
  Iterable,
@@ -30,14 +31,12 @@ from io import StringIO
30
31
  from typing import (
31
32
  TYPE_CHECKING,
32
33
  Any,
33
- Callable,
34
34
  Final,
35
35
  cast,
36
36
  )
37
37
 
38
38
  from streamlit import dataframe_util, type_util
39
39
  from streamlit.errors import StreamlitAPIException
40
- from streamlit.logger import get_logger
41
40
  from streamlit.runtime.metrics_util import gather_metrics
42
41
  from streamlit.string_util import (
43
42
  is_mem_address_str,
@@ -56,10 +55,6 @@ HELP_TYPES: Final[tuple[type[Any], ...]] = (
56
55
  types.ModuleType,
57
56
  )
58
57
 
59
- _LOGGER: Final = get_logger(__name__)
60
-
61
- _TEXT_CURSOR: Final = " ▏"
62
-
63
58
 
64
59
  class StreamingOutput(list[Any]):
65
60
  pass
@@ -73,8 +68,10 @@ class WriteMixin:
73
68
  | Generator[Any, Any, Any]
74
69
  | Iterable[Any]
75
70
  | AsyncGenerator[Any, Any],
71
+ *,
72
+ cursor: str | None = None,
76
73
  ) -> list[Any] | str:
77
- """Stream a generator, iterable, or stream-like sequence to the app.
74
+ r"""Stream a generator, iterable, or stream-like sequence to the app.
78
75
 
79
76
  ``st.write_stream`` iterates through the given sequences and writes all
80
77
  chunks to the app. String chunks will be written using a typewriter effect.
@@ -94,6 +91,27 @@ class WriteMixin:
94
91
  manually define a generator function and include custom output
95
92
  parsing.
96
93
 
94
+ cursor : str or None
95
+ A string to append to text as it's being written. If this is
96
+ ``None`` (default), no cursor is shown. Otherwise, the string is
97
+ rendered as Markdown and appears as a cursor at the end of the
98
+ streamed text. For example, you can use an emoji, emoji shortcode,
99
+ or Material icon.
100
+
101
+ The first line of the cursor string can contain GitHub-flavored
102
+ Markdown of the following types: Bold, Italics, Strikethroughs,
103
+ Inline Code, Links, and Images. Images display like icons, with a
104
+ max height equal to the font height. If you pass a multiline
105
+ string, additional lines display after the text with the full
106
+ Markdown rendering capabilities of ``st.markdown``.
107
+
108
+ See the ``body`` parameter of |st.markdown|_ for additional,
109
+ supported Markdown directives.
110
+
111
+ .. |st.markdown| replace:: ``st.markdown``
112
+ .. _st.markdown: https://docs.streamlit.io/develop/api-reference/text/st.markdown
113
+
114
+
97
115
  Returns
98
116
  -------
99
117
  str or list
@@ -153,6 +171,7 @@ class WriteMixin:
153
171
  "this data type."
154
172
  )
155
173
 
174
+ cursor_str = cursor or ""
156
175
  stream_container: DeltaGenerator | None = None
157
176
  streamed_response: str = ""
158
177
  written_content: list[Any] = StreamingOutput()
@@ -231,7 +250,7 @@ class WriteMixin:
231
250
  streamed_response += chunk
232
251
  # Only add the streaming symbol on the second text chunk
233
252
  stream_container.markdown(
234
- streamed_response + ("" if first_text else _TEXT_CURSOR),
253
+ streamed_response + ("" if first_text else cursor_str),
235
254
  )
236
255
  elif callable(chunk):
237
256
  flush_stream_response()
@@ -254,7 +273,7 @@ class WriteMixin:
254
273
  return written_content
255
274
 
256
275
  @gather_metrics("write")
257
- def write(self, *args: Any, unsafe_allow_html: bool = False, **kwargs: Any) -> None:
276
+ def write(self, *args: Any, unsafe_allow_html: bool = False) -> None:
258
277
  """Displays arguments in the app.
259
278
 
260
279
  This is the Swiss Army knife of Streamlit commands: it does different
@@ -323,13 +342,6 @@ class WriteMixin:
323
342
  If you only want to insert HTML or CSS without Markdown text,
324
343
  we recommend using ``st.html`` instead.
325
344
 
326
- **kwargs : any
327
- Keyword arguments. Not used.
328
-
329
- .. deprecated::
330
- ``**kwargs`` is deprecated and will be removed in a later version.
331
- Use other, more specific Streamlit commands to pass additional
332
- keyword arguments.
333
345
 
334
346
  Returns
335
347
  -------
@@ -400,13 +412,6 @@ class WriteMixin:
400
412
  height: 300px
401
413
 
402
414
  """
403
- if kwargs:
404
- _LOGGER.warning(
405
- 'Invalid arguments were passed to "st.write" function. Support for '
406
- "passing such unknown keywords arguments will be dropped in future. "
407
- "Invalid arguments were: %s",
408
- kwargs,
409
- )
410
415
 
411
416
  if len(args) == 1 and isinstance(args[0], str):
412
417
  # Optimization: If there is only one arg, and it's a string,