streamlit-nightly 1.45.2.dev20250527__py3-none-any.whl → 1.45.2.dev20250530__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 (180) hide show
  1. streamlit/auth_util.py +3 -3
  2. streamlit/commands/echo.py +1 -1
  3. streamlit/config.py +32 -12
  4. streamlit/config_option.py +3 -5
  5. streamlit/config_util.py +4 -5
  6. streamlit/connections/snowflake_connection.py +4 -3
  7. streamlit/delta_generator.py +10 -14
  8. streamlit/elements/arrow.py +1 -0
  9. streamlit/elements/deck_gl_json_chart.py +1 -0
  10. streamlit/elements/doc_string.py +7 -15
  11. streamlit/elements/exception.py +4 -12
  12. streamlit/elements/form.py +14 -0
  13. streamlit/elements/graphviz_chart.py +1 -1
  14. streamlit/elements/heading.py +3 -4
  15. streamlit/elements/json.py +7 -6
  16. streamlit/elements/layouts.py +21 -3
  17. streamlit/elements/lib/image_utils.py +2 -3
  18. streamlit/elements/lib/layout_utils.py +24 -0
  19. streamlit/elements/lib/mutable_status_container.py +9 -0
  20. streamlit/elements/lib/streamlit_plotly_theme.py +54 -53
  21. streamlit/elements/lib/utils.py +15 -0
  22. streamlit/elements/markdown.py +34 -4
  23. streamlit/elements/media.py +1 -1
  24. streamlit/elements/plotly_chart.py +1 -0
  25. streamlit/elements/progress.py +6 -15
  26. streamlit/elements/spinner.py +5 -4
  27. streamlit/elements/vega_charts.py +1 -0
  28. streamlit/elements/widgets/audio_input.py +4 -10
  29. streamlit/elements/widgets/button.py +3 -1
  30. streamlit/elements/widgets/button_group.py +1 -0
  31. streamlit/elements/widgets/camera_input.py +6 -9
  32. streamlit/elements/widgets/chat.py +11 -13
  33. streamlit/elements/widgets/checkbox.py +1 -0
  34. streamlit/elements/widgets/color_picker.py +9 -14
  35. streamlit/elements/widgets/data_editor.py +9 -5
  36. streamlit/elements/widgets/file_uploader.py +10 -9
  37. streamlit/elements/widgets/multiselect.py +1 -0
  38. streamlit/elements/widgets/number_input.py +12 -12
  39. streamlit/elements/widgets/radio.py +2 -1
  40. streamlit/elements/widgets/select_slider.py +4 -10
  41. streamlit/elements/widgets/selectbox.py +11 -13
  42. streamlit/elements/widgets/slider.py +28 -41
  43. streamlit/elements/widgets/text_widgets.py +16 -24
  44. streamlit/elements/widgets/time_widgets.py +15 -22
  45. streamlit/hello/animation_demo.py +9 -9
  46. streamlit/hello/dataframe_demo.py +2 -2
  47. streamlit/hello/hello.py +1 -0
  48. streamlit/hello/mapping_demo.py +5 -6
  49. streamlit/hello/streamlit_app.py +27 -25
  50. streamlit/logger.py +1 -1
  51. streamlit/proto/AudioInput_pb2.py +3 -4
  52. streamlit/proto/AudioInput_pb2.pyi +2 -7
  53. streamlit/proto/Block_pb2.py +27 -27
  54. streamlit/proto/Block_pb2.pyi +3 -17
  55. streamlit/proto/CameraInput_pb2.py +3 -4
  56. streamlit/proto/CameraInput_pb2.pyi +2 -8
  57. streamlit/proto/ChatInput_pb2.py +7 -8
  58. streamlit/proto/ChatInput_pb2.pyi +1 -10
  59. streamlit/proto/Code_pb2.py +3 -4
  60. streamlit/proto/DateInput_pb2.py +3 -4
  61. streamlit/proto/DateInput_pb2.pyi +2 -8
  62. streamlit/proto/DocString_pb2.py +5 -6
  63. streamlit/proto/DocString_pb2.pyi +1 -9
  64. streamlit/proto/FileUploader_pb2.py +3 -4
  65. streamlit/proto/FileUploader_pb2.pyi +2 -8
  66. streamlit/proto/Json_pb2.py +3 -4
  67. streamlit/proto/Json_pb2.pyi +2 -9
  68. streamlit/proto/NewSession_pb2.py +16 -16
  69. streamlit/proto/NewSession_pb2.pyi +7 -2
  70. streamlit/proto/NumberInput_pb2.py +5 -6
  71. streamlit/proto/NumberInput_pb2.pyi +2 -9
  72. streamlit/proto/Progress_pb2.py +3 -4
  73. streamlit/proto/Progress_pb2.pyi +1 -7
  74. streamlit/proto/Selectbox_pb2.py +3 -4
  75. streamlit/proto/Selectbox_pb2.pyi +2 -9
  76. streamlit/proto/Slider_pb2.py +7 -8
  77. streamlit/proto/Slider_pb2.pyi +2 -8
  78. streamlit/proto/TextArea_pb2.py +3 -4
  79. streamlit/proto/TextArea_pb2.pyi +2 -9
  80. streamlit/proto/TextInput_pb2.py +5 -6
  81. streamlit/proto/TextInput_pb2.pyi +2 -9
  82. streamlit/proto/TimeInput_pb2.py +3 -4
  83. streamlit/proto/TimeInput_pb2.pyi +2 -9
  84. streamlit/runtime/app_session.py +11 -8
  85. streamlit/runtime/caching/hashing.py +8 -9
  86. streamlit/runtime/caching/storage/local_disk_cache_storage.py +3 -3
  87. streamlit/runtime/connection_factory.py +12 -12
  88. streamlit/runtime/credentials.py +13 -26
  89. streamlit/runtime/runtime_util.py +2 -2
  90. streamlit/runtime/scriptrunner/script_runner.py +8 -7
  91. streamlit/static/index.html +1 -1
  92. streamlit/static/manifest.json +1240 -0
  93. streamlit/static/static/js/{ErrorOutline.esm.qteVcUUN.js → ErrorOutline.esm.D5NgCh5m.js} +1 -1
  94. streamlit/static/static/js/{FileDownload.esm.ncu7N-Hr.js → FileDownload.esm.NuObx1Tl.js} +1 -1
  95. streamlit/static/static/js/{FileHelper.zsMZ7RXt.js → FileHelper.BH7o4_P9.js} +5 -5
  96. streamlit/static/static/js/{FormClearHelper.W8yVYXZp.js → FormClearHelper.BAxB8JFY.js} +1 -1
  97. streamlit/static/static/js/{Hooks.DBj6srQ1.js → Hooks.Bjt8oBOT.js} +1 -1
  98. streamlit/static/static/js/{InputInstructions.BobLsJJb.js → InputInstructions.BZZLp6t9.js} +1 -1
  99. streamlit/static/static/js/{ProgressBar.CtvJrIzN.js → ProgressBar.BwRgGfI0.js} +2 -2
  100. streamlit/static/static/js/{RenderInPortalIfExists.DnT_UdzV.js → RenderInPortalIfExists.C_c286r8.js} +1 -1
  101. streamlit/static/static/js/{Toolbar.BVF7NtOB.js → Toolbar.5tXjF_eX.js} +1 -1
  102. streamlit/static/static/js/{base-input.B4sdS3vw.js → base-input.wfBDFTlB.js} +1 -1
  103. streamlit/static/static/js/{checkbox.DKDitzF8.js → checkbox.D1GhNngU.js} +1 -1
  104. streamlit/static/static/js/{createSuper.mhx956J9.js → createSuper.CudEEVs2.js} +1 -1
  105. streamlit/static/static/js/{data-grid-overlay-editor.CmXS0PAX.js → data-grid-overlay-editor.DUTI_Rbg.js} +1 -1
  106. streamlit/static/static/js/{downloader.Cnd9SuxG.js → downloader.BwLpAoXN.js} +1 -1
  107. streamlit/static/static/js/{es6.DM-pf09u.js → es6.B_HLnUb9.js} +2 -2
  108. streamlit/static/static/js/{iframeResizer.contentWindow.Gc5GAjZM.js → iframeResizer.contentWindow.BNcjOcan.js} +1 -1
  109. streamlit/static/static/js/{index.D4XRYl23.js → index.3WJoJFGb.js} +1 -1
  110. streamlit/static/static/js/{index.C_2m4F7k.js → index.B0h616Th.js} +1 -1
  111. streamlit/static/static/js/{index.p2Wl4zMi.js → index.B0paBg5x.js} +1 -1
  112. streamlit/static/static/js/index.B3vWaIrN.js +1 -0
  113. streamlit/static/static/js/{index.B45ExNhw.js → index.B4PbMsBe.js} +1 -1
  114. streamlit/static/static/js/{index.BWTBe3a1.js → index.BGKVW2u9.js} +1 -1
  115. streamlit/static/static/js/index.BJQPxOFd.js +12 -0
  116. streamlit/static/static/js/{index.DdyZtGcg.js → index.BOHEcsVb.js} +1 -1
  117. streamlit/static/static/js/{index.BR-S54Iv.js → index.BPGAPI9w.js} +1 -1
  118. streamlit/static/static/js/{index.gBOr8z2K.js → index.Bj6uLiaA.js} +1 -1
  119. streamlit/static/static/js/{index.I3iNnzJx.js → index.BkvVxUIW.js} +1 -1
  120. streamlit/static/static/js/{index._BaeK1t7.js → index.Bs0m0eUy.js} +1 -1
  121. streamlit/static/static/js/{index.DwUISpCs.js → index.BtpsTdHN.js} +177 -174
  122. streamlit/static/static/js/index.C1GNiWbH.js +1 -0
  123. streamlit/static/static/js/{index.B6xTo8b8.js → index.CL0UH4WF.js} +1 -1
  124. streamlit/static/static/js/{index.BJQNG4O1.js → index.CXP5ffxh.js} +1 -1
  125. streamlit/static/static/js/{index.DAvhwYMG.js → index.Ca-9xoC2.js} +1 -1
  126. streamlit/static/static/js/{index.COBionvf.js → index.Cdd7Ri21.js} +1 -1
  127. streamlit/static/static/js/index.Cf8KcH2X.js +1 -0
  128. streamlit/static/static/js/{index.BkLkRTpZ.js → index.CfzaRR6P.js} +1 -1
  129. streamlit/static/static/js/{index.CkKptP1T.js → index.CjRwuAdg.js} +1 -1
  130. streamlit/static/static/js/{index.CjBaoWYr.js → index.CkOUlPYT.js} +1 -1
  131. streamlit/static/static/js/{index.DQGSbu2C.js → index.CxtkoiKl.js} +1 -1
  132. streamlit/static/static/js/index.D3wYqvI6.js +1 -0
  133. streamlit/static/static/js/index.D8i27llu.js +3 -0
  134. streamlit/static/static/js/{index.BfusYuD8.js → index.DA7wmIe4.js} +1 -1
  135. streamlit/static/static/js/index.DIG9Mo9J.js +1 -0
  136. streamlit/static/static/js/index.DNR4wKJg.js +1 -0
  137. streamlit/static/static/js/{index.B29JQLHa.js → index.DNS8a-dx.js} +20 -20
  138. streamlit/static/static/js/{index.BNNR5Jmd.js → index.NveskZ7j.js} +1 -1
  139. streamlit/static/static/js/{index.CWgnk1N4.js → index.PR2mcvVR.js} +1 -1
  140. streamlit/static/static/js/{index.CJ-XXd1r.js → index.df4uuSoD.js} +1 -1
  141. streamlit/static/static/js/{index.WWYmGCrM.js → index.flyQEkeT.js} +1 -1
  142. streamlit/static/static/js/{index.vOqxh1m2.js → index.iF9jUtwl.js} +1 -1
  143. streamlit/static/static/js/{index.C5KKmyWy.js → index.jyqBAhvH.js} +1 -1
  144. streamlit/static/static/js/{index.AWkO-7e-.js → index.sYLAHlH0.js} +1 -1
  145. streamlit/static/static/js/{index.CZ5fZcT5.js → index.zq3LdRhj.js} +1 -1
  146. streamlit/static/static/js/{input.BvD9DHLa.js → input.CtZjQ6Pv.js} +1 -1
  147. streamlit/static/static/js/{memory.DCVB1HOm.js → memory.Ddl3R0up.js} +1 -1
  148. streamlit/static/static/js/{mergeWith.BqTORFAq.js → mergeWith.D-TqDY0-.js} +1 -1
  149. streamlit/static/static/js/{number-overlay-editor.VB_OvuPv.js → number-overlay-editor.Dndf05Hx.js} +1 -1
  150. streamlit/static/static/js/{possibleConstructorReturn.DhYxBDlj.js → possibleConstructorReturn.DNEY6J9G.js} +1 -1
  151. streamlit/static/static/js/{sandbox.CoN7LRFk.js → sandbox.B_XDPkfx.js} +1 -1
  152. streamlit/static/static/js/{textarea.DkHpIjdT.js → textarea.BZ9lTMhV.js} +1 -1
  153. streamlit/static/static/js/{timepicker.C8UIzYhf.js → timepicker.D9UUwpRT.js} +1 -1
  154. streamlit/static/static/js/{toConsumableArray.DXfr1fvT.js → toConsumableArray.DNJjbOUS.js} +1 -1
  155. streamlit/static/static/js/{uniqueId.CgrMSBTb.js → uniqueId.psBJ_tSg.js} +1 -1
  156. streamlit/static/static/js/{useBasicWidgetState.C-e-WEFS.js → useBasicWidgetState.CTpx4w-3.js} +1 -1
  157. streamlit/static/static/js/{useOnInputChange.CtRJhZD6.js → useOnInputChange.WKTDSC4O.js} +1 -1
  158. streamlit/static/static/js/{withFullScreenWrapper.od0SAvAK.js → withFullScreenWrapper.oyWCn2-3.js} +1 -1
  159. streamlit/watcher/local_sources_watcher.py +1 -1
  160. streamlit/watcher/path_watcher.py +2 -3
  161. streamlit/web/bootstrap.py +1 -1
  162. streamlit/web/cli.py +5 -5
  163. streamlit/web/server/authlib_tornado_integration.py +3 -3
  164. streamlit/web/server/oauth_authlib_routes.py +4 -2
  165. streamlit/web/server/oidc_mixin.py +6 -5
  166. streamlit/web/server/server.py +1 -1
  167. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250530.dist-info}/METADATA +2 -2
  168. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250530.dist-info}/RECORD +172 -171
  169. streamlit/static/static/js/index.B0E6Rv1F.js +0 -1
  170. streamlit/static/static/js/index.BONHiJUZ.js +0 -1
  171. streamlit/static/static/js/index.BV38yp5k.js +0 -1
  172. streamlit/static/static/js/index.CgOynO1t.js +0 -1
  173. streamlit/static/static/js/index.DIyx-z1Q.js +0 -1
  174. streamlit/static/static/js/index.DOYomqqU.js +0 -1
  175. streamlit/static/static/js/index.DOl-SOKu.js +0 -3
  176. streamlit/static/static/js/index.DTU7qmDP.js +0 -12
  177. {streamlit_nightly-1.45.2.dev20250527.data → streamlit_nightly-1.45.2.dev20250530.data}/scripts/streamlit.cmd +0 -0
  178. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250530.dist-info}/WHEEL +0 -0
  179. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250530.dist-info}/entry_points.txt +0 -0
  180. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250530.dist-info}/top_level.txt +0 -0
@@ -15,6 +15,60 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import contextlib
18
+ from typing import Final
19
+
20
+ # This is the streamlit theme for plotly where we pass in a template.data
21
+ # and a template.layout.
22
+ # Template.data is for changing specific graph properties in a general aspect
23
+ # such as Contour plots or Waterfall plots.
24
+ # Template.layout is for changing things such as the x axis and fonts and other
25
+ # general layout properties for general graphs.
26
+ # We pass in temporary colors to the frontend and the frontend will replace
27
+ # those colors because we want to change colors based on the background color.
28
+ # Start at #0000001 because developers may be likely to use #000000
29
+ CATEGORY_0: Final = "#000001"
30
+ CATEGORY_1: Final = "#000002"
31
+ CATEGORY_2: Final = "#000003"
32
+ CATEGORY_3: Final = "#000004"
33
+ CATEGORY_4: Final = "#000005"
34
+ CATEGORY_5: Final = "#000006"
35
+ CATEGORY_6: Final = "#000007"
36
+ CATEGORY_7: Final = "#000008"
37
+ CATEGORY_8: Final = "#000009"
38
+ CATEGORY_9: Final = "#000010"
39
+
40
+ SEQUENTIAL_0: Final = "#000011"
41
+ SEQUENTIAL_1: Final = "#000012"
42
+ SEQUENTIAL_2: Final = "#000013"
43
+ SEQUENTIAL_3: Final = "#000014"
44
+ SEQUENTIAL_4: Final = "#000015"
45
+ SEQUENTIAL_5: Final = "#000016"
46
+ SEQUENTIAL_6: Final = "#000017"
47
+ SEQUENTIAL_7: Final = "#000018"
48
+ SEQUENTIAL_8: Final = "#000019"
49
+ SEQUENTIAL_9: Final = "#000020"
50
+
51
+ DIVERGING_0: Final = "#000021"
52
+ DIVERGING_1: Final = "#000022"
53
+ DIVERGING_2: Final = "#000023"
54
+ DIVERGING_3: Final = "#000024"
55
+ DIVERGING_4: Final = "#000025"
56
+ DIVERGING_5: Final = "#000026"
57
+ DIVERGING_6: Final = "#000027"
58
+ DIVERGING_7: Final = "#000028"
59
+ DIVERGING_8: Final = "#000029"
60
+ DIVERGING_9: Final = "#000030"
61
+ DIVERGING_10: Final = "#000031"
62
+
63
+ INCREASING: Final = "#000032"
64
+ DECREASING: Final = "#000033"
65
+ TOTAL: Final = "#000034"
66
+
67
+ GRAY_70: Final = "#000036"
68
+ GRAY_90: Final = "#000037"
69
+ BG_COLOR: Final = "#000038"
70
+ FADED_TEXT_05: Final = "#000039"
71
+ BG_MIX: Final = "#000040"
18
72
 
19
73
 
20
74
  def configure_streamlit_plotly_theme() -> None:
@@ -27,59 +81,6 @@ def configure_streamlit_plotly_theme() -> None:
27
81
  import plotly.graph_objects as go
28
82
  import plotly.io as pio
29
83
 
30
- # This is the streamlit theme for plotly where we pass in a template.data
31
- # and a template.layout.
32
- # Template.data is for changing specific graph properties in a general aspect
33
- # such as Contour plots or Waterfall plots.
34
- # Template.layout is for changing things such as the x axis and fonts and other
35
- # general layout properties for general graphs.
36
- # We pass in temporary colors to the frontend and the frontend will replace
37
- # those colors because we want to change colors based on the background color.
38
- # Start at #0000001 because developers may be likely to use #000000
39
- CATEGORY_0 = "#000001"
40
- CATEGORY_1 = "#000002"
41
- CATEGORY_2 = "#000003"
42
- CATEGORY_3 = "#000004"
43
- CATEGORY_4 = "#000005"
44
- CATEGORY_5 = "#000006"
45
- CATEGORY_6 = "#000007"
46
- CATEGORY_7 = "#000008"
47
- CATEGORY_8 = "#000009"
48
- CATEGORY_9 = "#000010"
49
-
50
- SEQUENTIAL_0 = "#000011"
51
- SEQUENTIAL_1 = "#000012"
52
- SEQUENTIAL_2 = "#000013"
53
- SEQUENTIAL_3 = "#000014"
54
- SEQUENTIAL_4 = "#000015"
55
- SEQUENTIAL_5 = "#000016"
56
- SEQUENTIAL_6 = "#000017"
57
- SEQUENTIAL_7 = "#000018"
58
- SEQUENTIAL_8 = "#000019"
59
- SEQUENTIAL_9 = "#000020"
60
-
61
- DIVERGING_0 = "#000021"
62
- DIVERGING_1 = "#000022"
63
- DIVERGING_2 = "#000023"
64
- DIVERGING_3 = "#000024"
65
- DIVERGING_4 = "#000025"
66
- DIVERGING_5 = "#000026"
67
- DIVERGING_6 = "#000027"
68
- DIVERGING_7 = "#000028"
69
- DIVERGING_8 = "#000029"
70
- DIVERGING_9 = "#000030"
71
- DIVERGING_10 = "#000031"
72
-
73
- INCREASING = "#000032"
74
- DECREASING = "#000033"
75
- TOTAL = "#000034"
76
-
77
- GRAY_70 = "#000036"
78
- GRAY_90 = "#000037"
79
- BG_COLOR = "#000038"
80
- FADED_TEXT_05 = "#000039"
81
- BG_MIX = "#000040"
82
-
83
84
  # Plotly represents continuous colorscale through an array of pairs.
84
85
  # The pair's first index is the starting point and the next pair's first index is the end point.
85
86
  # The pair's second index is the starting color and the next pair's second index is the end color.
@@ -31,6 +31,7 @@ from streamlit import config
31
31
  from streamlit.errors import StreamlitDuplicateElementId, StreamlitDuplicateElementKey
32
32
  from streamlit.proto.ChatInput_pb2 import ChatInput
33
33
  from streamlit.proto.LabelVisibilityMessage_pb2 import LabelVisibilityMessage
34
+ from streamlit.proto.RootContainer_pb2 import RootContainer
34
35
  from streamlit.runtime.scriptrunner_utils.script_run_context import (
35
36
  ScriptRunContext,
36
37
  get_script_run_ctx,
@@ -45,6 +46,8 @@ if TYPE_CHECKING:
45
46
  from builtins import ellipsis
46
47
  from collections.abc import Iterable
47
48
 
49
+ from streamlit.delta_generator import DeltaGenerator
50
+
48
51
 
49
52
  Key: TypeAlias = Union[str, int]
50
53
 
@@ -182,6 +185,7 @@ def compute_and_register_element_id(
182
185
  *,
183
186
  user_key: str | None,
184
187
  form_id: str | None,
188
+ dg: DeltaGenerator | None = None,
185
189
  **kwargs: SAFE_VALUES | Iterable[SAFE_VALUES],
186
190
  ) -> str:
187
191
  """Compute and register the ID for the given element.
@@ -212,6 +216,9 @@ def compute_and_register_element_id(
212
216
  The ID of the form that the element belongs to. `None` or empty string
213
217
  if the element doesn't belong to a form or doesn't support forms.
214
218
 
219
+ dg : DeltaGenerator | None
220
+ The DeltaGenerator of each element. `None` if the element is not a widget.
221
+
215
222
  kwargs : SAFE_VALUES | Iterable[SAFE_VALUES]
216
223
  The arguments to use to compute the element ID.
217
224
  The arguments must be stable, deterministic values.
@@ -229,6 +236,14 @@ def compute_and_register_element_id(
229
236
  # pages unique IDs.
230
237
  kwargs_to_use["active_script_hash"] = ctx.active_script_hash
231
238
 
239
+ if dg:
240
+ # If no key is provided and the widget element is inside the sidebar area
241
+ # add it to the kwargs
242
+ # allowing the same widget to be both in main area and sidebar.
243
+ active_dg_root_container = dg._active_dg._root_container
244
+ if active_dg_root_container == RootContainer.SIDEBAR and user_key is None:
245
+ kwargs_to_use["active_dg_root_container"] = str(active_dg_root_container)
246
+
232
247
  element_id = _compute_element_id(
233
248
  element_type,
234
249
  user_key,
@@ -16,6 +16,12 @@ from __future__ import annotations
16
16
 
17
17
  from typing import TYPE_CHECKING, Final, Literal, cast
18
18
 
19
+ from streamlit.elements.lib.layout_utils import (
20
+ LayoutConfig,
21
+ Width,
22
+ WidthWithoutContent,
23
+ validate_width,
24
+ )
19
25
  from streamlit.proto.Markdown_pb2 import Markdown as MarkdownProto
20
26
  from streamlit.runtime.metrics_util import gather_metrics
21
27
  from streamlit.string_util import clean_text, validate_icon_or_emoji
@@ -212,6 +218,7 @@ class MarkdownMixin:
212
218
  body: SupportsStr | sympy.Expr,
213
219
  *, # keyword-only arguments:
214
220
  help: str | None = None,
221
+ width: Width = "stretch",
215
222
  ) -> DeltaGenerator:
216
223
  # This docstring needs to be "raw" because of the backslashes in the
217
224
  # example below.
@@ -235,6 +242,12 @@ class MarkdownMixin:
235
242
  including the Markdown directives described in the ``body``
236
243
  parameter of ``st.markdown``.
237
244
 
245
+ width : int or "stretch" or "content"
246
+ The width of the LaTeX expression. If "stretch" (default), the
247
+ expression will take up the full width of the container. If "content",
248
+ the expression will take up only as much width as needed. If an integer,
249
+ the width will be set to that number of pixels.
250
+
238
251
  Example
239
252
  -------
240
253
  >>> import streamlit as st
@@ -246,22 +259,34 @@ class MarkdownMixin:
246
259
  ... ''')
247
260
 
248
261
  """
262
+
249
263
  if is_sympy_expression(body):
250
264
  import sympy
251
265
 
252
266
  body = sympy.latex(body)
253
267
 
254
268
  latex_proto = MarkdownProto()
255
- latex_proto.body = "$$\n%s\n$$" % clean_text(body)
269
+ latex_proto.body = f"$$\n{clean_text(body)}\n$$"
256
270
  latex_proto.element_type = MarkdownProto.Type.LATEX
257
271
  if help:
258
272
  latex_proto.help = help
259
- return self.dg._enqueue("markdown", latex_proto)
273
+
274
+ validate_width(width, allow_content=True)
275
+ layout_config = LayoutConfig(width=width)
276
+
277
+ return self.dg._enqueue("markdown", latex_proto, layout_config=layout_config)
260
278
 
261
279
  @gather_metrics("divider")
262
- def divider(self) -> DeltaGenerator:
280
+ def divider(self, *, width: WidthWithoutContent = "stretch") -> DeltaGenerator:
263
281
  """Display a horizontal rule.
264
282
 
283
+ Parameters
284
+ ----------
285
+ width : int or "stretch"
286
+ The width of the divider. If "stretch" (default), the divider will
287
+ take up the full width of the container. If an integer, the width
288
+ will be set to that number of pixels.
289
+
265
290
  .. note::
266
291
  You can achieve the same effect with st.write("---") or
267
292
  even just "---" in your script (via magic).
@@ -273,10 +298,15 @@ class MarkdownMixin:
273
298
  >>> st.divider()
274
299
 
275
300
  """
301
+
276
302
  divider_proto = MarkdownProto()
277
303
  divider_proto.body = MARKDOWN_HORIZONTAL_RULE_EXPRESSION
278
304
  divider_proto.element_type = MarkdownProto.Type.DIVIDER
279
- return self.dg._enqueue("markdown", divider_proto)
305
+
306
+ validate_width(width, allow_content=False)
307
+ layout_config = LayoutConfig(width=width)
308
+
309
+ return self.dg._enqueue("markdown", divider_proto, layout_config=layout_config)
280
310
 
281
311
  @gather_metrics("badge")
282
312
  def badge(
@@ -478,7 +478,7 @@ def _marshall_av_media(
478
478
  elif type_util.is_type(data, "numpy.ndarray"):
479
479
  data_or_filename = cast("npt.NDArray[Any]", data).tobytes()
480
480
  else:
481
- raise RuntimeError("Invalid binary data format: %s" % type(data))
481
+ raise RuntimeError(f"Invalid binary data format: {type(data)}")
482
482
 
483
483
  if runtime.exists():
484
484
  file_url = runtime.get_instance().media_file_mgr.add(
@@ -510,6 +510,7 @@ class PlotlyMixin:
510
510
  "plotly_chart",
511
511
  user_key=key,
512
512
  form_id=plotly_chart_proto.form_id,
513
+ dg=self.dg,
513
514
  plotly_spec=plotly_chart_proto.spec,
514
515
  plotly_config=plotly_chart_proto.config,
515
516
  selection_mode=selection_mode,
@@ -19,10 +19,9 @@ from typing import TYPE_CHECKING, Union, cast
19
19
 
20
20
  from typing_extensions import TypeAlias
21
21
 
22
- from streamlit.elements.lib.layout_utils import validate_width
22
+ from streamlit.elements.lib.layout_utils import LayoutConfig, validate_width
23
23
  from streamlit.errors import StreamlitAPIException
24
24
  from streamlit.proto.Progress_pb2 import Progress as ProgressProto
25
- from streamlit.proto.WidthConfig_pb2 import WidthConfig
26
25
  from streamlit.string_util import clean_text
27
26
 
28
27
  if TYPE_CHECKING:
@@ -66,17 +65,17 @@ def _get_value(value: FloatOrInt) -> int:
66
65
  if 0 <= value <= 100:
67
66
  return value
68
67
  raise StreamlitAPIException(
69
- "Progress Value has invalid value [0, 100]: %d" % value
68
+ f"Progress Value has invalid value [0, 100]: {value}"
70
69
  )
71
70
 
72
71
  if isinstance(value, float):
73
72
  if _check_float_between(value, low=0.0, high=1.0):
74
73
  return int(value * 100)
75
74
  raise StreamlitAPIException(
76
- "Progress Value has invalid value [0.0, 1.0]: %f" % value
75
+ f"Progress Value has invalid value [0.0, 1.0]: {value}"
77
76
  )
78
77
  raise StreamlitAPIException(
79
- "Progress Value has invalid type: %s" % type(value).__name__
78
+ f"Progress Value has invalid type: {type(value).__name__}"
80
79
  )
81
80
 
82
81
 
@@ -158,18 +157,10 @@ class ProgressMixin:
158
157
  if text is not None:
159
158
  progress_proto.text = text
160
159
 
161
- width_config = WidthConfig()
162
-
163
160
  validate_width(width)
161
+ layout_config = LayoutConfig(width=width)
164
162
 
165
- if isinstance(width, int):
166
- width_config.pixel_width = width
167
- else:
168
- width_config.use_stretch = True
169
-
170
- progress_proto.width_config.CopyFrom(width_config)
171
-
172
- return self.dg._enqueue("progress", progress_proto)
163
+ return self.dg._enqueue("progress", progress_proto, layout_config=layout_config)
173
164
 
174
165
  @property
175
166
  def dg(self) -> DeltaGenerator:
@@ -16,7 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  import contextlib
18
18
  import threading
19
- from typing import TYPE_CHECKING
19
+ from typing import TYPE_CHECKING, Final
20
20
 
21
21
  import streamlit as st
22
22
  from streamlit.runtime.scriptrunner import add_script_run_ctx
@@ -24,6 +24,10 @@ from streamlit.runtime.scriptrunner import add_script_run_ctx
24
24
  if TYPE_CHECKING:
25
25
  from collections.abc import Iterator
26
26
 
27
+ # Set the message 0.5 seconds in the future to avoid annoying
28
+ # flickering if this spinner runs too quickly.
29
+ DELAY_SECS: Final = 0.5
30
+
27
31
 
28
32
  @contextlib.contextmanager
29
33
  def spinner(
@@ -75,9 +79,6 @@ def spinner(
75
79
 
76
80
  message = st.empty()
77
81
 
78
- # Set the message 0.5 seconds in the future to avoid annoying
79
- # flickering if this spinner runs too quickly.
80
- DELAY_SECS = 0.5
81
82
  display_message = True
82
83
  display_message_lock = threading.Lock()
83
84
 
@@ -1947,6 +1947,7 @@ class VegaChartsMixin:
1947
1947
  "arrow_vega_lite_chart",
1948
1948
  user_key=key,
1949
1949
  form_id=vega_lite_proto.form_id,
1950
+ dg=self.dg,
1950
1951
  vega_lite_spec=vega_lite_proto.spec,
1951
1952
  # The data is either in vega_lite_proto.data.data
1952
1953
  # or in a named dataset in vega_lite_proto.datasets
@@ -22,7 +22,7 @@ from typing_extensions import TypeAlias
22
22
 
23
23
  from streamlit.elements.lib.file_uploader_utils import enforce_filename_restriction
24
24
  from streamlit.elements.lib.form_utils import current_form_id
25
- from streamlit.elements.lib.layout_utils import validate_width
25
+ from streamlit.elements.lib.layout_utils import LayoutConfig, validate_width
26
26
  from streamlit.elements.lib.policies import (
27
27
  check_widget_policies,
28
28
  maybe_raise_label_warnings,
@@ -38,7 +38,6 @@ from streamlit.elements.widgets.file_uploader import _get_upload_files
38
38
  from streamlit.proto.AudioInput_pb2 import AudioInput as AudioInputProto
39
39
  from streamlit.proto.Common_pb2 import FileUploaderState as FileUploaderStateProto
40
40
  from streamlit.proto.Common_pb2 import UploadedFileInfo as UploadedFileInfoProto
41
- from streamlit.proto.WidthConfig_pb2 import WidthConfig
42
41
  from streamlit.runtime.metrics_util import gather_metrics
43
42
  from streamlit.runtime.scriptrunner import ScriptRunContext, get_script_run_ctx
44
43
  from streamlit.runtime.state import (
@@ -236,6 +235,7 @@ class AudioInputMixin:
236
235
  "audio_input",
237
236
  user_key=key,
238
237
  form_id=current_form_id(self.dg),
238
+ dg=self.dg,
239
239
  label=label,
240
240
  help=help,
241
241
  width=width,
@@ -253,14 +253,8 @@ class AudioInputMixin:
253
253
  if label and help is not None:
254
254
  audio_input_proto.help = dedent(help)
255
255
 
256
- # Set width configuration
257
256
  validate_width(width)
258
- width_config = WidthConfig()
259
- if isinstance(width, int):
260
- width_config.pixel_width = width
261
- else:
262
- width_config.use_stretch = True
263
- audio_input_proto.width_config.CopyFrom(width_config)
257
+ layout_config = LayoutConfig(width=width)
264
258
 
265
259
  serde = AudioInputSerde()
266
260
 
@@ -275,7 +269,7 @@ class AudioInputMixin:
275
269
  value_type="file_uploader_state_value",
276
270
  )
277
271
 
278
- self.dg._enqueue("audio_input", audio_input_proto)
272
+ self.dg._enqueue("audio_input", audio_input_proto, layout_config=layout_config)
279
273
 
280
274
  if isinstance(audio_input_state.value, DeletedFile):
281
275
  return None
@@ -818,6 +818,7 @@ class ButtonMixin:
818
818
  user_key=key,
819
819
  # download_button is not allowed to be used in a form.
820
820
  form_id=None,
821
+ dg=self.dg,
821
822
  label=label,
822
823
  icon=icon,
823
824
  file_name=file_name,
@@ -1009,6 +1010,7 @@ class ButtonMixin:
1009
1010
  user_key=key,
1010
1011
  # Only the
1011
1012
  form_id=form_id,
1013
+ dg=self.dg,
1012
1014
  label=label,
1013
1015
  icon=icon,
1014
1016
  help=help,
@@ -1105,7 +1107,7 @@ def marshall_file(
1105
1107
  data_as_bytes = data.read() or b""
1106
1108
  mimetype = mimetype or "application/octet-stream"
1107
1109
  else:
1108
- raise StreamlitAPIException("Invalid binary data format: %s" % type(data))
1110
+ raise StreamlitAPIException(f"Invalid binary data format: {type(data)}")
1109
1111
 
1110
1112
  if runtime.exists():
1111
1113
  file_url = runtime.get_instance().media_file_mgr.add(
@@ -984,6 +984,7 @@ class ButtonGroupMixin:
984
984
  widget_name,
985
985
  user_key=key,
986
986
  form_id=form_id,
987
+ dg=self.dg,
987
988
  options=formatted_options,
988
989
  default=default,
989
990
  click_mode=parsed_selection_mode,
@@ -22,7 +22,7 @@ from typing_extensions import TypeAlias
22
22
 
23
23
  from streamlit.elements.lib.file_uploader_utils import enforce_filename_restriction
24
24
  from streamlit.elements.lib.form_utils import current_form_id
25
- from streamlit.elements.lib.layout_utils import validate_width
25
+ from streamlit.elements.lib.layout_utils import LayoutConfig, validate_width
26
26
  from streamlit.elements.lib.policies import (
27
27
  check_widget_policies,
28
28
  maybe_raise_label_warnings,
@@ -38,7 +38,6 @@ from streamlit.elements.widgets.file_uploader import _get_upload_files
38
38
  from streamlit.proto.CameraInput_pb2 import CameraInput as CameraInputProto
39
39
  from streamlit.proto.Common_pb2 import FileUploaderState as FileUploaderStateProto
40
40
  from streamlit.proto.Common_pb2 import UploadedFileInfo as UploadedFileInfoProto
41
- from streamlit.proto.WidthConfig_pb2 import WidthConfig
42
41
  from streamlit.runtime.metrics_util import gather_metrics
43
42
  from streamlit.runtime.scriptrunner import ScriptRunContext, get_script_run_ctx
44
43
  from streamlit.runtime.state import (
@@ -230,6 +229,7 @@ class CameraInputMixin:
230
229
  "camera_input",
231
230
  user_key=key,
232
231
  form_id=current_form_id(self.dg),
232
+ dg=self.dg,
233
233
  label=label,
234
234
  help=help,
235
235
  width=width,
@@ -248,12 +248,7 @@ class CameraInputMixin:
248
248
  camera_input_proto.help = dedent(help)
249
249
 
250
250
  validate_width(width)
251
- width_config = WidthConfig()
252
- if isinstance(width, int):
253
- width_config.pixel_width = width
254
- else:
255
- width_config.use_stretch = True
256
- camera_input_proto.width_config.CopyFrom(width_config)
251
+ layout_config = LayoutConfig(width=width)
257
252
 
258
253
  serde = CameraInputSerde()
259
254
 
@@ -268,7 +263,9 @@ class CameraInputMixin:
268
263
  value_type="file_uploader_state_value",
269
264
  )
270
265
 
271
- self.dg._enqueue("camera_input", camera_input_proto)
266
+ self.dg._enqueue(
267
+ "camera_input", camera_input_proto, layout_config=layout_config
268
+ )
272
269
 
273
270
  if isinstance(camera_input_state.value, DeletedFile):
274
271
  return None
@@ -34,6 +34,7 @@ from streamlit.elements.lib.file_uploader_utils import (
34
34
  from streamlit.elements.lib.form_utils import is_in_form
35
35
  from streamlit.elements.lib.image_utils import AtomicImage, WidthBehavior, image_to_url
36
36
  from streamlit.elements.lib.layout_utils import (
37
+ LayoutConfig,
37
38
  Width,
38
39
  WidthWithoutContent,
39
40
  validate_width,
@@ -123,7 +124,7 @@ def _process_avatar_input(
123
124
  Tuple[AvatarType, str]
124
125
  The detected avatar type and the prepared avatar data.
125
126
  """
126
- AvatarType = BlockProto.ChatMessage.AvatarType
127
+ AvatarType = BlockProto.ChatMessage.AvatarType # noqa: N806
127
128
 
128
129
  if avatar is None:
129
130
  return AvatarType.ICON, ""
@@ -350,11 +351,11 @@ class ChatMixin:
350
351
  width_config.use_content = True
351
352
  else:
352
353
  width_config.use_stretch = True
353
- message_container_proto.width_config.CopyFrom(width_config)
354
354
 
355
355
  block_proto = BlockProto()
356
356
  block_proto.allow_empty = True
357
357
  block_proto.chat_message.CopyFrom(message_container_proto)
358
+ block_proto.width_config.CopyFrom(width_config)
358
359
 
359
360
  return self.dg._block(block_proto=block_proto)
360
361
 
@@ -582,8 +583,6 @@ class ChatMixin:
582
583
  writes_allowed=False,
583
584
  )
584
585
 
585
- validate_width(width)
586
-
587
586
  if accept_file not in {True, False, "multiple"}:
588
587
  raise StreamlitAPIException(
589
588
  "The `accept_file` parameter must be a boolean or 'multiple'."
@@ -596,6 +595,7 @@ class ChatMixin:
596
595
  user_key=key,
597
596
  # chat_input is not allowed to be used in a form.
598
597
  form_id=None,
598
+ dg=self.dg,
599
599
  placeholder=placeholder,
600
600
  max_chars=max_chars,
601
601
  accept_file=accept_file,
@@ -644,13 +644,6 @@ class ChatMixin:
644
644
  chat_input_proto.file_type[:] = file_type if file_type is not None else []
645
645
  chat_input_proto.max_upload_size_mb = config.get_option("server.maxUploadSize")
646
646
 
647
- width_config = WidthConfig()
648
- if isinstance(width, int):
649
- width_config.pixel_width = width
650
- else:
651
- width_config.use_stretch = True
652
- chat_input_proto.width_config.CopyFrom(width_config)
653
-
654
647
  serde = ChatInputSerde(
655
648
  accept_files=bool(accept_file),
656
649
  allowed_types=file_type,
@@ -666,6 +659,9 @@ class ChatMixin:
666
659
  value_type="chat_input_value",
667
660
  )
668
661
 
662
+ validate_width(width)
663
+ layout_config = LayoutConfig(width=width)
664
+
669
665
  chat_input_proto.disabled = disabled
670
666
  if widget_state.value_changed and widget_state.value is not None:
671
667
  chat_input_proto.value = widget_state.value
@@ -677,10 +673,12 @@ class ChatMixin:
677
673
  # We need to enqueue the chat input into the bottom container
678
674
  # instead of the currently active dg.
679
675
  get_dg_singleton_instance().bottom_dg._enqueue(
680
- "chat_input", chat_input_proto
676
+ "chat_input", chat_input_proto, layout_config=layout_config
681
677
  )
682
678
  else:
683
- self.dg._enqueue("chat_input", chat_input_proto)
679
+ self.dg._enqueue(
680
+ "chat_input", chat_input_proto, layout_config=layout_config
681
+ )
684
682
 
685
683
  return widget_state.value if not widget_state.value_changed else None
686
684
 
@@ -307,6 +307,7 @@ class CheckboxMixin:
307
307
  "toggle" if type == CheckboxProto.StyleType.TOGGLE else "checkbox",
308
308
  user_key=key,
309
309
  form_id=current_form_id(self.dg),
310
+ dg=self.dg,
310
311
  label=label,
311
312
  value=bool(value),
312
313
  help=help,
@@ -195,6 +195,7 @@ class ColorPickerMixin:
195
195
  "color_picker",
196
196
  user_key=key,
197
197
  form_id=current_form_id(self.dg),
198
+ dg=self.dg,
198
199
  label=label,
199
200
  value=str(value),
200
201
  help=help,
@@ -206,25 +207,19 @@ class ColorPickerMixin:
206
207
 
207
208
  # make sure the value is a string
208
209
  if not isinstance(value, str):
209
- raise StreamlitAPIException(
210
- """
211
- Color Picker Value has invalid type: %s. Expects a hex string
212
- like '#00FFAA' or '#000'.
213
- """
214
- % type(value).__name__
215
- )
210
+ raise StreamlitAPIException(f"""
211
+ Color Picker Value has invalid type: {type(value).__name__}. Expects a hex string
212
+ like '#00FFAA' or '#000'.
213
+ """)
216
214
 
217
215
  # validate the value and expects a hex string
218
216
  match = re.match(r"^#(?:[0-9a-fA-F]{3}){1,2}$", value)
219
217
 
220
218
  if not match:
221
- raise StreamlitAPIException(
222
- """
223
- '%s' is not a valid hex code for colors. Valid ones are like
224
- '#00FFAA' or '#000'.
225
- """
226
- % value
227
- )
219
+ raise StreamlitAPIException(f"""
220
+ '{value}' is not a valid hex code for colors. Valid ones are like
221
+ '#00FFAA' or '#000'.
222
+ """)
228
223
 
229
224
  color_picker_proto = ColorPickerProto()
230
225
  color_picker_proto.id = element_id