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
streamlit/__init__.py CHANGED
@@ -93,10 +93,7 @@ _event = _dg_singleton._event_dg
93
93
  _bottom = _dg_singleton._bottom_dg
94
94
 
95
95
 
96
- from streamlit.elements.dialog_decorator import (
97
- dialog_decorator as _dialog_decorator,
98
- experimental_dialog_decorator as _experimental_dialog_decorator,
99
- )
96
+ from streamlit.elements.dialog_decorator import dialog_decorator as _dialog_decorator
100
97
  from streamlit.runtime.caching import (
101
98
  cache_resource as _cache_resource,
102
99
  cache_data as _cache_data,
@@ -105,10 +102,7 @@ from streamlit.runtime.caching import (
105
102
  from streamlit.runtime.connection_factory import (
106
103
  connection_factory as _connection,
107
104
  )
108
- from streamlit.runtime.fragment import (
109
- experimental_fragment as _experimental_fragment,
110
- fragment as _fragment,
111
- )
105
+ from streamlit.runtime.fragment import fragment as _fragment
112
106
  from streamlit.runtime.metrics_util import gather_metrics as _gather_metrics
113
107
  from streamlit.runtime.secrets import secrets_singleton as _secrets_singleton
114
108
  from streamlit.runtime.context import ContextProxy as _ContextProxy
@@ -212,6 +206,7 @@ metric = _main.metric
212
206
  multiselect = _main.multiselect
213
207
  number_input = _main.number_input
214
208
  page_link = _main.page_link
209
+ pdf = _main.pdf
215
210
  pills = _main.pills
216
211
  plotly_chart = _main.plotly_chart
217
212
  popover = _main.popover
@@ -283,8 +278,6 @@ logout = _logout
283
278
  user = _UserInfoProxy()
284
279
 
285
280
  # Experimental APIs
286
- experimental_dialog = _experimental_dialog_decorator
287
- experimental_fragment = _experimental_fragment
288
281
  experimental_user = _DeprecatedUserInfoProxy()
289
282
 
290
283
  _EXPERIMENTAL_QUERY_PARAMS_DEPRECATE_MSG = (
@@ -19,7 +19,8 @@ from __future__ import annotations
19
19
  from typing import Literal
20
20
 
21
21
  from streamlit import url_util
22
- from streamlit.elements.lib.image_utils import AtomicImage, WidthBehavior, image_to_url
22
+ from streamlit.elements.lib.image_utils import AtomicImage, image_to_url
23
+ from streamlit.elements.lib.layout_utils import LayoutConfig
23
24
  from streamlit.errors import StreamlitAPIException
24
25
  from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
25
26
  from streamlit.runtime.metrics_util import gather_metrics
@@ -142,7 +143,7 @@ def logo(
142
143
  try:
143
144
  image_url = image_to_url(
144
145
  image,
145
- width=WidthBehavior.AUTO,
146
+ layout_config=LayoutConfig(width="content"),
146
147
  clamp=False,
147
148
  channels="RGB",
148
149
  output_format="auto",
@@ -166,7 +167,7 @@ def logo(
166
167
  try:
167
168
  icon_image_url = image_to_url(
168
169
  icon_image,
169
- width=WidthBehavior.AUTO,
170
+ layout_config=LayoutConfig(width="content"),
170
171
  clamp=False,
171
172
  channels="RGB",
172
173
  output_format="auto",
@@ -316,7 +316,7 @@ def _navigation(
316
316
  else:
317
317
  nav_sections = {
318
318
  section: [convert_to_streamlit_page(p) for p in section_pages]
319
- for section, section_pages in pages.items()
319
+ for section, section_pages in pages.items() # ty: ignore[possibly-unbound-attribute]
320
320
  }
321
321
  page_list = pages_from_nav_sections(nav_sections)
322
322
 
@@ -23,6 +23,7 @@ from typing import TYPE_CHECKING, Any, Final, Literal, Union, cast
23
23
  from typing_extensions import TypeAlias
24
24
 
25
25
  from streamlit.elements.lib.image_utils import AtomicImage, image_to_url
26
+ from streamlit.elements.lib.layout_utils import LayoutConfig
26
27
  from streamlit.errors import (
27
28
  StreamlitInvalidMenuItemKeyError,
28
29
  StreamlitInvalidPageLayoutError,
@@ -91,7 +92,9 @@ def _get_favicon_string(page_icon: PageIcon) -> str:
91
92
  try:
92
93
  return image_to_url(
93
94
  page_icon,
94
- width=-1, # Always use full width for favicons
95
+ layout_config=LayoutConfig(
96
+ width="stretch"
97
+ ), # Always use full width for favicons
95
98
  clamp=False,
96
99
  channels="RGB",
97
100
  output_format="auto",
@@ -194,7 +194,7 @@ And if you're using Streamlit Cloud, add "pyarrow" to your requirements.txt."""
194
194
  computed_id = compute_and_register_element_id(
195
195
  "component_instance",
196
196
  user_key=key,
197
- form_id=current_form_id(dg),
197
+ dg=dg,
198
198
  name=self.name,
199
199
  url=self.url,
200
200
  json_args=serialized_json_args,
@@ -204,7 +204,7 @@ And if you're using Streamlit Cloud, add "pyarrow" to your requirements.txt."""
204
204
  computed_id = compute_and_register_element_id(
205
205
  "component_instance",
206
206
  user_key=key,
207
- form_id=current_form_id(dg),
207
+ dg=dg,
208
208
  name=self.name,
209
209
  url=self.url,
210
210
  )
streamlit/config.py CHANGED
@@ -17,6 +17,7 @@
17
17
  from __future__ import annotations
18
18
 
19
19
  import copy
20
+ import json
20
21
  import logging
21
22
  import os
22
23
  import secrets
@@ -960,12 +961,39 @@ _create_option(
960
961
 
961
962
  The server may choose to clean up session state, uploaded files, etc
962
963
  for a given session with no active websocket connection at any point
963
- after this time has passed.
964
+ after this time has passed. If you are using load balancing or
965
+ replication in your deployment, you must enable session stickiness
966
+ in your proxy to guarantee reconnection to the existing session. For
967
+ more information, see https://docs.streamlit.io/replication.
964
968
  """,
965
969
  default_val=120,
966
970
  type_=int,
967
971
  )
968
972
 
973
+ _create_option(
974
+ "server.trustedUserHeaders",
975
+ description="""
976
+ HTTP headers to embed in st.user.
977
+
978
+ Configures HTTP headers whose values, on websocket connect, will be saved in
979
+ st.user. Each key is the header name to map, and each value is the key in
980
+ st.user to save the value under. If the configured header occurs multiple times
981
+ in the request, the first value will be used. Multiple headers may not point to
982
+ the same user key, and an error will be thrown on initialization if this is
983
+ done.
984
+
985
+ If configured using an environment variable or CLI option, it should be a
986
+ single JSON-formatted dict of string-to-string.
987
+
988
+ Note: This is an experimental API subject to change.
989
+ """,
990
+ default_val={},
991
+ # This is used by click. We accept a JSON string, so this is a str.
992
+ type_=str,
993
+ # Hide until API is finalized.
994
+ visibility="hidden",
995
+ )
996
+
969
997
  # Config Section: Browser #
970
998
 
971
999
  _create_section("browser", "Configuration of non-UI browser options.")
@@ -1987,6 +2015,56 @@ def _set_development_mode() -> None:
1987
2015
  development.is_development_mode = get_option("global.developmentMode")
1988
2016
 
1989
2017
 
2018
+ def _parse_trusted_user_headers() -> None:
2019
+ """Convert string-valued server.trustedUserHeaders to a dict.
2020
+
2021
+ If server.trustedUserHeaders is configured from an environment variable or from
2022
+ the CLI, it will be a JSON string. Parse this and set the value to the resulting
2023
+ dict, after validation.
2024
+ """
2025
+ options = get_config_options()
2026
+ trusted_user_headers = options["server.trustedUserHeaders"]
2027
+ if isinstance(trusted_user_headers.value, str):
2028
+ try:
2029
+ parsed_value = json.loads(trusted_user_headers.value)
2030
+ # Validate that this is an object with string values.
2031
+ if not isinstance(parsed_value, dict):
2032
+ # Config validation is using RuntimeError deliberately; ignore warning
2033
+ # about making this TypeError.
2034
+ # ruff: noqa: TRY004
2035
+ raise RuntimeError("server.trustedUserHeaders JSON must be an object")
2036
+ for json_key, json_value in parsed_value.items():
2037
+ if not isinstance(json_value, str):
2038
+ raise RuntimeError(
2039
+ "server.trustedUserHeaders JSON must only have string values. "
2040
+ f'got bad value for key "{json_key}": {json_value}'
2041
+ )
2042
+ set_option(
2043
+ "server.trustedUserHeaders",
2044
+ parsed_value,
2045
+ where_defined=trusted_user_headers.where_defined,
2046
+ )
2047
+ except json.JSONDecodeError as jde:
2048
+ raise RuntimeError(
2049
+ f"bad JSON value for server.trustedUserHeaders: {jde.msg}"
2050
+ )
2051
+
2052
+ # Fetch the latest value, since we might've updated it from JSON.
2053
+ final_config_value = options["server.trustedUserHeaders"].value
2054
+ # Ensure no user keys are duplicated.
2055
+ values = set()
2056
+ bad_keys = []
2057
+ for user_key in final_config_value.values():
2058
+ if user_key in values:
2059
+ bad_keys.append(user_key)
2060
+ values.add(user_key)
2061
+
2062
+ if bad_keys:
2063
+ raise RuntimeError(
2064
+ f"server.trustedUserHeaders had multiple mappings for user key(s) {bad_keys}"
2065
+ )
2066
+
2067
+
1990
2068
  def on_config_parsed(
1991
2069
  func: Callable[[], None], force_connect: bool = False, lock: bool = False
1992
2070
  ) -> Callable[[], None]:
@@ -2046,3 +2124,6 @@ def on_config_parsed(
2046
2124
  # may edit config options based on the values of other config options.
2047
2125
  on_config_parsed(_check_conflicts, lock=True)
2048
2126
  on_config_parsed(_set_development_mode)
2127
+ # Update server.trustedUserHeaders from any JSON string that was set. Take out the
2128
+ # lock, since this is mutating the config.
2129
+ on_config_parsed(_parse_trusted_user_headers, lock=True)
@@ -73,7 +73,9 @@ class SnowflakeConnection(BaseConnection["InternalSnowflakeConnection"]):
73
73
  must be installed in your environment to use this connection. You can
74
74
  install it as an extra with Streamlit:
75
75
 
76
- >>> pip install streamlit[snowflake]
76
+ .. code-block:: shell
77
+
78
+ pip install streamlit[snowflake]
77
79
 
78
80
  .. Important::
79
81
  Account identifiers must be of the form ``<orgname>-<account_name>``
@@ -71,6 +71,7 @@ from streamlit.elements.map import MapMixin
71
71
  from streamlit.elements.markdown import MarkdownMixin
72
72
  from streamlit.elements.media import MediaMixin
73
73
  from streamlit.elements.metric import MetricMixin
74
+ from streamlit.elements.pdf import PdfMixin
74
75
  from streamlit.elements.plotly_chart import PlotlyMixin
75
76
  from streamlit.elements.progress import ProgressMixin
76
77
  from streamlit.elements.pyplot import PyplotMixin
@@ -196,6 +197,7 @@ class DeltaGenerator(
196
197
  MetricMixin,
197
198
  MultiSelectMixin,
198
199
  NumberInputMixin,
200
+ PdfMixin,
199
201
  PlotlyMixin,
200
202
  ProgressMixin,
201
203
  PydeckMixin,
@@ -533,6 +535,7 @@ class DeltaGenerator(
533
535
  invoked_dg_id=self.id,
534
536
  used_dg_id=dg.id,
535
537
  returned_dg_id=output_dg.id,
538
+ layout_config=layout_config,
536
539
  )
537
540
 
538
541
  return output_dg
@@ -29,6 +29,10 @@ from typing import (
29
29
  from typing_extensions import TypeAlias
30
30
 
31
31
  from streamlit import dataframe_util
32
+ from streamlit.deprecation_util import (
33
+ make_deprecated_name_warning,
34
+ show_deprecation_warning,
35
+ )
32
36
  from streamlit.elements.lib.column_config_utils import (
33
37
  INDEX_IDENTIFIER,
34
38
  ColumnConfigMappingInput,
@@ -40,6 +44,9 @@ from streamlit.elements.lib.column_config_utils import (
40
44
  from streamlit.elements.lib.form_utils import current_form_id
41
45
  from streamlit.elements.lib.layout_utils import (
42
46
  LayoutConfig,
47
+ Width,
48
+ validate_height,
49
+ validate_width,
43
50
  )
44
51
  from streamlit.elements.lib.pandas_styler_utils import marshall_styler
45
52
  from streamlit.elements.lib.policies import check_widget_policies
@@ -67,13 +74,20 @@ if TYPE_CHECKING:
67
74
 
68
75
 
69
76
  SelectionMode: TypeAlias = Literal[
70
- "single-row", "multi-row", "single-column", "multi-column"
77
+ "single-row",
78
+ "multi-row",
79
+ "single-column",
80
+ "multi-column",
81
+ "single-cell",
82
+ "multi-cell",
71
83
  ]
72
84
  _SELECTION_MODES: Final[set[SelectionMode]] = {
73
85
  "single-row",
74
86
  "multi-row",
75
87
  "single-column",
76
88
  "multi-column",
89
+ "single-cell",
90
+ "multi-cell",
77
91
  }
78
92
 
79
93
 
@@ -100,12 +114,18 @@ class DataframeSelectionState(TypedDict, total=False):
100
114
  or ``.iat[]``.
101
115
  columns : list[str]
102
116
  The selected columns, identified by their names.
117
+ cells : list[tuple[int, str]]
118
+ The selected cells, provided as a tuple of row integer position
119
+ and column name. For example, the first cell in a column named "col 1"
120
+ is represented as ``(0, "col 1")``. Cells within index columns are not
121
+ returned.
103
122
 
104
123
  Example
105
124
  -------
106
125
  The following example has multi-row and multi-column selections enabled.
107
- Try selecting some rows. To select multiple columns, hold ``Ctrl`` while
108
- selecting columns. Hold ``Shift`` to select a range of columns.
126
+ Try selecting some rows. To select multiple columns, hold ``CMD`` (macOS)
127
+ or ``Ctrl`` (Windows) while selecting columns. Hold ``Shift`` to select a
128
+ range of columns.
109
129
 
110
130
  >>> import pandas as pd
111
131
  >>> import streamlit as st
@@ -119,7 +139,7 @@ class DataframeSelectionState(TypedDict, total=False):
119
139
  ... df,
120
140
  ... key="data",
121
141
  ... on_select="rerun",
122
- ... selection_mode=["multi-row", "multi-column"],
142
+ ... selection_mode=["multi-row", "multi-column", "multi-cell"],
123
143
  ... )
124
144
  >>>
125
145
  >>> event.selection
@@ -132,6 +152,7 @@ class DataframeSelectionState(TypedDict, total=False):
132
152
 
133
153
  rows: list[int]
134
154
  columns: list[str]
155
+ cells: list[tuple[int, str]]
135
156
 
136
157
 
137
158
  class DataframeState(TypedDict, total=False):
@@ -167,6 +188,7 @@ class DataframeSelectionSerde:
167
188
  "selection": {
168
189
  "rows": [],
169
190
  "columns": [],
191
+ "cells": [],
170
192
  },
171
193
  }
172
194
  selection_state: DataframeState = (
@@ -176,10 +198,27 @@ class DataframeSelectionSerde:
176
198
  if "selection" not in selection_state:
177
199
  selection_state = empty_selection_state
178
200
 
201
+ if "rows" not in selection_state["selection"]:
202
+ selection_state["selection"]["rows"] = []
203
+
204
+ if "columns" not in selection_state["selection"]:
205
+ selection_state["selection"]["columns"] = []
206
+
207
+ if "cells" not in selection_state["selection"]:
208
+ selection_state["selection"]["cells"] = []
209
+ else:
210
+ # Explicitly convert all cells to a tuple (from list).
211
+ # This is necessary since there isn't a concept of tuples in JSON
212
+ # The format that the data is transferred to the backend.
213
+ selection_state["selection"]["cells"] = [
214
+ tuple(cell) # type: ignore
215
+ for cell in selection_state["selection"]["cells"]
216
+ ]
217
+
179
218
  return cast("DataframeState", AttributeDictionary(selection_state))
180
219
 
181
- def serialize(self, editing_state: DataframeState) -> str:
182
- return json.dumps(editing_state, default=str)
220
+ def serialize(self, state: DataframeState) -> str:
221
+ return json.dumps(state)
183
222
 
184
223
 
185
224
  def parse_selection_mode(
@@ -209,6 +248,11 @@ def parse_selection_mode(
209
248
  "Only one of `single-column` or `multi-column` can be selected as selection mode."
210
249
  )
211
250
 
251
+ if selection_mode_set.issuperset({"single-cell", "multi-cell"}):
252
+ raise StreamlitAPIException(
253
+ "Only one of `single-cell` or `multi-cell` can be selected as selection mode."
254
+ )
255
+
212
256
  parsed_selection_modes = []
213
257
  for mode in selection_mode_set:
214
258
  if mode == "single-row":
@@ -219,6 +263,10 @@ def parse_selection_mode(
219
263
  parsed_selection_modes.append(ArrowProto.SelectionMode.SINGLE_COLUMN)
220
264
  elif mode == "multi-column":
221
265
  parsed_selection_modes.append(ArrowProto.SelectionMode.MULTI_COLUMN)
266
+ elif mode == "single-cell":
267
+ parsed_selection_modes.append(ArrowProto.SelectionMode.SINGLE_CELL)
268
+ elif mode == "multi-cell":
269
+ parsed_selection_modes.append(ArrowProto.SelectionMode.MULTI_CELL)
222
270
  return set(parsed_selection_modes)
223
271
 
224
272
 
@@ -227,8 +275,8 @@ class ArrowMixin:
227
275
  def dataframe(
228
276
  self,
229
277
  data: Data = None,
230
- width: int | None = None,
231
- height: int | None = None,
278
+ width: Width = "stretch",
279
+ height: int | Literal["auto"] = "auto",
232
280
  *,
233
281
  use_container_width: bool | None = None,
234
282
  hide_index: bool | None = None,
@@ -244,8 +292,8 @@ class ArrowMixin:
244
292
  def dataframe(
245
293
  self,
246
294
  data: Data = None,
247
- width: int | None = None,
248
- height: int | None = None,
295
+ width: Width = "stretch",
296
+ height: int | Literal["auto"] = "auto",
249
297
  *,
250
298
  use_container_width: bool | None = None,
251
299
  hide_index: bool | None = None,
@@ -261,8 +309,8 @@ class ArrowMixin:
261
309
  def dataframe(
262
310
  self,
263
311
  data: Data = None,
264
- width: int | None = None,
265
- height: int | None = None,
312
+ width: Width = "stretch",
313
+ height: int | Literal["auto"] = "auto",
266
314
  *,
267
315
  use_container_width: bool | None = None,
268
316
  hide_index: bool | None = None,
@@ -318,18 +366,28 @@ class ArrowMixin:
318
366
 
319
367
  If ``data`` is ``None``, Streamlit renders an empty table.
320
368
 
321
- width : int or None
322
- Desired width of the dataframe expressed in pixels. If ``width`` is
323
- ``None`` (default), Streamlit sets the dataframe width to fit its
324
- contents up to the width of the parent container. If ``width`` is
325
- greater than the width of the parent container, Streamlit sets the
326
- dataframe width to match the width of the parent container.
369
+ width : "stretch", "content", or int
370
+ The width of the dataframe element. This can be one of the following:
371
+
372
+ - ``"stretch"`` (default): The width of the element matches the
373
+ width of the parent container.
374
+ - ``"content"``: The width of the element matches the width of its
375
+ content, but doesn't exceed the width of the parent container.
376
+ - An integer specifying the width in pixels: The element has a
377
+ fixed width. If the specified width is greater than the width of
378
+ the parent container, the width of the element matches the width
379
+ of the parent container.
380
+
381
+ height : int or "auto"
382
+ The height of the dataframe element. This can be one of the following:
383
+
384
+ - ``"auto"`` (default): Streamlit sets the height to show at most
385
+ ten rows.
386
+ - An integer specifying the height in pixels: The element has a
387
+ fixed height.
327
388
 
328
- height : int or None
329
- Desired height of the dataframe expressed in pixels. If ``height``
330
- is ``None`` (default), Streamlit sets the height to show at most
331
- ten rows. Vertical scrolling within the dataframe element is
332
- enabled when the height does not accommodate all rows.
389
+ Vertical scrolling within the dataframe element is enabled when the
390
+ height does not accommodate all rows.
333
391
 
334
392
  use_container_width : bool
335
393
  Whether to override ``width`` with the width of the parent
@@ -343,42 +401,41 @@ class ArrowMixin:
343
401
  (default), the visibility of index columns is automatically
344
402
  determined based on the data.
345
403
 
346
- column_order : Iterable of str or None
347
- The ordered list of columns to display. If ``column_order`` is
348
- ``None`` (default), Streamlit displays all columns in the order
349
- inherited from the underlying data structure. If ``column_order``
350
- is a list, the indicated columns will display in the order they
351
- appear within the list. Columns may be omitted or repeated within
352
- the list.
404
+ column_order : Iterable[str] or None
405
+ The ordered list of columns to display. If this is ``None``
406
+ (default), Streamlit displays all columns in the order inherited
407
+ from the underlying data structure. If this is a list, the
408
+ indicated columns will display in the order they appear within the
409
+ list. Columns may be omitted or repeated within the list.
353
410
 
354
411
  For example, ``column_order=("col2", "col1")`` will display
355
412
  ``"col2"`` first, followed by ``"col1"``, and will hide all other
356
413
  non-index columns.
357
414
 
415
+ ``column_order`` does not accept positional column indices and
416
+ can't move the index column(s).
417
+
358
418
  column_config : dict or None
359
- Configuration to customize how columns display. If ``column_config``
360
- is ``None`` (default), columns are styled based on the underlying
361
- data type of each column.
419
+ Configuration to customize how columns are displayed. If this is
420
+ ``None`` (default), columns are styled based on the underlying data
421
+ type of each column.
362
422
 
363
423
  Column configuration can modify column names, visibility, type,
364
- width, or format, among other things. ``column_config`` must be a
365
- dictionary where each key is a column name and the associated value
366
- is one of the following:
367
-
368
- - ``None``: Streamlit hides the column.
369
-
370
- - A string: Streamlit changes the display label of the column to
371
- the given string.
372
-
373
- - A column type within ``st.column_config``: Streamlit applies the
374
- defined configuration to the column. For example, use
375
- ``st.column_config.NumberColumn("Dollar values", format="$ %d")``
376
- to change the displayed name of the column to "Dollar values"
377
- and add a "$" prefix in each cell. For more info on the
378
- available column types and config options, see
379
- `Column configuration <https://docs.streamlit.io/develop/api-reference/data/st.column_config>`_.
380
-
381
- To configure the index column(s), use ``_index`` as the column name.
424
+ width, format, and more. If this is a dictionary, the keys are
425
+ column names (strings) and/or positional column indices (integers),
426
+ and the values are one of the following:
427
+
428
+ - ``None`` to hide the column.
429
+ - A string to set the display label of the column.
430
+ - One of the column types defined under ``st.column_config``. For
431
+ example, to show a column as dollar amounts, use
432
+ ``st.column_config.NumberColumn("Dollar values", format="$ %d")``.
433
+ See more info on the available column types and config options
434
+ `here <https://docs.streamlit.io/develop/api-reference/data/st.column_config>`_.
435
+
436
+ To configure the index column(s), use ``"_index"`` as the column
437
+ name, or use a positional column index where ``0`` refers to the
438
+ first index column.
382
439
 
383
440
  key : str
384
441
  An optional string to use for giving this element a stable
@@ -399,8 +456,8 @@ class ArrowMixin:
399
456
  input widget.
400
457
 
401
458
  - ``"rerun"``: Streamlit will rerun the app when the user selects
402
- rows or columns in the dataframe. In this case, ``st.dataframe``
403
- will return the selection data as a dictionary.
459
+ rows, columns, or cells in the dataframe. In this case,
460
+ ``st.dataframe`` will return the selection data as a dictionary.
404
461
 
405
462
  - A ``callable``: Streamlit will rerun the app and execute the
406
463
  ``callable`` as a callback function before the rest of the app.
@@ -408,7 +465,7 @@ class ArrowMixin:
408
465
  as a dictionary.
409
466
 
410
467
  selection_mode : "single-row", "multi-row", "single-column", \
411
- "multi-column", or Iterable of these
468
+ "multi-column", "single-cell", "multi-cell", or Iterable of these
412
469
  The types of selections Streamlit should allow when selections are
413
470
  enabled with ``on_select``. This can be one of the following:
414
471
 
@@ -416,8 +473,12 @@ class ArrowMixin:
416
473
  - "single-row": Only one row can be selected at a time.
417
474
  - "multi-column": Multiple columns can be selected at a time.
418
475
  - "single-column": Only one column can be selected at a time.
476
+ - "multi-cell": A rectangular range of cells can be selected.
477
+ - "single-cell": Only one cell can be selected at a time.
419
478
  - An ``Iterable`` of the above options: The table will allow
420
- selection based on the modes specified.
479
+ selection based on the modes specified. For example, to allow the
480
+ user to select multiple rows and multiple cells, use
481
+ ``["multi-row", "multi-cell"]``.
421
482
 
422
483
  When column selections are enabled, column sorting is disabled.
423
484
 
@@ -426,6 +487,11 @@ class ArrowMixin:
426
487
  is ``None`` (default), Streamlit will use a default row height,
427
488
  which fits one line of text.
428
489
 
490
+ .. deprecated::
491
+ ``use_container_width`` is deprecated and will be removed in a
492
+ future release. For ``use_container_width=True``, use
493
+ ``width="stretch"``.
494
+
429
495
  Returns
430
496
  -------
431
497
  element or dict
@@ -572,23 +638,36 @@ class ArrowMixin:
572
638
  enable_check_callback_rules=is_callback,
573
639
  )
574
640
 
641
+ if use_container_width is not None:
642
+ show_deprecation_warning(
643
+ make_deprecated_name_warning(
644
+ "use_container_width",
645
+ "width",
646
+ "2025-12-31",
647
+ "For `use_container_width=True`, use `width='stretch'`. "
648
+ "For `use_container_width=False`, use `width='content'`.",
649
+ include_st_prefix=False,
650
+ ),
651
+ show_in_browser=False,
652
+ )
653
+ if use_container_width:
654
+ width = "stretch"
655
+ elif not isinstance(width, int):
656
+ width = "content"
657
+
658
+ validate_width(width, allow_content=True)
659
+ validate_height(
660
+ height,
661
+ allow_content=False,
662
+ allow_stretch=False,
663
+ additional_allowed=["auto"],
664
+ )
665
+
575
666
  # Convert the user provided column config into the frontend compatible format:
576
667
  column_config_mapping = process_config_mapping(column_config)
577
668
 
578
669
  proto = ArrowProto()
579
670
 
580
- if use_container_width is None:
581
- # If use_container_width was not explicitly set by the user, we set
582
- # it to True if width was not set explicitly, and False otherwise.
583
- use_container_width = width is None
584
-
585
- proto.use_container_width = use_container_width
586
-
587
- if width:
588
- proto.width = width
589
- if height:
590
- proto.height = height
591
-
592
671
  if row_height:
593
672
  proto.row_height = row_height
594
673
 
@@ -629,6 +708,13 @@ class ArrowMixin:
629
708
  )
630
709
  marshall_column_config(proto, column_config_mapping)
631
710
 
711
+ # Create layout configuration
712
+ # For height, only include it in LayoutConfig if it's not "auto"
713
+ # "auto" is the default behavior and doesn't need to be sent
714
+ layout_config = LayoutConfig(
715
+ width=width, height=height if height != "auto" else None
716
+ )
717
+
632
718
  if is_selection_activated:
633
719
  # If selection events are activated, we need to register the dataframe
634
720
  # element as a widget.
@@ -639,7 +725,6 @@ class ArrowMixin:
639
725
  proto.id = compute_and_register_element_id(
640
726
  "dataframe",
641
727
  user_key=key,
642
- form_id=proto.form_id,
643
728
  dg=self.dg,
644
729
  data=proto.data,
645
730
  width=width,
@@ -661,9 +746,9 @@ class ArrowMixin:
661
746
  ctx=ctx,
662
747
  value_type="string_value",
663
748
  )
664
- self.dg._enqueue("arrow_data_frame", proto)
749
+ self.dg._enqueue("arrow_data_frame", proto, layout_config=layout_config)
665
750
  return widget_state.value
666
- return self.dg._enqueue("arrow_data_frame", proto)
751
+ return self.dg._enqueue("arrow_data_frame", proto, layout_config=layout_config)
667
752
 
668
753
  @gather_metrics("table")
669
754
  def table(self, data: Data = None) -> DeltaGenerator: