streamlit 1.48.1__py3-none-any.whl → 1.49.1__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 (203) hide show
  1. streamlit/__init__.py +3 -10
  2. streamlit/commands/logo.py +4 -3
  3. streamlit/commands/navigation.py +1 -1
  4. streamlit/commands/page_config.py +4 -1
  5. streamlit/components/v1/custom_component.py +2 -2
  6. streamlit/config.py +82 -1
  7. streamlit/connections/snowflake_connection.py +3 -1
  8. streamlit/delta_generator.py +3 -0
  9. streamlit/elements/arrow.py +155 -70
  10. streamlit/elements/bokeh_chart.py +13 -3
  11. streamlit/elements/deck_gl_json_chart.py +0 -1
  12. streamlit/elements/dialog_decorator.py +7 -59
  13. streamlit/elements/form.py +10 -1
  14. streamlit/elements/graphviz_chart.py +57 -6
  15. streamlit/elements/heading.py +17 -16
  16. streamlit/elements/image.py +64 -37
  17. streamlit/elements/layouts.py +2 -2
  18. streamlit/elements/lib/built_in_chart_utils.py +2 -5
  19. streamlit/elements/lib/column_config_utils.py +18 -4
  20. streamlit/elements/lib/column_types.py +75 -30
  21. streamlit/elements/lib/dialog.py +3 -3
  22. streamlit/elements/lib/image_utils.py +19 -11
  23. streamlit/elements/lib/layout_utils.py +19 -6
  24. streamlit/elements/lib/utils.py +20 -41
  25. streamlit/elements/markdown.py +7 -6
  26. streamlit/elements/media.py +6 -13
  27. streamlit/elements/metric.py +78 -1
  28. streamlit/elements/pdf.py +192 -0
  29. streamlit/elements/plotly_chart.py +3 -2
  30. streamlit/elements/pyplot.py +53 -11
  31. streamlit/elements/toast.py +81 -5
  32. streamlit/elements/vega_charts.py +3 -8
  33. streamlit/elements/widgets/audio_input.py +0 -1
  34. streamlit/elements/widgets/button.py +0 -4
  35. streamlit/elements/widgets/button_group.py +5 -4
  36. streamlit/elements/widgets/camera_input.py +0 -1
  37. streamlit/elements/widgets/chat.py +11 -13
  38. streamlit/elements/widgets/checkbox.py +0 -1
  39. streamlit/elements/widgets/color_picker.py +0 -1
  40. streamlit/elements/widgets/data_editor.py +142 -62
  41. streamlit/elements/widgets/file_uploader.py +74 -37
  42. streamlit/elements/widgets/multiselect.py +0 -1
  43. streamlit/elements/widgets/number_input.py +0 -1
  44. streamlit/elements/widgets/radio.py +0 -1
  45. streamlit/elements/widgets/select_slider.py +0 -1
  46. streamlit/elements/widgets/selectbox.py +0 -1
  47. streamlit/elements/widgets/slider.py +0 -1
  48. streamlit/elements/widgets/text_widgets.py +0 -2
  49. streamlit/elements/widgets/time_widgets.py +0 -2
  50. streamlit/errors.py +11 -0
  51. streamlit/material_icon_names.py +1 -1
  52. streamlit/proto/Arrow_pb2.py +14 -8
  53. streamlit/proto/Arrow_pb2.pyi +11 -3
  54. streamlit/proto/Block_pb2.py +16 -16
  55. streamlit/proto/Block_pb2.pyi +2 -0
  56. streamlit/proto/ChatInput_pb2.py +3 -3
  57. streamlit/proto/ChatInput_pb2.pyi +2 -0
  58. streamlit/proto/FileUploader_pb2.py +2 -2
  59. streamlit/proto/FileUploader_pb2.pyi +5 -1
  60. streamlit/proto/GraphVizChart_pb2.py +4 -2
  61. streamlit/proto/GraphVizChart_pb2.pyi +1 -1
  62. streamlit/proto/Image_pb2.py +4 -2
  63. streamlit/proto/Image_pb2.pyi +1 -10
  64. streamlit/proto/Metric_pb2.py +8 -6
  65. streamlit/proto/Metric_pb2.pyi +34 -10
  66. streamlit/proto/Toast_pb2.py +2 -2
  67. streamlit/proto/Toast_pb2.pyi +10 -1
  68. streamlit/runtime/caching/__init__.py +14 -2
  69. streamlit/runtime/caching/cache_data_api.py +0 -17
  70. streamlit/runtime/caching/cache_resource_api.py +0 -16
  71. streamlit/runtime/caching/cached_message_replay.py +8 -20
  72. streamlit/runtime/caching/hashing.py +31 -1
  73. streamlit/runtime/credentials.py +4 -4
  74. streamlit/runtime/fragment.py +0 -42
  75. streamlit/runtime/websocket_session_manager.py +1 -1
  76. streamlit/static/index.html +2 -2
  77. streamlit/static/manifest.json +223 -251
  78. streamlit/static/static/css/{index.CJVRHjQZ.css → index.C8X8rNzw.css} +1 -1
  79. streamlit/static/static/css/index.COe1010n.css +1 -0
  80. streamlit/static/static/js/{ErrorOutline.esm.DjObtx4K.js → ErrorOutline.esm.DcGrhbBP.js} +1 -1
  81. streamlit/static/static/js/{FileDownload.esm.Bz9nxNC5.js → FileDownload.esm.DgBvV6Pq.js} +1 -1
  82. streamlit/static/static/js/FileHelper.M6AAaeuA.js +5 -0
  83. streamlit/static/static/js/FormClearHelper.DHh1GFzm.js +1 -0
  84. streamlit/static/static/js/{Hooks.DEoLCfOE.js → Hooks.DGu1od_L.js} +1 -1
  85. streamlit/static/static/js/InputInstructions.z6sVgyYt.js +1 -0
  86. streamlit/static/static/js/Particles.DDVT-6Qc.js +1 -0
  87. streamlit/static/static/js/ProgressBar.BEY0cXXV.js +2 -0
  88. streamlit/static/static/js/Toolbar.DSnK1fUh.js +1 -0
  89. streamlit/static/static/js/{base-input.BmvSaPd2.js → base-input.CK3UVGp1.js} +4 -4
  90. streamlit/static/static/js/{checkbox.Cgxgc0et.js → checkbox.D8W881TL.js} +2 -2
  91. streamlit/static/static/js/createSuper.B6W-Dh9S.js +1 -0
  92. streamlit/static/static/js/data-grid-overlay-editor.DRTHOydk.js +1 -0
  93. streamlit/static/static/js/{downloader.M6jQeNDf.js → downloader.DiKpuU_S.js} +1 -1
  94. streamlit/static/static/js/es6.B8zRNPZ-.js +2 -0
  95. streamlit/static/static/js/iframeResizer.contentWindow.DIewJmmh.js +1 -0
  96. streamlit/static/static/js/index.452cqrrL.js +1 -0
  97. streamlit/static/static/js/index.4eF4NxG2.js +1 -0
  98. streamlit/static/static/js/index.B6U8LQo3.js +1 -0
  99. streamlit/static/static/js/index.B9mjBcgE.js +1 -0
  100. streamlit/static/static/js/index.BXYmrqnf.js +1 -0
  101. streamlit/static/static/js/index.B_8AnktO.js +1 -0
  102. streamlit/static/static/js/index.Bl7zGQSh.js +7 -0
  103. streamlit/static/static/js/index.BnEpvLEz.js +1 -0
  104. streamlit/static/static/js/{index.D1EayrNh.js → index.BnJIOYn9.js} +2 -2
  105. streamlit/static/static/js/index.Bte_9Lyq.js +1 -0
  106. streamlit/static/static/js/index.C1HcTl5K.js +1 -0
  107. streamlit/static/static/js/index.C7fRKRs4.js +1 -0
  108. streamlit/static/static/js/index.C7lSmSOP.js +1 -0
  109. streamlit/static/static/js/index.CD8HuT3N.js +976 -0
  110. streamlit/static/static/js/index.CP5TD2z1.js +1 -0
  111. streamlit/static/static/js/index.C_tmcx4B.js +1 -0
  112. streamlit/static/static/js/index.CcJf6BCU.js +3858 -0
  113. streamlit/static/static/js/{index.CbdWnLqS.js → index.CejBxbg1.js} +3 -3
  114. streamlit/static/static/js/index.Ch7MBCx0.js +5367 -0
  115. streamlit/static/static/js/index.CjXWwH-y.js +1 -0
  116. streamlit/static/static/js/index.CvYYtxD_.js +1 -0
  117. streamlit/static/static/js/index.D2-atlaQ.js +3 -0
  118. streamlit/static/static/js/index.D3K5nOu9.js +197 -0
  119. streamlit/static/static/js/index.D5naqx-J.js +1 -0
  120. streamlit/static/static/js/index.Dk4C7X3i.js +1 -0
  121. streamlit/static/static/js/index.DkKT3LUI.js +1 -0
  122. streamlit/static/static/js/index.DtYN2x4k.js +1 -0
  123. streamlit/static/static/js/index.MTPPBDHk.js +2 -0
  124. streamlit/static/static/js/{index.Cqa4gqqN.js → index.Ts_0SdB9.js} +1 -1
  125. streamlit/static/static/js/{index.CgZDfhN4.js → index.cnnXF7xQ.js} +2 -2
  126. streamlit/static/static/js/index.ho6NIXGl.js +1 -0
  127. streamlit/static/static/js/index.pqW9AMJD.js +3 -0
  128. streamlit/static/static/js/{index.D1jHqUJq.js → index.qhs54UAB.js} +1 -1
  129. streamlit/static/static/js/{index.tsvTLdio.js → index.urHgTgMQ.js} +9 -9
  130. streamlit/static/static/js/index.wzkv_11M.js +1 -0
  131. streamlit/static/static/js/index.yF5AncHY.js +1 -0
  132. streamlit/static/static/js/{index.BXDq9dj4.js → index.zecpGxtj.js} +1 -1
  133. streamlit/static/static/js/{input.DZd6EQlV.js → input.nzVJphXi.js} +2 -2
  134. streamlit/static/static/js/{memory.ptkfuI71.js → memory.CjCgTQz3.js} +1 -1
  135. streamlit/static/static/js/number-overlay-editor.DaRFzZEO.js +9 -0
  136. streamlit/static/static/js/{possibleConstructorReturn.Bd4ImlQ9.js → possibleConstructorReturn.DgiPnZ9N.js} +1 -1
  137. streamlit/static/static/js/{sandbox.DsH8LuID.js → sandbox.mithfq7Z.js} +1 -1
  138. streamlit/static/static/js/{timepicker.QVekV78C.js → timepicker.Dbl5KFh6.js} +4 -4
  139. streamlit/static/static/js/{toConsumableArray.BJvaP8gb.js → toConsumableArray.D-Dx88BQ.js} +3 -3
  140. streamlit/static/static/js/uniqueId.Bh26R_3S.js +1 -0
  141. streamlit/static/static/js/{useBasicWidgetState.DB3vMS9V.js → useBasicWidgetState.DeK-QJpD.js} +1 -1
  142. streamlit/static/static/js/{useTextInputAutoExpand.CBkGkaRt.js → useTextInputAutoExpand.4iAdLWD-.js} +2 -2
  143. streamlit/static/static/js/useUpdateUiValue.CmT7_nJN.js +1 -0
  144. streamlit/static/static/js/withFullScreenWrapper.DLp1ENGm.js +1 -0
  145. streamlit/static/static/media/MaterialSymbols-Rounded.CBxVaFdk.woff2 +0 -0
  146. streamlit/user_info.py +3 -1
  147. streamlit/web/server/browser_websocket_handler.py +15 -0
  148. {streamlit-1.48.1.dist-info → streamlit-1.49.1.dist-info}/METADATA +4 -2
  149. {streamlit-1.48.1.dist-info → streamlit-1.49.1.dist-info}/RECORD +153 -156
  150. streamlit/static/static/css/index.CQt5TjGB.css +0 -1
  151. streamlit/static/static/js/FileHelper.BrQvUXVD.js +0 -5
  152. streamlit/static/static/js/FormClearHelper.DF4gFAOO.js +0 -1
  153. streamlit/static/static/js/InputInstructions.D8zoMog9.js +0 -1
  154. streamlit/static/static/js/Particles.CCFySwdL.js +0 -1
  155. streamlit/static/static/js/ProgressBar.COK9j1l0.js +0 -2
  156. streamlit/static/static/js/Toolbar.Dt4jIKlY.js +0 -1
  157. streamlit/static/static/js/createSuper.siQeagI2.js +0 -1
  158. streamlit/static/static/js/data-grid-overlay-editor.Ct51iCb_.js +0 -1
  159. streamlit/static/static/js/es6.CMaUdEZ5.js +0 -2
  160. streamlit/static/static/js/iframeResizer.contentWindow.C33BryyP.js +0 -1
  161. streamlit/static/static/js/index.8GJD0eeD.js +0 -1
  162. streamlit/static/static/js/index.8QEYHMQD.js +0 -1
  163. streamlit/static/static/js/index.Ay41Wnu9.js +0 -1
  164. streamlit/static/static/js/index.BLiKiJ7_.js +0 -1
  165. streamlit/static/static/js/index.BT78cJmU.js +0 -1
  166. streamlit/static/static/js/index.BdGvnhlM.js +0 -1
  167. streamlit/static/static/js/index.BfasrT0d.js +0 -1
  168. streamlit/static/static/js/index.CCdtFMFG.js +0 -1
  169. streamlit/static/static/js/index.CFRGZDz1.js +0 -1
  170. streamlit/static/static/js/index.CFSFYiPA.js +0 -5366
  171. streamlit/static/static/js/index.CeiIiXap.js +0 -1
  172. streamlit/static/static/js/index.CzX2xpyc.js +0 -1
  173. streamlit/static/static/js/index.D1ErX5go.js +0 -2
  174. streamlit/static/static/js/index.D5gweoL5.js +0 -7
  175. streamlit/static/static/js/index.DByVKZgq.js +0 -1
  176. streamlit/static/static/js/index.DEND45D1.js +0 -3
  177. streamlit/static/static/js/index.DKN5MVff.js +0 -781
  178. streamlit/static/static/js/index.DfoxW1gP.js +0 -3855
  179. streamlit/static/static/js/index.Dtf1Ac0x.js +0 -1
  180. streamlit/static/static/js/index.DxrLhpeO.js +0 -1
  181. streamlit/static/static/js/index.J7o-_HIh.js +0 -1
  182. streamlit/static/static/js/index.LU8juINp.js +0 -197
  183. streamlit/static/static/js/index.L_N2iylt.js +0 -1
  184. streamlit/static/static/js/index.PZUX2kRz.js +0 -3
  185. streamlit/static/static/js/index.ROjU6K0k.js +0 -1
  186. streamlit/static/static/js/index.WSNLkF94.js +0 -1
  187. streamlit/static/static/js/index.X5W3gJLn.js +0 -1
  188. streamlit/static/static/js/index.k9LYqfSL.js +0 -1
  189. streamlit/static/static/js/index.pnHtHv_c.js +0 -203
  190. streamlit/static/static/js/index.tPUXqsfW.js +0 -1
  191. streamlit/static/static/js/mergeWith.GRNk8iwv.js +0 -1
  192. streamlit/static/static/js/number-overlay-editor.DXS2qb1U.js +0 -9
  193. streamlit/static/static/js/threshold.DjX0wlsa.js +0 -1
  194. streamlit/static/static/js/timer.CAwTRJ_g.js +0 -1
  195. streamlit/static/static/js/uniqueId.D_5M8Dgf.js +0 -1
  196. streamlit/static/static/js/useUpdateUiValue.C7ZKpLQK.js +0 -1
  197. streamlit/static/static/js/value.CgPGBV_l.js +0 -1
  198. streamlit/static/static/js/withFullScreenWrapper.C-gXt0Rl.js +0 -1
  199. streamlit/static/static/media/MaterialSymbols-Rounded.DsbC8sYI.woff2 +0 -0
  200. {streamlit-1.48.1.data → streamlit-1.49.1.data}/scripts/streamlit.cmd +0 -0
  201. {streamlit-1.48.1.dist-info → streamlit-1.49.1.dist-info}/WHEEL +0 -0
  202. {streamlit-1.48.1.dist-info → streamlit-1.49.1.dist-info}/entry_points.txt +0 -0
  203. {streamlit-1.48.1.dist-info → streamlit-1.49.1.dist-info}/top_level.txt +0 -0
@@ -33,6 +33,10 @@ from typing_extensions import TypeAlias
33
33
 
34
34
  from streamlit import dataframe_util
35
35
  from streamlit import logger as _logger
36
+ from streamlit.deprecation_util import (
37
+ make_deprecated_name_warning,
38
+ show_deprecation_warning,
39
+ )
36
40
  from streamlit.elements.lib.column_config_utils import (
37
41
  INDEX_IDENTIFIER,
38
42
  ColumnConfigMapping,
@@ -47,6 +51,12 @@ from streamlit.elements.lib.column_config_utils import (
47
51
  update_column_config,
48
52
  )
49
53
  from streamlit.elements.lib.form_utils import current_form_id
54
+ from streamlit.elements.lib.layout_utils import (
55
+ LayoutConfig,
56
+ Width,
57
+ validate_height,
58
+ validate_width,
59
+ )
50
60
  from streamlit.elements.lib.pandas_styler_utils import marshall_styler
51
61
  from streamlit.elements.lib.policies import check_widget_policies
52
62
  from streamlit.elements.lib.utils import Key, compute_and_register_element_id, to_key
@@ -60,7 +70,7 @@ from streamlit.runtime.state import (
60
70
  WidgetKwargs,
61
71
  register_widget,
62
72
  )
63
- from streamlit.type_util import is_type
73
+ from streamlit.type_util import is_list_like, is_type
64
74
  from streamlit.util import calc_md5
65
75
 
66
76
  if TYPE_CHECKING:
@@ -170,14 +180,14 @@ class DataEditorSerde:
170
180
 
171
181
 
172
182
  def _parse_value(
173
- value: str | int | float | bool | None,
183
+ value: str | int | float | bool | list[str] | None,
174
184
  column_data_kind: ColumnDataKind,
175
185
  ) -> Any:
176
186
  """Convert a value to the correct type.
177
187
 
178
188
  Parameters
179
189
  ----------
180
- value : str | int | float | bool | None
190
+ value : str | int | float | bool | list[str] | None
181
191
  The value to convert.
182
192
 
183
193
  column_data_kind : ColumnDataKind
@@ -194,9 +204,20 @@ def _parse_value(
194
204
  import pandas as pd
195
205
 
196
206
  try:
207
+ if column_data_kind == ColumnDataKind.LIST:
208
+ return list(value) if is_list_like(value) else [value] # ty: ignore
209
+
197
210
  if column_data_kind == ColumnDataKind.STRING:
198
211
  return str(value)
199
212
 
213
+ # List values aren't supported for anything else than list column data kind.
214
+ # To make the type checker happy, we raise a TypeError here. However,
215
+ # This isn't expected to happen.
216
+ if isinstance(value, list):
217
+ raise TypeError( # noqa: TRY301
218
+ "List values are only supported by list and string columns."
219
+ )
220
+
200
221
  if column_data_kind == ColumnDataKind.INTEGER:
201
222
  return int(value)
202
223
 
@@ -234,7 +255,7 @@ def _parse_value(
234
255
  if column_data_kind == ColumnDataKind.TIME:
235
256
  return datetime_value.time()
236
257
 
237
- except (ValueError, pd.errors.ParserError) as ex:
258
+ except (ValueError, pd.errors.ParserError, TypeError) as ex:
238
259
  _LOGGER.warning(
239
260
  "Failed to parse value %s as %s.",
240
261
  value,
@@ -247,7 +268,9 @@ def _parse_value(
247
268
 
248
269
  def _apply_cell_edits(
249
270
  df: pd.DataFrame,
250
- edited_rows: Mapping[int, Mapping[str, str | int | float | bool | None]],
271
+ edited_rows: Mapping[
272
+ int, Mapping[str, str | int | float | bool | list[str] | None]
273
+ ],
251
274
  dataframe_schema: DataframeSchema,
252
275
  ) -> None:
253
276
  """Apply cell edits to the provided dataframe (inplace).
@@ -278,7 +301,7 @@ def _apply_cell_edits(
278
301
  )
279
302
  else:
280
303
  col_pos = df.columns.get_loc(col_name)
281
- df.iloc[row_pos, col_pos] = _parse_value(
304
+ df.iat[row_pos, col_pos] = _parse_value(
282
305
  value, dataframe_schema[col_name]
283
306
  )
284
307
 
@@ -578,14 +601,14 @@ class DataEditorMixin:
578
601
  self,
579
602
  data: EditableData,
580
603
  *,
581
- width: int | None = None,
582
- height: int | None = None,
604
+ width: Width = "stretch",
605
+ height: int | Literal["auto"] = "auto",
583
606
  use_container_width: bool | None = None,
584
607
  hide_index: bool | None = None,
585
608
  column_order: Iterable[str] | None = None,
586
609
  column_config: ColumnConfigMappingInput | None = None,
587
610
  num_rows: Literal["fixed", "dynamic"] = "fixed",
588
- disabled: bool | Iterable[str] = False,
611
+ disabled: bool | Iterable[str | int] = False,
589
612
  key: Key | None = None,
590
613
  on_change: WidgetCallback | None = None,
591
614
  args: WidgetArgs | None = None,
@@ -599,14 +622,14 @@ class DataEditorMixin:
599
622
  self,
600
623
  data: Any,
601
624
  *,
602
- width: int | None = None,
603
- height: int | None = None,
625
+ width: Width = "stretch",
626
+ height: int | Literal["auto"] = "auto",
604
627
  use_container_width: bool | None = None,
605
628
  hide_index: bool | None = None,
606
629
  column_order: Iterable[str] | None = None,
607
630
  column_config: ColumnConfigMappingInput | None = None,
608
631
  num_rows: Literal["fixed", "dynamic"] = "fixed",
609
- disabled: bool | Iterable[str] = False,
632
+ disabled: bool | Iterable[str | int] = False,
610
633
  key: Key | None = None,
611
634
  on_change: WidgetCallback | None = None,
612
635
  args: WidgetArgs | None = None,
@@ -620,14 +643,14 @@ class DataEditorMixin:
620
643
  self,
621
644
  data: DataTypes,
622
645
  *,
623
- width: int | None = None,
624
- height: int | None = None,
646
+ width: Width = "stretch",
647
+ height: int | Literal["auto"] = "auto",
625
648
  use_container_width: bool | None = None,
626
649
  hide_index: bool | None = None,
627
650
  column_order: Iterable[str] | None = None,
628
651
  column_config: ColumnConfigMappingInput | None = None,
629
652
  num_rows: Literal["fixed", "dynamic"] = "fixed",
630
- disabled: bool | Iterable[str] = False,
653
+ disabled: bool | Iterable[str | int] = False,
631
654
  key: Key | None = None,
632
655
  on_change: WidgetCallback | None = None,
633
656
  args: WidgetArgs | None = None,
@@ -649,7 +672,7 @@ class DataEditorMixin:
649
672
  precedence over text and number formatting from ``pandas.Styler``.
650
673
  - Mixing data types within a column can make the column uneditable.
651
674
  - Additionally, the following data types are not yet supported for editing:
652
- ``complex``, ``list``, ``tuple``, ``bytes``, ``bytearray``,
675
+ ``complex``, ``tuple``, ``bytes``, ``bytearray``,
653
676
  ``memoryview``, ``dict``, ``set``, ``frozenset``,
654
677
  ``fractions.Fraction``, ``pandas.Interval``, and
655
678
  ``pandas.Period``.
@@ -658,18 +681,28 @@ class DataEditorMixin:
658
681
  default to uneditable, but this can be changed through column
659
682
  configuration.
660
683
 
661
- width : int or None
662
- Desired width of the data editor expressed in pixels. If ``width``
663
- is ``None`` (default), Streamlit sets the data editor width to fit
664
- its contents up to the width of the parent container. If ``width``
665
- is greater than the width of the parent container, Streamlit sets
666
- the data editor width to match the width of the parent container.
684
+ width : "stretch", "content", or int
685
+ The width of the data editor. This can be one of the following:
686
+
687
+ - ``"stretch"`` (default): The width of the editor matches the
688
+ width of the parent container.
689
+ - ``"content"``: The width of the editor matches the width of its
690
+ content, but doesn't exceed the width of the parent container.
691
+ - An integer specifying the width in pixels: The editor has a
692
+ fixed width. If the specified width is greater than the width of
693
+ the parent container, the width of the editor matches the width
694
+ of the parent container.
667
695
 
668
- height : int or None
669
- Desired height of the data editor expressed in pixels. If ``height``
670
- is ``None`` (default), Streamlit sets the height to show at most
671
- ten rows. Vertical scrolling within the data editor element is
672
- enabled when the height does not accommodate all rows.
696
+ height : int or "auto"
697
+ The height of the data editor. This can be one of the following:
698
+
699
+ - ``"auto"`` (default): Streamlit sets the height to show at most
700
+ ten rows.
701
+ - An integer specifying the height in pixels: The editor has a
702
+ fixed height.
703
+
704
+ Vertical scrolling within the data editor is enabled when the
705
+ height does not accommodate all rows.
673
706
 
674
707
  use_container_width : bool
675
708
  Whether to override ``width`` with the width of the parent
@@ -683,28 +716,42 @@ class DataEditorMixin:
683
716
  (default), the visibility of index columns is automatically
684
717
  determined based on the data.
685
718
 
686
- column_order : Iterable of str or None
687
- Specifies the display order of columns. This also affects which columns are
688
- visible. For example, ``column_order=("col2", "col1")`` will display 'col2'
689
- first, followed by 'col1', and will hide all other non-index columns. If
690
- None (default), the order is inherited from the original data structure.
719
+ column_order : Iterable[str] or None
720
+ The ordered list of columns to display. If this is ``None``
721
+ (default), Streamlit displays all columns in the order inherited
722
+ from the underlying data structure. If this is a list, the
723
+ indicated columns will display in the order they appear within the
724
+ list. Columns may be omitted or repeated within the list.
725
+
726
+ For example, ``column_order=("col2", "col1")`` will display
727
+ ``"col2"`` first, followed by ``"col1"``, and will hide all other
728
+ non-index columns.
729
+
730
+ ``column_order`` does not accept positional column indices and
731
+ can't move the index column(s).
691
732
 
692
733
  column_config : dict or None
693
- Configures how columns are displayed, e.g. their title, visibility, type, or
694
- format, as well as editing properties such as min/max value or step.
695
- This needs to be a dictionary where each key is a column name and the value
696
- is one of:
734
+ Configuration to customize how columns are displayed. If this is
735
+ ``None`` (default), columns are styled based on the underlying data
736
+ type of each column.
697
737
 
698
- - ``None`` to hide the column.
738
+ Column configuration can modify column names, visibility, type,
739
+ width, format, editing properties like min/max, and more. If this
740
+ is a dictionary, the keys are column names (strings) and/or
741
+ positional column indices (integers), and the values are one of the
742
+ following:
699
743
 
744
+ - ``None`` to hide the column.
700
745
  - A string to set the display label of the column.
746
+ - One of the column types defined under ``st.column_config``. For
747
+ example, to show a column as dollar amounts, use
748
+ ``st.column_config.NumberColumn("Dollar values", format="$ %d")``.
749
+ See more info on the available column types and config options
750
+ `here <https://docs.streamlit.io/develop/api-reference/data/st.column_config>`_.
701
751
 
702
- - One of the column types defined under ``st.column_config``, e.g.
703
- ``st.column_config.NumberColumn("Dollar values", format="$ %d")`` to show
704
- a column as dollar amounts. See more info on the available column types
705
- and config options `here <https://docs.streamlit.io/develop/api-reference/data/st.column_config>`_.
706
-
707
- To configure the index column(s), use ``_index`` as the column name.
752
+ To configure the index column(s), use ``"_index"`` as the column
753
+ name, or use a positional column index where ``0`` refers to the
754
+ first index column.
708
755
 
709
756
  num_rows : "fixed" or "dynamic"
710
757
  Specifies if the user can add and delete rows in the data editor.
@@ -712,11 +759,20 @@ class DataEditorMixin:
712
759
  add and delete rows in the data editor, but column sorting is disabled.
713
760
  Defaults to "fixed".
714
761
 
715
- disabled : bool or Iterable of str
716
- Controls the editing of columns. If True, editing is disabled for all columns.
717
- If an Iterable of column names is provided (e.g., ``disabled=("col1", "col2"))``,
718
- only the specified columns will be disabled for editing. If False (default),
719
- all columns that support editing are editable.
762
+ disabled : bool or Iterable[str | int]
763
+ Controls the editing of columns. This can be one of the following:
764
+
765
+ - ``False`` (default): All columns that support editing are editable.
766
+ - ``True``: All columns are disabled for editing.
767
+ - An Iterable of column names and/or positional indices: The
768
+ specified columns are disabled for editing while the remaining
769
+ columns are editable where supported. For example,
770
+ ``disabled=["col1", "col2"]`` will disable editing for the
771
+ columns named "col1" and "col2".
772
+
773
+ To disable editing for the index column(s), use ``"_index"`` as the
774
+ column name, or use a positional column index where ``0`` refers to
775
+ the first index column.
720
776
 
721
777
  key : str
722
778
  An optional string to use as the unique key for this widget. If this
@@ -737,6 +793,11 @@ class DataEditorMixin:
737
793
  is ``None`` (default), Streamlit will use a default row height,
738
794
  which fits one line of text.
739
795
 
796
+ .. deprecated::
797
+ ``use_container_width`` is deprecated and will be removed in a
798
+ future release. For ``use_container_width=True``, use
799
+ ``width="stretch"``.
800
+
740
801
  Returns
741
802
  -------
742
803
  pandas.DataFrame, pandas.Series, pyarrow.Table, numpy.ndarray, list, set, tuple, or dict.
@@ -839,6 +900,14 @@ class DataEditorMixin:
839
900
 
840
901
  key = to_key(key)
841
902
 
903
+ validate_width(width, allow_content=True)
904
+ validate_height(
905
+ height,
906
+ allow_content=False,
907
+ allow_stretch=False,
908
+ additional_allowed=["auto"],
909
+ )
910
+
842
911
  check_widget_policies(
843
912
  self.dg,
844
913
  key,
@@ -847,6 +916,23 @@ class DataEditorMixin:
847
916
  writes_allowed=False,
848
917
  )
849
918
 
919
+ if use_container_width is not None:
920
+ show_deprecation_warning(
921
+ make_deprecated_name_warning(
922
+ "use_container_width",
923
+ "width",
924
+ "2025-12-31",
925
+ "For `use_container_width=True`, use `width='stretch'`. "
926
+ "For `use_container_width=False`, use `width='content'`.",
927
+ include_st_prefix=False,
928
+ ),
929
+ show_in_browser=False,
930
+ )
931
+ if use_container_width:
932
+ width = "stretch"
933
+ elif not isinstance(width, int):
934
+ width = "content"
935
+
850
936
  if column_order is not None:
851
937
  column_order = list(column_order)
852
938
 
@@ -942,7 +1028,6 @@ class DataEditorMixin:
942
1028
  element_id = compute_and_register_element_id(
943
1029
  "data_editor",
944
1030
  user_key=key,
945
- form_id=current_form_id(self.dg),
946
1031
  dg=self.dg,
947
1032
  data=arrow_bytes,
948
1033
  width=width,
@@ -957,18 +1042,6 @@ class DataEditorMixin:
957
1042
  proto = ArrowProto()
958
1043
  proto.id = element_id
959
1044
 
960
- if use_container_width is None:
961
- # If use_container_width was not explicitly set by the user, we set
962
- # it to True if width was not set explicitly, and False otherwise.
963
- use_container_width = width is None
964
-
965
- proto.use_container_width = use_container_width
966
-
967
- if width:
968
- proto.width = width
969
- if height:
970
- proto.height = height
971
-
972
1045
  if row_height:
973
1046
  proto.row_height = row_height
974
1047
 
@@ -1005,6 +1078,13 @@ class DataEditorMixin:
1005
1078
 
1006
1079
  marshall_column_config(proto, column_config_mapping)
1007
1080
 
1081
+ # Create layout configuration
1082
+ # For height, only include it in LayoutConfig if it's not "auto"
1083
+ # "auto" is the default behavior and doesn't need to be sent
1084
+ layout_config = LayoutConfig(
1085
+ width=width, height=height if height != "auto" else None
1086
+ )
1087
+
1008
1088
  serde = DataEditorSerde()
1009
1089
 
1010
1090
  widget_state = register_widget(
@@ -1019,7 +1099,7 @@ class DataEditorMixin:
1019
1099
  )
1020
1100
 
1021
1101
  _apply_dataframe_edits(data_df, widget_state.value, dataframe_schema)
1022
- self.dg._enqueue("arrow_data_frame", proto)
1102
+ self.dg._enqueue("arrow_data_frame", proto, layout_config=layout_config)
1023
1103
  return dataframe_util.convert_pandas_df_to_data_format(data_df, data_format)
1024
1104
 
1025
1105
  @property
@@ -67,6 +67,12 @@ SomeUploadedFiles: TypeAlias = Union[
67
67
  None,
68
68
  ]
69
69
 
70
+ # Type alias for accept_multiple_files parameter.
71
+ # If True, multiple files can be uploaded.
72
+ # If False, only a single file can be uploaded.
73
+ # If set to the literal "directory", users can upload an entire directory (folder) of files.
74
+ AcceptMultipleFiles: TypeAlias = Union[bool, Literal["directory"]]
75
+
70
76
 
71
77
  def _get_upload_files(
72
78
  widget_value: FileUploaderStateProto | None,
@@ -104,7 +110,7 @@ def _get_upload_files(
104
110
 
105
111
  @dataclass
106
112
  class FileUploaderSerde:
107
- accept_multiple_files: bool
113
+ accept_multiple_files: AcceptMultipleFiles
108
114
  allowed_types: Sequence[str] | None = None
109
115
 
110
116
  def deserialize(self, ui_value: FileUploaderStateProto | None) -> SomeUploadedFiles:
@@ -117,12 +123,16 @@ class FileUploaderSerde:
117
123
  if self.allowed_types:
118
124
  enforce_filename_restriction(file.name, self.allowed_types)
119
125
 
126
+ # Directory uploads always return a list, similar to multiple files
127
+ is_multiple_or_directory = (
128
+ self.accept_multiple_files is True
129
+ or self.accept_multiple_files == "directory"
130
+ )
131
+
120
132
  if len(upload_files) == 0:
121
- return_value: SomeUploadedFiles = [] if self.accept_multiple_files else None
133
+ return_value: SomeUploadedFiles = [] if is_multiple_or_directory else None
122
134
  else:
123
- return_value = (
124
- upload_files if self.accept_multiple_files else upload_files[0]
125
- )
135
+ return_value = upload_files if is_multiple_or_directory else upload_files[0]
126
136
  return return_value
127
137
 
128
138
  def serialize(self, files: SomeUploadedFiles) -> FileUploaderStateProto:
@@ -149,21 +159,22 @@ class FileUploaderMixin:
149
159
  # Multiple overloads are defined on `file_uploader()` below to represent
150
160
  # the different return types of `file_uploader()`.
151
161
  # These return types differ according to the value of the `accept_multiple_files` argument.
152
- # There are 2 associated variables, each with 2 options.
153
- # 1. The `accept_multiple_files` argument is set as `True`,
154
- # or it is set as `False` or omitted, in which case the default value `False`.
155
- # 2. The `type` argument may or may not be provided as a keyword-only argument.
156
162
  # There must be 2x2=4 overloads to cover all the possible arguments,
157
163
  # as these overloads must be mutually exclusive for mypy.
164
+ # There are 3 associated variables, each with 2+ options.
165
+ # 1. The `accept_multiple_files` argument is set as `True` or `"directory"`,
166
+ # or it is set as `False` or omitted, in which case the default value `False`.
167
+ # 2. The `type` argument may or may not be provided as a keyword-only argument.
168
+ # 3. Directory uploads always return a list of UploadedFile objects.
158
169
 
159
170
  # 1. type is given as not a keyword-only argument
160
- # 2. accept_multiple_files = True
171
+ # 2. accept_multiple_files = True or "directory"
161
172
  @overload
162
173
  def file_uploader(
163
174
  self,
164
175
  label: str,
165
176
  type: str | Sequence[str] | None,
166
- accept_multiple_files: Literal[True],
177
+ accept_multiple_files: Literal[True, "directory"],
167
178
  key: Key | None = None,
168
179
  help: str | None = None,
169
180
  on_change: WidgetCallback | None = None,
@@ -200,13 +211,13 @@ class FileUploaderMixin:
200
211
  # for the related discussions and examples.
201
212
 
202
213
  # 1. type is skipped or a keyword argument
203
- # 2. accept_multiple_files = True
214
+ # 2. accept_multiple_files = True or "directory"
204
215
  @overload
205
216
  def file_uploader(
206
217
  self,
207
218
  label: str,
208
219
  *,
209
- accept_multiple_files: Literal[True],
220
+ accept_multiple_files: Literal[True, "directory"],
210
221
  type: str | Sequence[str] | None = None,
211
222
  key: Key | None = None,
212
223
  help: str | None = None,
@@ -242,7 +253,7 @@ class FileUploaderMixin:
242
253
  self,
243
254
  label: str,
244
255
  type: str | Sequence[str] | None = None,
245
- accept_multiple_files: bool = False,
256
+ accept_multiple_files: AcceptMultipleFiles = False,
246
257
  key: Key | None = None,
247
258
  help: str | None = None,
248
259
  on_change: WidgetCallback | None = None,
@@ -285,7 +296,7 @@ class FileUploaderMixin:
285
296
  .. |st.markdown| replace:: ``st.markdown``
286
297
  .. _st.markdown: https://docs.streamlit.io/develop/api-reference/text/st.markdown
287
298
 
288
- type : str or list of str or None
299
+ type : str, list of str, or None
289
300
  The allowed file extension(s) for uploaded files. This can be one
290
301
  of the following types:
291
302
 
@@ -302,11 +313,19 @@ class FileUploaderMixin:
302
313
  or type extensions. The correct handling of uploaded files is
303
314
  part of the app developer's responsibility.
304
315
 
305
- accept_multiple_files : bool
306
- Whether to accept more than one file in a submission. If this is
307
- ``False`` (default), the user can only submit one file at a time.
308
- If this is ``True``, the user can upload multiple files at the same
309
- time, in which case the return value will be a list of files.
316
+ accept_multiple_files : bool or "directory"
317
+ Whether to accept more than one file in a submission. This can be one
318
+ of the following values:
319
+
320
+ - ``False`` (default): The user can only submit one file at a time.
321
+ - ``True``: The user can upload multiple files at the same time.
322
+ - ``"directory"``: The user can select a directory to upload all
323
+ files in the directory and its subdirectories. If ``type`` is
324
+ set, only files matching those type(s) will be uploaded.
325
+
326
+ When this is ``True`` or ``"directory"``, the return value will be
327
+ a list and a user can additively select files if they click the
328
+ browse button on the widget multiple times.
310
329
 
311
330
  key : str or int
312
331
  An optional string or integer to use as the unique key for the widget.
@@ -356,19 +375,19 @@ class FileUploaderMixin:
356
375
  Returns
357
376
  -------
358
377
  None, UploadedFile, or list of UploadedFile
359
- - If accept_multiple_files is False, returns either None or
360
- an UploadedFile object.
361
- - If accept_multiple_files is True, returns a list with the
362
- uploaded files as UploadedFile objects. If no files were
363
- uploaded, returns an empty list.
378
+ - If accept_multiple_files is ``False``, returns either ``None`` or
379
+ an ``UploadedFile`` object.
380
+ - If accept_multiple_files is ``True`` or ``"directory"``, returns
381
+ a list with the uploaded files as ``UploadedFile`` objects. If no
382
+ files were uploaded, returns an empty list.
364
383
 
365
- The UploadedFile class is a subclass of BytesIO, and therefore is
366
- "file-like". This means you can pass an instance of it anywhere a
367
- file is expected.
384
+ The ``UploadedFile`` class is a subclass of ``BytesIO``, and
385
+ therefore is "file-like". This means you can pass an instance of it
386
+ anywhere a file is expected.
368
387
 
369
388
  Examples
370
389
  --------
371
- Insert a file uploader that accepts a single file at a time:
390
+ **Example 1: Accept a single file at a time**
372
391
 
373
392
  >>> import streamlit as st
374
393
  >>> import pandas as pd
@@ -392,22 +411,36 @@ class FileUploaderMixin:
392
411
  ... dataframe = pd.read_csv(uploaded_file)
393
412
  ... st.write(dataframe)
394
413
 
395
- Insert a file uploader that accepts multiple files at a time:
414
+ **Example 2: Accept multiple files at a time**
396
415
 
416
+ >>> import pandas as pd
397
417
  >>> import streamlit as st
398
418
  >>>
399
419
  >>> uploaded_files = st.file_uploader(
400
- ... "Choose a CSV file", accept_multiple_files=True
420
+ ... "Upload data", accept_multiple_files=True, type="csv"
401
421
  ... )
402
422
  >>> for uploaded_file in uploaded_files:
403
- ... bytes_data = uploaded_file.read()
404
- ... st.write("filename:", uploaded_file.name)
405
- ... st.write(bytes_data)
423
+ ... df = pd.read_csv(uploaded_file)
424
+ ... st.write(df)
406
425
 
407
426
  .. output::
408
427
  https://doc-file-uploader.streamlit.app/
409
428
  height: 375px
410
429
 
430
+ **Example 3: Accept an entire directory**
431
+
432
+ >>> import streamlit as st
433
+ >>>
434
+ >>> uploaded_files = st.file_uploader(
435
+ ... "Upload images", accept_multiple_files="directory", type=["jpg", "png"]
436
+ ... )
437
+ >>> for uploaded_file in uploaded_files:
438
+ ... st.image(uploaded_file)
439
+
440
+ .. output::
441
+ https://doc-file-uploader-directory.streamlit.app/
442
+ height: 375px
443
+
411
444
  """
412
445
  ctx = get_script_run_ctx()
413
446
  return self._file_uploader(
@@ -429,7 +462,7 @@ class FileUploaderMixin:
429
462
  self,
430
463
  label: str,
431
464
  type: str | Sequence[str] | None = None,
432
- accept_multiple_files: bool = False,
465
+ accept_multiple_files: AcceptMultipleFiles = False,
433
466
  key: Key | None = None,
434
467
  help: str | None = None,
435
468
  on_change: WidgetCallback | None = None,
@@ -455,7 +488,6 @@ class FileUploaderMixin:
455
488
  element_id = compute_and_register_element_id(
456
489
  "file_uploader",
457
490
  user_key=key,
458
- form_id=current_form_id(self.dg),
459
491
  dg=self.dg,
460
492
  label=label,
461
493
  type=type,
@@ -475,7 +507,12 @@ class FileUploaderMixin:
475
507
  file_uploader_proto.max_upload_size_mb = config.get_option(
476
508
  "server.maxUploadSize"
477
509
  )
478
- file_uploader_proto.multiple_files = accept_multiple_files
510
+ # Handle directory uploads - they should enable multiple files and set the directory flag
511
+ is_directory_upload = accept_multiple_files == "directory"
512
+ file_uploader_proto.multiple_files = (
513
+ accept_multiple_files is True or is_directory_upload
514
+ )
515
+ file_uploader_proto.accept_directory = is_directory_upload
479
516
  file_uploader_proto.form_id = current_form_id(self.dg)
480
517
  file_uploader_proto.disabled = disabled
481
518
  file_uploader_proto.label_visibility.value = get_label_visibility_proto_value(
@@ -492,7 +492,6 @@ class MultiSelectMixin:
492
492
  element_id = compute_and_register_element_id(
493
493
  widget_name,
494
494
  user_key=key,
495
- form_id=form_id,
496
495
  dg=self.dg,
497
496
  label=label,
498
497
  options=formatted_options,
@@ -452,7 +452,6 @@ class NumberInputMixin:
452
452
  element_id = compute_and_register_element_id(
453
453
  "number_input",
454
454
  user_key=key,
455
- form_id=current_form_id(self.dg),
456
455
  dg=self.dg,
457
456
  label=label,
458
457
  min_value=min_value,
@@ -369,7 +369,6 @@ class RadioMixin:
369
369
  element_id = compute_and_register_element_id(
370
370
  "radio",
371
371
  user_key=key,
372
- form_id=current_form_id(self.dg),
373
372
  dg=self.dg,
374
373
  label=label,
375
374
  options=[str(format_func(option)) for option in opt],
@@ -377,7 +377,6 @@ class SelectSliderMixin:
377
377
  element_id = compute_and_register_element_id(
378
378
  "select_slider",
379
379
  user_key=key,
380
- form_id=current_form_id(self.dg),
381
380
  dg=self.dg,
382
381
  label=label,
383
382
  options=[str(format_func(option)) for option in opt],
@@ -541,7 +541,6 @@ class SelectboxMixin:
541
541
  element_id = compute_and_register_element_id(
542
542
  "selectbox",
543
543
  user_key=key,
544
- form_id=current_form_id(self.dg),
545
544
  dg=self.dg,
546
545
  label=label,
547
546
  options=formatted_options,
@@ -680,7 +680,6 @@ class SliderMixin:
680
680
  element_id = compute_and_register_element_id(
681
681
  "slider",
682
682
  user_key=key,
683
- form_id=current_form_id(self.dg),
684
683
  dg=self.dg,
685
684
  label=label,
686
685
  min_value=min_value,