streamlit 1.47.0__py3-none-any.whl → 1.48.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 (189) hide show
  1. streamlit/cli_util.py +1 -1
  2. streamlit/commands/echo.py +2 -2
  3. streamlit/commands/execution_control.py +1 -1
  4. streamlit/commands/page_config.py +16 -16
  5. streamlit/components/v1/component_arrow.py +4 -4
  6. streamlit/config.py +23 -5
  7. streamlit/connections/base_connection.py +2 -2
  8. streamlit/connections/snowflake_connection.py +2 -2
  9. streamlit/connections/sql_connection.py +4 -3
  10. streamlit/dataframe_util.py +1 -1
  11. streamlit/deprecation_util.py +20 -5
  12. streamlit/elements/arrow.py +105 -79
  13. streamlit/elements/deck_gl_json_chart.py +6 -6
  14. streamlit/elements/dialog_decorator.py +72 -17
  15. streamlit/elements/form.py +36 -7
  16. streamlit/elements/graphviz_chart.py +7 -0
  17. streamlit/elements/json.py +3 -3
  18. streamlit/elements/layouts.py +241 -75
  19. streamlit/elements/lib/built_in_chart_utils.py +11 -3
  20. streamlit/elements/lib/dialog.py +43 -0
  21. streamlit/elements/lib/file_uploader_utils.py +21 -2
  22. streamlit/elements/lib/layout_utils.py +88 -2
  23. streamlit/elements/lib/options_selector_utils.py +1 -1
  24. streamlit/elements/lib/utils.py +23 -3
  25. streamlit/elements/map.py +12 -11
  26. streamlit/elements/plotly_chart.py +21 -21
  27. streamlit/elements/pyplot.py +8 -4
  28. streamlit/elements/vega_charts.py +237 -143
  29. streamlit/elements/widgets/audio_input.py +2 -2
  30. streamlit/elements/widgets/button.py +147 -35
  31. streamlit/elements/widgets/button_group.py +9 -8
  32. streamlit/elements/widgets/camera_input.py +2 -2
  33. streamlit/elements/widgets/chat.py +8 -2
  34. streamlit/elements/widgets/checkbox.py +4 -4
  35. streamlit/elements/widgets/color_picker.py +2 -2
  36. streamlit/elements/widgets/data_editor.py +22 -15
  37. streamlit/elements/widgets/file_uploader.py +8 -2
  38. streamlit/elements/widgets/multiselect.py +27 -17
  39. streamlit/elements/widgets/number_input.py +2 -2
  40. streamlit/elements/widgets/radio.py +5 -4
  41. streamlit/elements/widgets/select_slider.py +8 -5
  42. streamlit/elements/widgets/selectbox.py +14 -4
  43. streamlit/elements/widgets/slider.py +59 -33
  44. streamlit/elements/widgets/text_widgets.py +4 -4
  45. streamlit/elements/widgets/time_widgets.py +4 -4
  46. streamlit/elements/write.py +9 -8
  47. streamlit/env_util.py +1 -1
  48. streamlit/errors.py +20 -4
  49. streamlit/file_util.py +1 -1
  50. streamlit/git_util.py +1 -1
  51. streamlit/logger.py +2 -2
  52. streamlit/proto/Block_pb2.py +39 -31
  53. streamlit/proto/Block_pb2.pyi +54 -3
  54. streamlit/proto/Button_pb2.py +4 -2
  55. streamlit/proto/Button_pb2.pyi +1 -0
  56. streamlit/runtime/caching/cache_data_api.py +15 -2
  57. streamlit/runtime/caching/cache_errors.py +1 -1
  58. streamlit/runtime/caching/cache_resource_api.py +24 -2
  59. streamlit/runtime/caching/cache_utils.py +6 -3
  60. streamlit/runtime/caching/hashing.py +6 -9
  61. streamlit/runtime/fragment.py +3 -2
  62. streamlit/runtime/runtime.py +19 -2
  63. streamlit/runtime/scriptrunner/script_runner.py +3 -3
  64. streamlit/runtime/state/common.py +2 -1
  65. streamlit/runtime/state/query_params.py +2 -1
  66. streamlit/runtime/state/session_state.py +1 -1
  67. streamlit/static/index.html +1 -1
  68. streamlit/static/manifest.json +231 -231
  69. streamlit/static/static/css/index.CQt5TjGB.css +1 -0
  70. streamlit/static/static/js/{ErrorOutline.esm.bg5MMAri.js → ErrorOutline.esm.D_4oFNKB.js} +1 -1
  71. streamlit/static/static/js/{FileDownload.esm.ZD5PIl3I.js → FileDownload.esm.NPgaLlUE.js} +1 -1
  72. streamlit/static/static/js/{FileHelper.B6jszxAn.js → FileHelper.B2t9ikoS.js} +1 -1
  73. streamlit/static/static/js/{FormClearHelper.DuzI-rET.js → FormClearHelper.BLEIUk6L.js} +1 -1
  74. streamlit/static/static/js/{Hooks.qKXFrFZm.js → Hooks.BGm9sd4U.js} +1 -1
  75. streamlit/static/static/js/{InputInstructions.7NdlV9ze.js → InputInstructions.DtUxCBS8.js} +1 -1
  76. streamlit/static/static/js/Particles.BDRPO7r3.js +1 -0
  77. streamlit/static/static/js/ProgressBar.B64DUUqp.js +2 -0
  78. streamlit/static/static/js/Toolbar.B3FquPk5.js +1 -0
  79. streamlit/static/static/js/{base-input.Dl5fJ2xw.js → base-input.DeBqm5mN.js} +4 -4
  80. streamlit/static/static/js/{checkbox.DCoT7yTn.js → checkbox.C0odQfKb.js} +2 -2
  81. streamlit/static/static/js/createDownloadLinkElement.ZaXNnPK4.js +1 -0
  82. streamlit/static/static/js/{createSuper.DIDXPRra.js → createSuper.DqQ5L3XG.js} +1 -1
  83. streamlit/static/static/js/data-grid-overlay-editor.DbNsQa8Y.js +1 -0
  84. streamlit/static/static/js/{downloader.DKv2kGmf.js → downloader.Bx1D0jhz.js} +1 -1
  85. streamlit/static/static/js/{es6.JcohG4tM.js → es6.CbPK4m0H.js} +2 -2
  86. streamlit/static/static/js/{iframeResizer.contentWindow.3rtAterA.js → iframeResizer.contentWindow.CfLKrptA.js} +1 -1
  87. streamlit/static/static/js/{index.BO22lkaO.js → index.0XDwe9RV.js} +12 -12
  88. streamlit/static/static/js/{index.Wj4EUfiO.js → index.4lI9TuZm.js} +3 -3
  89. streamlit/static/static/js/index.6s0nVIis.js +3855 -0
  90. streamlit/static/static/js/index.9E7bRUBU.js +1 -0
  91. streamlit/static/static/js/index.B9PgeLrZ.js +1 -0
  92. streamlit/static/static/js/index.B9vzGbOt.js +1 -0
  93. streamlit/static/static/js/index.BDrQKMCm.js +1 -0
  94. streamlit/static/static/js/index.BPsoiGgP.js +1 -0
  95. streamlit/static/static/js/index.CJzdLAun.js +1 -0
  96. streamlit/static/static/js/index.CNNlC1NL.js +1 -0
  97. streamlit/static/static/js/index.CO1sClzJ.js +2 -0
  98. streamlit/static/static/js/index.CZnagxXD.js +1 -0
  99. streamlit/static/static/js/{index.CnNERm7h.js → index.Cb0xSF7V.js} +289 -289
  100. streamlit/static/static/js/index.CgUt3tz_.js +1 -0
  101. streamlit/static/static/js/index.CjImmcsV.js +1 -0
  102. streamlit/static/static/js/index.ClRTsv8m.js +2 -0
  103. streamlit/static/static/js/{index.DBhELRFO.js → index.CnfWsQzS.js} +1 -1
  104. streamlit/static/static/js/index.CrJ1XD_V.js +1 -0
  105. streamlit/static/static/js/index.CtiKsjSC.js +1 -0
  106. streamlit/static/static/js/index.CwAuytgV.js +1 -0
  107. streamlit/static/static/js/index.D7GB-kly.js +1 -0
  108. streamlit/static/static/js/index.DA5wU0mQ.js +1 -0
  109. streamlit/static/static/js/{index.BVTVGhCW.js → index.DCpyIFTV.js} +1 -1
  110. streamlit/static/static/js/{index.Brmdn6cI.js → index.DE9wNOje.js} +1 -1
  111. streamlit/static/static/js/{index.B4UgLnfD.js → index.DHnB-C8A.js} +1 -1
  112. streamlit/static/static/js/{index.DmB_1wAI.js → index.DRTn9zvD.js} +1 -1
  113. streamlit/static/static/js/index.DjMjyJl9.js +7 -0
  114. streamlit/static/static/js/{index.BTGIlECR.js → index.DvRPFfw6.js} +162 -188
  115. streamlit/static/static/js/{index.BlIoUPom.js → index.DwaoC4Zp.js} +3 -3
  116. streamlit/static/static/js/index.F9tSej94.js +1 -0
  117. streamlit/static/static/js/index.HeVbRh9H.js +73 -0
  118. streamlit/static/static/js/index.J2D_m7LY.js +197 -0
  119. streamlit/static/static/js/index.PyIqRRSR.js +1 -0
  120. streamlit/static/static/js/index.dfivzJNz.js +1 -0
  121. streamlit/static/static/js/index.mRztGO69.js +3 -0
  122. streamlit/static/static/js/index.tB1kn_7z.js +1 -0
  123. streamlit/static/static/js/index.wDYef4mQ.js +12 -0
  124. streamlit/static/static/js/{input.vCGI-j0z.js → input.BL2buuce.js} +2 -2
  125. streamlit/static/static/js/{memory.CAr59PeX.js → memory.CUxjUWS7.js} +1 -1
  126. streamlit/static/static/js/{mergeWith.KUX-f18q.js → mergeWith.C1kp1zIi.js} +1 -1
  127. streamlit/static/static/js/{number-overlay-editor.7_qeQYbF.js → number-overlay-editor.WpheGpmR.js} +1 -1
  128. streamlit/static/static/js/{possibleConstructorReturn.ChgdWjjy.js → possibleConstructorReturn.DbvQboK3.js} +1 -1
  129. streamlit/static/static/js/{sandbox.6mITyM_H.js → sandbox.6lnFVWhX.js} +1 -1
  130. streamlit/static/static/js/{timepicker.BlKW9Kob.js → timepicker.Bg4xAK95.js} +1 -1
  131. streamlit/static/static/js/{toConsumableArray.DkNUwUhg.js → toConsumableArray.D9x7Ktv4.js} +1 -1
  132. streamlit/static/static/js/{uniqueId.BW6icrs1.js → uniqueId.Bm8FHN92.js} +1 -1
  133. streamlit/static/static/js/{useBasicWidgetState.oPxte5Mj.js → useBasicWidgetState.CUSYQZpm.js} +1 -1
  134. streamlit/static/static/js/{useTextInputAutoExpand.s7ZXp9QC.js → useTextInputAutoExpand.Bf2egQOG.js} +2 -2
  135. streamlit/static/static/js/useUpdateUiValue.lE5xnYWF.js +1 -0
  136. streamlit/static/static/js/withFullScreenWrapper.CCOXR7N6.js +1 -0
  137. streamlit/temporary_directory.py +5 -3
  138. streamlit/testing/v1/app_test.py +4 -1
  139. streamlit/testing/v1/element_tree.py +4 -5
  140. streamlit/type_util.py +10 -3
  141. streamlit/user_info.py +18 -14
  142. streamlit/util.py +11 -1
  143. streamlit/watcher/local_sources_watcher.py +4 -3
  144. streamlit/web/bootstrap.py +18 -12
  145. streamlit/web/cli.py +2 -1
  146. streamlit/web/server/oauth_authlib_routes.py +59 -3
  147. streamlit/web/server/routes.py +3 -0
  148. streamlit/web/server/server.py +72 -21
  149. {streamlit-1.47.0.dist-info → streamlit-1.48.0.dist-info}/METADATA +14 -2
  150. {streamlit-1.47.0.dist-info → streamlit-1.48.0.dist-info}/RECORD +154 -154
  151. streamlit/static/static/css/index.CsLB_Bnz.css +0 -1
  152. streamlit/static/static/js/ProgressBar.d6X6RRog.js +0 -2
  153. streamlit/static/static/js/RenderInPortalIfExists.DEmedSWH.js +0 -1
  154. streamlit/static/static/js/Toolbar.D8wuuqZd.js +0 -1
  155. streamlit/static/static/js/createDownloadLinkElement.DZMwyjvU.js +0 -1
  156. streamlit/static/static/js/data-grid-overlay-editor.Bxxjm6-o.js +0 -1
  157. streamlit/static/static/js/index.0dTVhOfX.js +0 -1
  158. streamlit/static/static/js/index.4yEdNndV.js +0 -1
  159. streamlit/static/static/js/index.5n6QoSUA.js +0 -1
  160. streamlit/static/static/js/index.6nngkCAa.js +0 -2
  161. streamlit/static/static/js/index.94f3Fw7s.js +0 -1
  162. streamlit/static/static/js/index.B61tWuMK.js +0 -73
  163. streamlit/static/static/js/index.B7u9Flh8.js +0 -1
  164. streamlit/static/static/js/index.BASsihSP.js +0 -1
  165. streamlit/static/static/js/index.BL9HK8jG.js +0 -1
  166. streamlit/static/static/js/index.BQWRZ6al.js +0 -3855
  167. streamlit/static/static/js/index.BQXddtYi.js +0 -1
  168. streamlit/static/static/js/index.BUnHfDxu.js +0 -1
  169. streamlit/static/static/js/index.BWQlvt-p.js +0 -1
  170. streamlit/static/static/js/index.BhB2h-IN.js +0 -1
  171. streamlit/static/static/js/index.BjbAdGl1.js +0 -2
  172. streamlit/static/static/js/index.BqMXJWvY.js +0 -197
  173. streamlit/static/static/js/index.BteAxTUz.js +0 -1
  174. streamlit/static/static/js/index.ByH19tU7.js +0 -1
  175. streamlit/static/static/js/index.CH_JROvL.js +0 -1
  176. streamlit/static/static/js/index.CRMaL4_D.js +0 -1
  177. streamlit/static/static/js/index.CitqAWcf.js +0 -7
  178. streamlit/static/static/js/index.DNTjV0h_.js +0 -3
  179. streamlit/static/static/js/index.Df2TZ_h-.js +0 -1
  180. streamlit/static/static/js/index.GID7Wiqx.js +0 -1
  181. streamlit/static/static/js/index.hprQgsHY.js +0 -1
  182. streamlit/static/static/js/index.mJxNfDOA.js +0 -12
  183. streamlit/static/static/js/index.qkxYEW65.js +0 -1
  184. streamlit/static/static/js/useOnInputChange.CBaDeGVQ.js +0 -1
  185. streamlit/static/static/js/withFullScreenWrapper.DkugyWpW.js +0 -1
  186. {streamlit-1.47.0.data → streamlit-1.48.0.data}/scripts/streamlit.cmd +0 -0
  187. {streamlit-1.47.0.dist-info → streamlit-1.48.0.dist-info}/WHEEL +0 -0
  188. {streamlit-1.47.0.dist-info → streamlit-1.48.0.dist-info}/entry_points.txt +0 -0
  189. {streamlit-1.47.0.dist-info → streamlit-1.48.0.dist-info}/top_level.txt +0 -0
@@ -33,6 +33,7 @@ from typing_extensions import TypeAlias
33
33
 
34
34
  from streamlit import runtime
35
35
  from streamlit.elements.lib.form_utils import current_form_id, is_in_form
36
+ from streamlit.elements.lib.layout_utils import LayoutConfig, Width, validate_width
36
37
  from streamlit.elements.lib.policies import check_widget_policies
37
38
  from streamlit.elements.lib.utils import (
38
39
  Key,
@@ -62,6 +63,7 @@ from streamlit.runtime.state import (
62
63
  )
63
64
  from streamlit.string_util import validate_icon_or_emoji
64
65
  from streamlit.url_util import is_url
66
+ from streamlit.util import in_sidebar
65
67
 
66
68
  if TYPE_CHECKING:
67
69
  from streamlit.delta_generator import DeltaGenerator
@@ -98,7 +100,8 @@ class ButtonMixin:
98
100
  type: Literal["primary", "secondary", "tertiary"] = "secondary",
99
101
  icon: str | None = None,
100
102
  disabled: bool = False,
101
- use_container_width: bool = False,
103
+ use_container_width: bool | None = None,
104
+ width: Width = "content",
102
105
  ) -> bool:
103
106
  r"""Display a button widget.
104
107
 
@@ -138,8 +141,8 @@ class ButtonMixin:
138
141
  on_click : callable
139
142
  An optional callback invoked when this button is clicked.
140
143
 
141
- args : tuple
142
- An optional tuple of args to pass to the callback.
144
+ args : list or tuple
145
+ An optional list or tuple of args to pass to the callback.
143
146
 
144
147
  kwargs : dict
145
148
  An optional dict of kwargs to pass to the callback.
@@ -153,7 +156,7 @@ class ButtonMixin:
153
156
  - ``"secondary"`` (default): The button's background coordinates
154
157
  with the app's background color for normal emphasis.
155
158
  - ``"tertiary"``: The button is plain text without a border or
156
- background for subtly.
159
+ background for subtlety.
157
160
 
158
161
  icon : str or None
159
162
  An optional emoji or icon to display next to the button label. If ``icon``
@@ -185,6 +188,25 @@ class ButtonMixin:
185
188
  In both cases, if the contents of the button are wider than the
186
189
  parent container, the contents will line wrap.
187
190
 
191
+ width : "content", "stretch", or int
192
+ The width of the button. This can be one of the following:
193
+
194
+ - ``"content"`` (default): The width of the button matches the
195
+ width of its content, but doesn't exceed the width of the parent
196
+ container.
197
+ - ``"stretch"``: The width of the button matches the width of the
198
+ parent container.
199
+ - An integer specifying the width in pixels: The button has a
200
+ fixed width. If the specified width is greater than the width of
201
+ the parent container, the width of the button matches the width
202
+ of the parent container.
203
+
204
+ .. deprecated::
205
+ ``use_container_width`` is deprecated and will be removed in a
206
+ future release. For ``use_container_width=True``, use
207
+ ``width="stretch"``. For ``use_container_width=False``, use
208
+ ``width="content"``.
209
+
188
210
  Returns
189
211
  -------
190
212
  bool
@@ -218,11 +240,11 @@ class ButtonMixin:
218
240
  >>> import streamlit as st
219
241
  >>>
220
242
  >>> left, middle, right = st.columns(3)
221
- >>> if left.button("Plain button", use_container_width=True):
243
+ >>> if left.button("Plain button", width="stretch"):
222
244
  ... left.markdown("You clicked the plain button.")
223
- >>> if middle.button("Emoji button", icon="😃", use_container_width=True):
245
+ >>> if middle.button("Emoji button", icon="😃", width="stretch"):
224
246
  ... middle.markdown("You clicked the emoji button.")
225
- >>> if right.button("Material button", icon=":material/mood:", use_container_width=True):
247
+ >>> if right.button("Material button", icon=":material/mood:", width="stretch"):
226
248
  ... right.markdown("You clicked the Material button.")
227
249
 
228
250
  .. output::
@@ -233,6 +255,9 @@ class ButtonMixin:
233
255
  key = to_key(key)
234
256
  ctx = get_script_run_ctx()
235
257
 
258
+ if use_container_width is not None:
259
+ width = "stretch" if use_container_width else "content"
260
+
236
261
  # Checks whether the entered button type is one of the allowed options
237
262
  if type not in ["primary", "secondary", "tertiary"]:
238
263
  raise StreamlitAPIException(
@@ -251,8 +276,8 @@ class ButtonMixin:
251
276
  disabled=disabled,
252
277
  type=type,
253
278
  icon=icon,
254
- use_container_width=use_container_width,
255
279
  ctx=ctx,
280
+ width=width,
256
281
  )
257
282
 
258
283
  @gather_metrics("download_button")
@@ -271,7 +296,8 @@ class ButtonMixin:
271
296
  type: Literal["primary", "secondary", "tertiary"] = "secondary",
272
297
  icon: str | None = None,
273
298
  disabled: bool = False,
274
- use_container_width: bool = False,
299
+ use_container_width: bool | None = None,
300
+ width: Width = "content",
275
301
  ) -> bool:
276
302
  r"""Display a download button widget.
277
303
 
@@ -359,8 +385,8 @@ class ButtonMixin:
359
385
  - ``None``: This is same as ``on_click="rerun"``. This value exists
360
386
  for backwards compatibility and shouldn't be used.
361
387
 
362
- args : tuple
363
- An optional tuple of args to pass to the callback.
388
+ args : list or tuple
389
+ An optional list or tuple of args to pass to the callback.
364
390
 
365
391
  kwargs : dict
366
392
  An optional dict of kwargs to pass to the callback.
@@ -374,7 +400,7 @@ class ButtonMixin:
374
400
  - ``"secondary"`` (default): The button's background coordinates
375
401
  with the app's background color for normal emphasis.
376
402
  - ``"tertiary"``: The button is plain text without a border or
377
- background for subtly.
403
+ background for subtlety.
378
404
 
379
405
  icon : str or None
380
406
  An optional emoji or icon to display next to the button label. If ``icon``
@@ -406,6 +432,25 @@ class ButtonMixin:
406
432
  In both cases, if the contents of the button are wider than the
407
433
  parent container, the contents will line wrap.
408
434
 
435
+ width : "content", "stretch", or int
436
+ The width of the download button. This can be one of the following:
437
+
438
+ - ``"content"`` (default): The width of the button matches the
439
+ width of its content, but doesn't exceed the width of the parent
440
+ container.
441
+ - ``"stretch"``: The width of the button matches the width of the
442
+ parent container.
443
+ - An integer specifying the width in pixels: The button has a
444
+ fixed width. If the specified width is greater than the width of
445
+ the parent container, the width of the button matches the width
446
+ of the parent container.
447
+
448
+ .. deprecated::
449
+ ``use_container_width`` is deprecated and will be removed in a
450
+ future release. For ``use_container_width=True``, use
451
+ ``width="stretch"``. For ``use_container_width=False``, use
452
+ ``width="content"``.
453
+
409
454
  Returns
410
455
  -------
411
456
  bool
@@ -519,6 +564,9 @@ class ButtonMixin:
519
564
  """
520
565
  ctx = get_script_run_ctx()
521
566
 
567
+ if use_container_width is not None:
568
+ width = "stretch" if use_container_width else "content"
569
+
522
570
  if type not in ["primary", "secondary", "tertiary"]:
523
571
  raise StreamlitAPIException(
524
572
  'The type argument to st.download_button must be "primary", "secondary", or "tertiary". \n'
@@ -538,8 +586,8 @@ class ButtonMixin:
538
586
  type=type,
539
587
  icon=icon,
540
588
  disabled=disabled,
541
- use_container_width=use_container_width,
542
589
  ctx=ctx,
590
+ width=width,
543
591
  )
544
592
 
545
593
  @gather_metrics("link_button")
@@ -552,7 +600,8 @@ class ButtonMixin:
552
600
  type: Literal["primary", "secondary", "tertiary"] = "secondary",
553
601
  icon: str | None = None,
554
602
  disabled: bool = False,
555
- use_container_width: bool = False,
603
+ use_container_width: bool | None = None,
604
+ width: Width = "content",
556
605
  ) -> DeltaGenerator:
557
606
  r"""Display a link button element.
558
607
 
@@ -599,7 +648,7 @@ class ButtonMixin:
599
648
  - ``"secondary"`` (default): The button's background coordinates
600
649
  with the app's background color for normal emphasis.
601
650
  - ``"tertiary"``: The button is plain text without a border or
602
- background for subtly.
651
+ background for subtlety.
603
652
 
604
653
  icon : str or None
605
654
  An optional emoji or icon to display next to the button label. If ``icon``
@@ -631,6 +680,25 @@ class ButtonMixin:
631
680
  In both cases, if the contents of the button are wider than the
632
681
  parent container, the contents will line wrap.
633
682
 
683
+ width : "content", "stretch", or int
684
+ The width of the link button. This can be one of the following:
685
+
686
+ - ``"content"`` (default): The width of the button matches the
687
+ width of its content, but doesn't exceed the width of the parent
688
+ container.
689
+ - ``"stretch"``: The width of the button matches the width of the
690
+ parent container.
691
+ - An integer specifying the width in pixels: The button has a
692
+ fixed width. If the specified width is greater than the width of
693
+ the parent container, the width of the button matches the width
694
+ of the parent container.
695
+
696
+ .. deprecated::
697
+ ``use_container_width`` is deprecated and will be removed in a
698
+ future release. For ``use_container_width=True``, use
699
+ ``width="stretch"``. For ``use_container_width=False``, use
700
+ ``width="content"``.
701
+
634
702
  Example
635
703
  -------
636
704
  >>> import streamlit as st
@@ -649,6 +717,9 @@ class ButtonMixin:
649
717
  f'\nThe argument passed was "{type}".'
650
718
  )
651
719
 
720
+ if use_container_width is not None:
721
+ width = "stretch" if use_container_width else "content"
722
+
652
723
  return self._link_button(
653
724
  label=label,
654
725
  url=url,
@@ -656,7 +727,7 @@ class ButtonMixin:
656
727
  disabled=disabled,
657
728
  type=type,
658
729
  icon=icon,
659
- use_container_width=use_container_width,
730
+ width=width,
660
731
  )
661
732
 
662
733
  @gather_metrics("page_link")
@@ -669,6 +740,7 @@ class ButtonMixin:
669
740
  help: str | None = None,
670
741
  disabled: bool = False,
671
742
  use_container_width: bool | None = None,
743
+ width: Width = "content",
672
744
  ) -> DeltaGenerator:
673
745
  r"""Display a link to another page in a multipage app or to an external page.
674
746
 
@@ -740,6 +812,25 @@ class ButtonMixin:
740
812
  The default is ``True`` for page links in the sidebar and ``False``
741
813
  for those in the main app.
742
814
 
815
+ width : "content", "stretch", or int
816
+ The width of the page-link button. This can be one of the following:
817
+
818
+ - ``"content"`` (default): The width of the button matches the
819
+ width of its content, but doesn't exceed the width of the parent
820
+ container.
821
+ - ``"stretch"``: The width of the button matches the width of the
822
+ parent container.
823
+ - An integer specifying the width in pixels: The button has a
824
+ fixed width. If the specified width is greater than the width of
825
+ the parent container, the width of the button matches the width
826
+ of the parent container.
827
+
828
+ .. deprecated::
829
+ ``use_container_width`` is deprecated and will be removed in a
830
+ future release. For ``use_container_width=True``, use
831
+ ``width="stretch"``. For ``use_container_width=False``, use
832
+ ``width="content"``.
833
+
743
834
  Example
744
835
  -------
745
836
  Consider the following example given this file structure:
@@ -770,6 +861,12 @@ class ButtonMixin:
770
861
  height: 350px
771
862
 
772
863
  """
864
+ if use_container_width is not None:
865
+ width = "stretch" if use_container_width else "content"
866
+
867
+ if in_sidebar(self.dg):
868
+ # Sidebar page links should always be stretch width.
869
+ width = "stretch"
773
870
 
774
871
  return self._page_link(
775
872
  page=page,
@@ -777,7 +874,7 @@ class ButtonMixin:
777
874
  icon=icon,
778
875
  help=help,
779
876
  disabled=disabled,
780
- use_container_width=use_container_width,
877
+ width=width,
781
878
  )
782
879
 
783
880
  def _download_button(
@@ -795,8 +892,8 @@ class ButtonMixin:
795
892
  type: Literal["primary", "secondary", "tertiary"] = "secondary",
796
893
  icon: str | None = None,
797
894
  disabled: bool = False,
798
- use_container_width: bool = False,
799
895
  ctx: ScriptRunContext | None = None,
896
+ width: Width = "content",
800
897
  ) -> bool:
801
898
  key = to_key(key)
802
899
 
@@ -826,7 +923,7 @@ class ButtonMixin:
826
923
  mime=mime,
827
924
  help=help,
828
925
  type=type,
829
- use_container_width=use_container_width,
926
+ width=width,
830
927
  )
831
928
 
832
929
  if is_in_form(self.dg):
@@ -836,7 +933,6 @@ class ButtonMixin:
836
933
 
837
934
  download_button_proto = DownloadButtonProto()
838
935
  download_button_proto.id = element_id
839
- download_button_proto.use_container_width = use_container_width
840
936
  download_button_proto.label = label
841
937
  download_button_proto.default = False
842
938
  download_button_proto.type = type
@@ -869,7 +965,11 @@ class ButtonMixin:
869
965
  value_type="trigger_value",
870
966
  )
871
967
 
872
- self.dg._enqueue("download_button", download_button_proto)
968
+ validate_width(width, allow_content=True)
969
+ layout_config = LayoutConfig(width=width)
970
+ self.dg._enqueue(
971
+ "download_button", download_button_proto, layout_config=layout_config
972
+ )
873
973
  return button_state.value
874
974
 
875
975
  def _link_button(
@@ -881,13 +981,12 @@ class ButtonMixin:
881
981
  type: Literal["primary", "secondary", "tertiary"] = "secondary",
882
982
  icon: str | None = None,
883
983
  disabled: bool = False,
884
- use_container_width: bool = False,
984
+ width: Width = "content",
885
985
  ) -> DeltaGenerator:
886
986
  link_button_proto = LinkButtonProto()
887
987
  link_button_proto.label = label
888
988
  link_button_proto.url = url
889
989
  link_button_proto.type = type
890
- link_button_proto.use_container_width = use_container_width
891
990
  link_button_proto.disabled = disabled
892
991
 
893
992
  if help is not None:
@@ -896,7 +995,11 @@ class ButtonMixin:
896
995
  if icon is not None:
897
996
  link_button_proto.icon = validate_icon_or_emoji(icon)
898
997
 
899
- return self.dg._enqueue("link_button", link_button_proto)
998
+ validate_width(width, allow_content=True)
999
+ layout_config = LayoutConfig(width=width)
1000
+ return self.dg._enqueue(
1001
+ "link_button", link_button_proto, layout_config=layout_config
1002
+ )
900
1003
 
901
1004
  def _page_link(
902
1005
  self,
@@ -906,13 +1009,17 @@ class ButtonMixin:
906
1009
  icon: str | None = None,
907
1010
  help: str | None = None,
908
1011
  disabled: bool = False,
909
- use_container_width: bool | None = None,
1012
+ width: Width = "content",
910
1013
  ) -> DeltaGenerator:
911
1014
  page_link_proto = PageLinkProto()
1015
+ validate_width(width, allow_content=True)
912
1016
 
913
1017
  ctx = get_script_run_ctx()
914
1018
  if not ctx:
915
- return self.dg._enqueue("page_link", page_link_proto)
1019
+ layout_config = LayoutConfig(width=width)
1020
+ return self.dg._enqueue(
1021
+ "page_link", page_link_proto, layout_config=layout_config
1022
+ )
916
1023
 
917
1024
  page_link_proto.disabled = disabled
918
1025
 
@@ -925,9 +1032,6 @@ class ButtonMixin:
925
1032
  if help is not None:
926
1033
  page_link_proto.help = dedent(help)
927
1034
 
928
- if use_container_width is not None:
929
- page_link_proto.use_container_width = use_container_width
930
-
931
1035
  if isinstance(page, StreamlitPage):
932
1036
  page_link_proto.page_script_hash = page._script_hash
933
1037
  page_link_proto.page = page.url_path
@@ -948,7 +1052,10 @@ class ButtonMixin:
948
1052
  raise StreamlitMissingPageLabelError()
949
1053
  page_link_proto.page = page
950
1054
  page_link_proto.external = True
951
- return self.dg._enqueue("page_link", page_link_proto)
1055
+ layout_config = LayoutConfig(width=width)
1056
+ return self.dg._enqueue(
1057
+ "page_link", page_link_proto, layout_config=layout_config
1058
+ )
952
1059
 
953
1060
  ctx_main_script = ""
954
1061
  all_app_pages = {}
@@ -979,7 +1086,10 @@ class ButtonMixin:
979
1086
  uses_pages_directory=bool(PagesManager.uses_pages_directory),
980
1087
  )
981
1088
 
982
- return self.dg._enqueue("page_link", page_link_proto)
1089
+ layout_config = LayoutConfig(width=width)
1090
+ return self.dg._enqueue(
1091
+ "page_link", page_link_proto, layout_config=layout_config
1092
+ )
983
1093
 
984
1094
  def _button(
985
1095
  self,
@@ -994,8 +1104,8 @@ class ButtonMixin:
994
1104
  type: Literal["primary", "secondary", "tertiary"] = "secondary",
995
1105
  icon: str | None = None,
996
1106
  disabled: bool = False,
997
- use_container_width: bool = False,
998
1107
  ctx: ScriptRunContext | None = None,
1108
+ width: Width = "content",
999
1109
  ) -> bool:
1000
1110
  key = to_key(key)
1001
1111
 
@@ -1021,7 +1131,7 @@ class ButtonMixin:
1021
1131
  help=help,
1022
1132
  is_form_submitter=is_form_submitter,
1023
1133
  type=type,
1024
- use_container_width=use_container_width,
1134
+ width=width,
1025
1135
  )
1026
1136
 
1027
1137
  # It doesn't make sense to create a button inside a form (except
@@ -1046,7 +1156,6 @@ class ButtonMixin:
1046
1156
  button_proto.is_form_submitter = is_form_submitter
1047
1157
  button_proto.form_id = form_id
1048
1158
  button_proto.type = type
1049
- button_proto.use_container_width = use_container_width
1050
1159
  button_proto.disabled = disabled
1051
1160
 
1052
1161
  if help is not None:
@@ -1070,7 +1179,10 @@ class ButtonMixin:
1070
1179
 
1071
1180
  if ctx:
1072
1181
  save_for_app_testing(ctx, element_id, button_state.value)
1073
- self.dg._enqueue("button", button_proto)
1182
+
1183
+ validate_width(width, allow_content=True)
1184
+ layout_config = LayoutConfig(width=width)
1185
+ self.dg._enqueue("button", button_proto, layout_config=layout_config)
1074
1186
 
1075
1187
  return button_state.value
1076
1188
 
@@ -59,7 +59,6 @@ from streamlit.runtime.metrics_util import gather_metrics
59
59
  from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
60
60
  from streamlit.runtime.state import register_widget
61
61
  from streamlit.string_util import is_emoji, validate_material_icon
62
- from streamlit.type_util import T
63
62
 
64
63
  if TYPE_CHECKING:
65
64
  from streamlit.dataframe_util import OptionSequence
@@ -75,7 +74,7 @@ if TYPE_CHECKING:
75
74
  WidgetSerializer,
76
75
  )
77
76
 
78
-
77
+ T = TypeVar("T")
79
78
  V = TypeVar("V")
80
79
 
81
80
  _THUMB_ICONS: Final = (":material/thumb_up:", ":material/thumb_down:")
@@ -340,8 +339,8 @@ class ButtonGroupMixin:
340
339
  An optional callback invoked when this feedback widget's value
341
340
  changes.
342
341
 
343
- args : tuple
344
- An optional tuple of args to pass to the callback.
342
+ args : list or tuple
343
+ An optional list or tuple of args to pass to the callback.
345
344
 
346
345
  kwargs : dict
347
346
  An optional dict of kwargs to pass to the callback.
@@ -562,8 +561,8 @@ class ButtonGroupMixin:
562
561
  on_change : callable
563
562
  An optional callback invoked when this widget's value changes.
564
563
 
565
- args : tuple
566
- An optional tuple of args to pass to the callback.
564
+ args : list or tuple
565
+ An optional list or tuple of args to pass to the callback.
567
566
 
568
567
  kwargs : dict
569
568
  An optional dict of kwargs to pass to the callback.
@@ -788,8 +787,8 @@ class ButtonGroupMixin:
788
787
  on_change : callable
789
788
  An optional callback invoked when this widget's value changes.
790
789
 
791
- args : tuple
792
- An optional tuple of args to pass to the callback.
790
+ args : list or tuple
791
+ An optional list or tuple of args to pass to the callback.
793
792
 
794
793
  kwargs : dict
795
794
  An optional dict of kwargs to pass to the callback.
@@ -1053,6 +1052,8 @@ class ButtonGroupMixin:
1053
1052
  click_mode=parsed_selection_mode,
1054
1053
  style=style,
1055
1054
  width=width,
1055
+ label=label,
1056
+ help=help,
1056
1057
  )
1057
1058
 
1058
1059
  proto = _build_proto(
@@ -143,8 +143,8 @@ class CameraInputMixin:
143
143
  An optional callback invoked when this camera_input's value
144
144
  changes.
145
145
 
146
- args : tuple
147
- An optional tuple of args to pass to the callback.
146
+ args : list or tuple
147
+ An optional list or tuple of args to pass to the callback.
148
148
 
149
149
  kwargs : dict
150
150
  An optional dict of kwargs to pass to the callback.
@@ -465,6 +465,12 @@ class ChatMixin:
465
465
  example, to only accept JPG/JPEG and PNG files, use
466
466
  ``["jpg", "jpeg", "png"]``.
467
467
 
468
+ .. note::
469
+ This is a best-effort check, but doesn't provide a
470
+ security guarantee against users uploading files of other types
471
+ or type extensions. The correct handling of uploaded files is
472
+ part of the app developer's responsibility.
473
+
468
474
  disabled : bool
469
475
  Whether the chat input should be disabled. This defaults to
470
476
  ``False``.
@@ -472,8 +478,8 @@ class ChatMixin:
472
478
  on_submit : callable
473
479
  An optional callback invoked when the chat input's value is submitted.
474
480
 
475
- args : tuple
476
- An optional tuple of args to pass to the callback.
481
+ args : list or tuple
482
+ An optional list or tuple of args to pass to the callback.
477
483
 
478
484
  kwargs : dict
479
485
  An optional dict of kwargs to pass to the callback.
@@ -123,8 +123,8 @@ class CheckboxMixin:
123
123
  on_change : callable
124
124
  An optional callback invoked when this checkbox's value changes.
125
125
 
126
- args : tuple
127
- An optional tuple of args to pass to the callback.
126
+ args : list or tuple
127
+ An optional list or tuple of args to pass to the callback.
128
128
 
129
129
  kwargs : dict
130
130
  An optional dict of kwargs to pass to the callback.
@@ -249,8 +249,8 @@ class CheckboxMixin:
249
249
  on_change : callable
250
250
  An optional callback invoked when this toggle's value changes.
251
251
 
252
- args : tuple
253
- An optional tuple of args to pass to the callback.
252
+ args : list or tuple
253
+ An optional list or tuple of args to pass to the callback.
254
254
 
255
255
  kwargs : dict
256
256
  An optional dict of kwargs to pass to the callback.
@@ -126,8 +126,8 @@ class ColorPickerMixin:
126
126
  An optional callback invoked when this color_picker's value
127
127
  changes.
128
128
 
129
- args : tuple
130
- An optional tuple of args to pass to the callback.
129
+ args : list or tuple
130
+ An optional list or tuple of args to pass to the callback.
131
131
 
132
132
  kwargs : dict
133
133
  An optional dict of kwargs to pass to the callback.
@@ -337,8 +337,8 @@ def _apply_row_additions(
337
337
  if isinstance(df.index, pd.RangeIndex):
338
338
  # Extract metadata from the range index:
339
339
  index_type = "range"
340
- index_stop = cast("int", df.index.stop)
341
- index_step = cast("int", df.index.step)
340
+ index_stop = df.index.stop
341
+ index_step = df.index.step
342
342
  elif isinstance(df.index, pd.Index) and pd.api.types.is_integer_dtype(
343
343
  df.index.dtype
344
344
  ):
@@ -726,8 +726,8 @@ class DataEditorMixin:
726
726
  on_change : callable
727
727
  An optional callback invoked when this data_editor's value changes.
728
728
 
729
- args : tuple
730
- An optional tuple of args to pass to the callback.
729
+ args : list or tuple
730
+ An optional list or tuple of args to pass to the callback.
731
731
 
732
732
  kwargs : dict
733
733
  An optional dict of kwargs to pass to the callback.
@@ -746,15 +746,17 @@ class DataEditorMixin:
746
746
 
747
747
  Examples
748
748
  --------
749
- >>> import streamlit as st
749
+ **Example 1: Basic usage**
750
+
750
751
  >>> import pandas as pd
752
+ >>> import streamlit as st
751
753
  >>>
752
754
  >>> df = pd.DataFrame(
753
755
  >>> [
754
- >>> {"command": "st.selectbox", "rating": 4, "is_widget": True},
755
- >>> {"command": "st.balloons", "rating": 5, "is_widget": False},
756
- >>> {"command": "st.time_input", "rating": 3, "is_widget": True},
757
- >>> ]
756
+ >>> {"command": "st.selectbox", "rating": 4, "is_widget": True},
757
+ >>> {"command": "st.balloons", "rating": 5, "is_widget": False},
758
+ >>> {"command": "st.time_input", "rating": 3, "is_widget": True},
759
+ >>> ]
758
760
  >>> )
759
761
  >>> edited_df = st.data_editor(df)
760
762
  >>>
@@ -765,17 +767,20 @@ class DataEditorMixin:
765
767
  https://doc-data-editor.streamlit.app/
766
768
  height: 350px
767
769
 
768
- You can also allow the user to add and delete rows by setting ``num_rows`` to "dynamic":
770
+ **Example 2: Allowing users to add and delete rows**
771
+
772
+ You can allow your users to add and delete rows by setting ``num_rows``
773
+ to "dynamic":
769
774
 
770
775
  >>> import streamlit as st
771
776
  >>> import pandas as pd
772
777
  >>>
773
778
  >>> df = pd.DataFrame(
774
779
  >>> [
775
- >>> {"command": "st.selectbox", "rating": 4, "is_widget": True},
776
- >>> {"command": "st.balloons", "rating": 5, "is_widget": False},
777
- >>> {"command": "st.time_input", "rating": 3, "is_widget": True},
778
- >>> ]
780
+ >>> {"command": "st.selectbox", "rating": 4, "is_widget": True},
781
+ >>> {"command": "st.balloons", "rating": 5, "is_widget": False},
782
+ >>> {"command": "st.time_input", "rating": 3, "is_widget": True},
783
+ >>> ]
779
784
  >>> )
780
785
  >>> edited_df = st.data_editor(df, num_rows="dynamic")
781
786
  >>>
@@ -786,7 +791,9 @@ class DataEditorMixin:
786
791
  https://doc-data-editor1.streamlit.app/
787
792
  height: 450px
788
793
 
789
- Or you can customize the data editor via ``column_config``, ``hide_index``,
794
+ **Example 3: Data editor configuration**
795
+
796
+ You can customize the data editor via ``column_config``, ``hide_index``,
790
797
  ``column_order``, or ``disabled``:
791
798
 
792
799
  >>> import pandas as pd