streamlit 1.51.0__py3-none-any.whl → 1.52.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 (314) hide show
  1. streamlit/__init__.py +1 -0
  2. streamlit/commands/execution_control.py +89 -14
  3. streamlit/components/v1/component_arrow.py +7 -7
  4. streamlit/components/v2/__init__.py +59 -3
  5. streamlit/components/v2/bidi_component/main.py +161 -13
  6. streamlit/components/v2/bidi_component/serialization.py +13 -6
  7. streamlit/components/v2/component_manager.py +11 -3
  8. streamlit/components/v2/component_registry.py +18 -1
  9. streamlit/components/v2/types.py +2 -2
  10. streamlit/connections/snowflake_connection.py +1 -1
  11. streamlit/connections/snowpark_connection.py +1 -1
  12. streamlit/dataframe_util.py +18 -18
  13. streamlit/delta_generator.py +7 -0
  14. streamlit/delta_generator_singletons.py +8 -14
  15. streamlit/elements/alert.py +16 -0
  16. streamlit/elements/arrow.py +36 -6
  17. streamlit/elements/bokeh_chart.py +10 -78
  18. streamlit/elements/code.py +2 -2
  19. streamlit/elements/deck_gl_json_chart.py +1 -1
  20. streamlit/elements/exception.py +1 -1
  21. streamlit/elements/form.py +27 -0
  22. streamlit/elements/heading.py +60 -5
  23. streamlit/elements/html.py +13 -2
  24. streamlit/elements/image.py +1 -1
  25. streamlit/elements/layouts.py +28 -22
  26. streamlit/elements/lib/built_in_chart_utils.py +49 -16
  27. streamlit/elements/lib/color_util.py +1 -1
  28. streamlit/elements/lib/column_config_utils.py +6 -5
  29. streamlit/elements/lib/layout_utils.py +50 -0
  30. streamlit/elements/lib/pandas_styler_utils.py +17 -9
  31. streamlit/elements/lib/shortcut_utils.py +152 -0
  32. streamlit/elements/markdown.py +50 -3
  33. streamlit/elements/metric.py +31 -1
  34. streamlit/elements/plotly_chart.py +75 -6
  35. streamlit/elements/spinner.py +1 -1
  36. streamlit/elements/text.py +20 -3
  37. streamlit/elements/toast.py +2 -0
  38. streamlit/elements/vega_charts.py +17 -1
  39. streamlit/elements/widgets/audio_input.py +8 -7
  40. streamlit/elements/widgets/button.py +279 -40
  41. streamlit/elements/widgets/button_group.py +27 -2
  42. streamlit/elements/widgets/camera_input.py +1 -1
  43. streamlit/elements/widgets/chat.py +300 -42
  44. streamlit/elements/widgets/color_picker.py +7 -0
  45. streamlit/elements/widgets/data_editor.py +68 -28
  46. streamlit/elements/widgets/file_uploader.py +4 -1
  47. streamlit/elements/widgets/number_input.py +2 -0
  48. streamlit/elements/widgets/text_widgets.py +2 -0
  49. streamlit/elements/widgets/time_widgets.py +581 -9
  50. streamlit/errors.py +22 -0
  51. streamlit/git_util.py +1 -1
  52. streamlit/navigation/page.py +7 -0
  53. streamlit/net_util.py +2 -2
  54. streamlit/proto/Alert_pb2.pyi +3 -3
  55. streamlit/proto/AppPage_pb2.pyi +7 -1
  56. streamlit/proto/ArrowData_pb2.pyi +7 -1
  57. streamlit/proto/ArrowNamedDataSet_pb2.pyi +7 -1
  58. streamlit/proto/ArrowVegaLiteChart_pb2.pyi +7 -1
  59. streamlit/proto/Arrow_pb2.py +10 -10
  60. streamlit/proto/Arrow_pb2.pyi +19 -12
  61. streamlit/proto/AudioInput_pb2.pyi +7 -1
  62. streamlit/proto/Audio_pb2.pyi +7 -1
  63. streamlit/proto/AuthRedirect_pb2.pyi +7 -1
  64. streamlit/proto/AutoRerun_pb2.pyi +7 -1
  65. streamlit/proto/BackMsg_pb2.py +4 -2
  66. streamlit/proto/BackMsg_pb2.pyi +34 -4
  67. streamlit/proto/Balloons_pb2.pyi +7 -1
  68. streamlit/proto/BidiComponent_pb2.pyi +10 -4
  69. streamlit/proto/Block_pb2.pyi +35 -35
  70. streamlit/proto/BokehChart_pb2.pyi +7 -1
  71. streamlit/proto/ButtonGroup_pb2.pyi +9 -9
  72. streamlit/proto/Button_pb2.py +2 -2
  73. streamlit/proto/Button_pb2.pyi +11 -2
  74. streamlit/proto/CameraInput_pb2.pyi +7 -1
  75. streamlit/proto/ChatInput_pb2.py +6 -6
  76. streamlit/proto/ChatInput_pb2.pyi +18 -6
  77. streamlit/proto/Checkbox_pb2.pyi +3 -3
  78. streamlit/proto/ClientState_pb2.pyi +10 -4
  79. streamlit/proto/Code_pb2.pyi +7 -1
  80. streamlit/proto/ColorPicker_pb2.pyi +7 -1
  81. streamlit/proto/Common_pb2.py +3 -3
  82. streamlit/proto/Common_pb2.pyi +35 -23
  83. streamlit/proto/Components_pb2.pyi +19 -13
  84. streamlit/proto/DataFrame_pb2.pyi +55 -49
  85. streamlit/proto/DateInput_pb2.pyi +7 -1
  86. streamlit/proto/DateTimeInput_pb2.py +28 -0
  87. streamlit/proto/DateTimeInput_pb2.pyi +92 -0
  88. streamlit/proto/DeckGlJsonChart_pb2.pyi +3 -3
  89. streamlit/proto/Delta_pb2.pyi +7 -1
  90. streamlit/proto/DocString_pb2.pyi +10 -4
  91. streamlit/proto/DownloadButton_pb2.py +2 -2
  92. streamlit/proto/DownloadButton_pb2.pyi +16 -2
  93. streamlit/proto/Element_pb2.py +5 -3
  94. streamlit/proto/Element_pb2.pyi +23 -5
  95. streamlit/proto/Empty_pb2.pyi +7 -1
  96. streamlit/proto/Exception_pb2.pyi +7 -1
  97. streamlit/proto/Favicon_pb2.pyi +7 -1
  98. streamlit/proto/FileUploader_pb2.pyi +7 -1
  99. streamlit/proto/ForwardMsg_pb2.py +12 -10
  100. streamlit/proto/ForwardMsg_pb2.pyi +42 -15
  101. streamlit/proto/GapSize_pb2.pyi +4 -4
  102. streamlit/proto/GitInfo_pb2.pyi +3 -3
  103. streamlit/proto/GraphVizChart_pb2.pyi +7 -1
  104. streamlit/proto/Heading_pb2.pyi +7 -1
  105. streamlit/proto/HeightConfig_pb2.pyi +7 -1
  106. streamlit/proto/Html_pb2.py +2 -2
  107. streamlit/proto/Html_pb2.pyi +11 -2
  108. streamlit/proto/IFrame_pb2.pyi +7 -1
  109. streamlit/proto/Image_pb2.pyi +10 -4
  110. streamlit/proto/Json_pb2.pyi +7 -1
  111. streamlit/proto/LabelVisibilityMessage_pb2.pyi +3 -3
  112. streamlit/proto/LinkButton_pb2.py +2 -2
  113. streamlit/proto/LinkButton_pb2.pyi +15 -2
  114. streamlit/proto/Logo_pb2.pyi +7 -1
  115. streamlit/proto/Markdown_pb2.pyi +3 -3
  116. streamlit/proto/Metric_pb2.pyi +7 -7
  117. streamlit/proto/MetricsEvent_pb2.pyi +10 -4
  118. streamlit/proto/MultiSelect_pb2.pyi +7 -1
  119. streamlit/proto/NamedDataSet_pb2.pyi +7 -1
  120. streamlit/proto/Navigation_pb2.pyi +3 -3
  121. streamlit/proto/NewSession_pb2.pyi +40 -40
  122. streamlit/proto/NumberInput_pb2.pyi +3 -3
  123. streamlit/proto/PageConfig_pb2.pyi +7 -7
  124. streamlit/proto/PageInfo_pb2.pyi +7 -1
  125. streamlit/proto/PageLink_pb2.py +2 -2
  126. streamlit/proto/PageLink_pb2.pyi +11 -2
  127. streamlit/proto/PageNotFound_pb2.pyi +7 -1
  128. streamlit/proto/PageProfile_pb2.pyi +13 -7
  129. streamlit/proto/PagesChanged_pb2.pyi +7 -1
  130. streamlit/proto/ParentMessage_pb2.pyi +7 -1
  131. streamlit/proto/PlotlyChart_pb2.pyi +6 -6
  132. streamlit/proto/Progress_pb2.pyi +7 -1
  133. streamlit/proto/Radio_pb2.pyi +7 -1
  134. streamlit/proto/RootContainer_pb2.pyi +1 -1
  135. streamlit/proto/Selectbox_pb2.pyi +7 -1
  136. streamlit/proto/SessionEvent_pb2.pyi +7 -1
  137. streamlit/proto/SessionStatus_pb2.pyi +7 -1
  138. streamlit/proto/Skeleton_pb2.pyi +3 -3
  139. streamlit/proto/Slider_pb2.pyi +5 -5
  140. streamlit/proto/Snow_pb2.pyi +7 -1
  141. streamlit/proto/Space_pb2.pyi +7 -1
  142. streamlit/proto/Spinner_pb2.pyi +7 -1
  143. streamlit/proto/TextAlignmentConfig_pb2.py +29 -0
  144. streamlit/proto/TextAlignmentConfig_pb2.pyi +68 -0
  145. streamlit/proto/TextArea_pb2.pyi +7 -1
  146. streamlit/proto/TextInput_pb2.pyi +3 -3
  147. streamlit/proto/Text_pb2.pyi +7 -1
  148. streamlit/proto/TimeInput_pb2.pyi +7 -1
  149. streamlit/proto/Toast_pb2.pyi +7 -1
  150. streamlit/proto/VegaLiteChart_pb2.pyi +7 -1
  151. streamlit/proto/Video_pb2.pyi +6 -6
  152. streamlit/proto/WidgetStates_pb2.pyi +10 -4
  153. streamlit/proto/WidthConfig_pb2.pyi +7 -1
  154. streamlit/proto/openmetrics_data_model_pb2.pyi +52 -52
  155. streamlit/runtime/app_session.py +38 -1
  156. streamlit/runtime/caching/cache_data_api.py +1 -1
  157. streamlit/runtime/caching/cache_resource_api.py +2 -2
  158. streamlit/runtime/caching/cache_utils.py +1 -1
  159. streamlit/runtime/caching/hashing.py +1 -1
  160. streamlit/runtime/download_data_util.py +53 -0
  161. streamlit/runtime/forward_msg_queue.py +1 -0
  162. streamlit/runtime/media_file_manager.py +178 -2
  163. streamlit/runtime/metrics_util.py +87 -3
  164. streamlit/runtime/scriptrunner/script_runner.py +3 -1
  165. streamlit/runtime/state/query_params.py +80 -29
  166. streamlit/runtime/state/session_state.py +2 -2
  167. streamlit/static/index.html +1 -1
  168. streamlit/static/manifest.json +530 -229
  169. streamlit/static/static/js/{ErrorOutline.esm.YoJdlW1p.js → ErrorOutline.esm.ZJDbmVTx.js} +1 -1
  170. streamlit/static/static/js/{FileDownload.esm.Ddx8VEYy.js → FileDownload.esm.Dx0vI3vH.js} +1 -1
  171. streamlit/static/static/js/{FileHelper.90EtOmj9.js → FileHelper.B7Ero7qQ.js} +3 -3
  172. streamlit/static/static/js/{FormClearHelper.BB1Km6eP.js → FormClearHelper.CG2XN1_g.js} +1 -1
  173. streamlit/static/static/js/IFrameUtil.DefezniK.js +1 -0
  174. streamlit/static/static/js/InputInstructions.Cj5-1zf6.js +1 -0
  175. streamlit/static/static/js/Particles.BfWfv0Aw.js +1 -0
  176. streamlit/static/static/js/{ProgressBar.DLY8H6nE.js → ProgressBar.CGQ8OgfO.js} +2 -2
  177. streamlit/static/static/js/StreamlitSyntaxHighlighter.DTKLpwhl.js +20 -0
  178. streamlit/static/static/js/{Toolbar.D8nHCkuz.js → Toolbar.B2qFUmd9.js} +1 -1
  179. streamlit/static/static/js/_arrayIncludes.B19Iyn2B.js +1 -0
  180. streamlit/static/static/js/_baseIndexOf.BTknn6Gb.js +1 -0
  181. streamlit/static/static/js/{base-input.CJGiNqed.js → base-input.o9tL8MDP.js} +4 -4
  182. streamlit/static/static/js/{checkbox.Cpdd482O.js → checkbox.0BeV1IBL.js} +1 -1
  183. streamlit/static/static/js/{createSuper.CuQIogbW.js → createSuper.RBO59fEm.js} +1 -1
  184. streamlit/static/static/js/data-grid-overlay-editor.CiTkUy0t.js +1 -0
  185. streamlit/static/static/js/{downloader.CN0K7xlu.js → downloader.DwNZg3Mw.js} +1 -1
  186. streamlit/static/static/js/embed.XT9xNd3F.js +195 -0
  187. streamlit/static/static/js/{es6.BJcsVXQ0.js → es6.x9KsYQg-.js} +2 -2
  188. streamlit/static/static/js/{iframeResizer.contentWindow.XzUvQqcZ.js → iframeResizer.contentWindow.ZVXpMPi0.js} +1 -1
  189. streamlit/static/static/js/index.5VPOamri.js +1 -0
  190. streamlit/static/static/js/index.8HslT92O.js +14 -0
  191. streamlit/static/static/js/index.AnXMIBz3.js +7 -0
  192. streamlit/static/static/js/index.B0yp3bM1.js +6 -0
  193. streamlit/static/static/js/index.B1fRb5wF.js +1 -0
  194. streamlit/static/static/js/index.B527JZdO.js +3 -0
  195. streamlit/static/static/js/index.BHgV-yW4.js +1 -0
  196. streamlit/static/static/js/index.BQr-XwGV.js +1 -0
  197. streamlit/static/static/js/index.BTtmaLDB.js +1 -0
  198. streamlit/static/static/js/index.BWB_91TA.js +1 -0
  199. streamlit/static/static/js/index.BfEKaEmw.js +1 -0
  200. streamlit/static/static/js/index.BfXjTO8b.js +1 -0
  201. streamlit/static/static/js/index.Bjy4NRu9.js +3 -0
  202. streamlit/static/static/js/index.Bu5JWpT_.js +1 -0
  203. streamlit/static/static/js/index.BuCx76ZV.js +1 -0
  204. streamlit/static/static/js/index.BxjzhVUb.js +2 -0
  205. streamlit/static/static/js/index.By55VdPY.js +1 -0
  206. streamlit/static/static/js/index.CF5MxTbK.js +1 -0
  207. streamlit/static/static/js/index.CLmq_z9K.js +1 -0
  208. streamlit/static/static/js/index.CNH4rdSz.js +1 -0
  209. streamlit/static/static/js/{index.D3GPA5k4.js → index.CTgm_-jO.js} +9 -40
  210. streamlit/static/static/js/index.C_rK-Swb.js +188 -0
  211. streamlit/static/static/js/index.CjozwSzS.js +1 -0
  212. streamlit/static/static/js/{index.DOFlg3dS.js → index.CkGVt6-G.js} +1 -1
  213. streamlit/static/static/js/index.CuvXOyER.js +2 -0
  214. streamlit/static/static/js/{index.B_dWA3vd.js → index.CyUHWoCC.js} +2 -2
  215. streamlit/static/static/js/index.CyroQtI4.js +2 -0
  216. streamlit/static/static/js/index.D6HmkoDm.js +263 -0
  217. streamlit/static/static/js/index.DAqCNvsO.js +1 -0
  218. streamlit/static/static/js/index.DB_w_CZQ.js +1 -0
  219. streamlit/static/static/js/index.DBalctjj.js +2 -0
  220. streamlit/static/static/js/index.DK0RFJUG.js +11 -0
  221. streamlit/static/static/js/index.DMxc2XFp.js +151 -0
  222. streamlit/static/static/js/index.DO5utP74.js +2 -0
  223. streamlit/static/static/js/index.DS7lf09n.js +1 -0
  224. streamlit/static/static/js/index.DWexTVLY.js +1 -0
  225. streamlit/static/static/js/index.DXxnU5ej.js +1 -0
  226. streamlit/static/static/js/index.DcU3uDvB.js +2 -0
  227. streamlit/static/static/js/index.DlltaH7J.js +1 -0
  228. streamlit/static/static/js/index.DpNTZz82.js +27 -0
  229. streamlit/static/static/js/index.Dr9HIhQw.js +1 -0
  230. streamlit/static/static/js/index.DsgAU5lc.js +1 -0
  231. streamlit/static/static/js/{index.DPUXkcQL.js → index.KfXqjDYy.js} +1 -1
  232. streamlit/static/static/js/index.PaidgjCs.js +1 -0
  233. streamlit/static/static/js/index.RJZuWCGA.js +1 -0
  234. streamlit/static/static/js/{index.CxIUUfab.js → index.hbeqcRTn.js} +53 -122
  235. streamlit/static/static/js/index.q5hIQwAY.js +1 -0
  236. streamlit/static/static/js/index.rORSX6IW.js +1 -0
  237. streamlit/static/static/js/index.uSX757_v.js +1 -0
  238. streamlit/static/static/js/index.x_QRaLMd.js +1 -0
  239. streamlit/static/static/js/{input.D4MN_FzN.js → input.D5oh9-aB.js} +2 -2
  240. streamlit/static/static/js/main.q9oGOg0H.js +13 -0
  241. streamlit/static/static/js/{memory.DrZjtdGT.js → memory.5kCSFUJS.js} +1 -1
  242. streamlit/static/static/js/moment.C3j7ZXd7.js +4 -0
  243. streamlit/static/static/js/number-overlay-editor.Cn_LsK8N.js +9 -0
  244. streamlit/static/static/js/pandasStylerUtils.BqhXt51_.js +1 -0
  245. streamlit/static/static/js/{possibleConstructorReturn.exeeJQEP.js → possibleConstructorReturn.DD9NK1Z8.js} +1 -1
  246. streamlit/static/static/js/{sandbox.ClO3IuUr.js → sandbox.DACSyz29.js} +1 -1
  247. streamlit/static/static/js/styled-components.C3R090At.js +1 -0
  248. streamlit/static/static/js/threshold.Q1mXg5rX.js +1 -0
  249. streamlit/static/static/js/throttle.B0GR3Iyz.js +1 -0
  250. streamlit/static/static/js/{timepicker.DAhu-vcF.js → timepicker.BdhzPxrv.js} +1 -1
  251. streamlit/static/static/js/timer.C2hYhUse.js +1 -0
  252. streamlit/static/static/js/{toConsumableArray.DNbljYEC.js → toConsumableArray.Db2pdqM2.js} +1 -1
  253. streamlit/static/static/js/uniqueId.CtqIr-Yh.js +1 -0
  254. streamlit/static/static/js/urls.BwSlolu9.js +1 -0
  255. streamlit/static/static/js/{useBasicWidgetState.D6sOH6oI.js → useBasicWidgetState.Bfp6TnSw.js} +1 -1
  256. streamlit/static/static/js/useIntlLocale.hRV75Xgj.js +12 -0
  257. streamlit/static/static/js/{useTextInputAutoExpand.4u3_GcuN.js → useTextInputAutoExpand.QepX7n8Y.js} +1 -1
  258. streamlit/static/static/js/useUpdateUiValue.DHx8TzX6.js +1 -0
  259. streamlit/static/static/js/useWaveformController.WxVzpzEX.js +1 -0
  260. streamlit/static/static/js/value.B4vHRSi7.js +1 -0
  261. streamlit/static/static/js/withCalculatedWidth.DcKeRSWJ.js +1 -0
  262. streamlit/static/static/js/withFullScreenWrapper.CrHddARq.js +1 -0
  263. streamlit/string_util.py +8 -1
  264. streamlit/testing/v1/app_test.py +15 -0
  265. streamlit/testing/v1/element_tree.py +62 -0
  266. streamlit/web/bootstrap.py +24 -0
  267. streamlit/web/server/oauth_authlib_routes.py +5 -2
  268. streamlit/web/server/upload_file_request_handler.py +16 -0
  269. {streamlit-1.51.0.dist-info → streamlit-1.52.0.dist-info}/METADATA +9 -5
  270. {streamlit-1.51.0.dist-info → streamlit-1.52.0.dist-info}/RECORD +274 -239
  271. streamlit/static/static/js/InputInstructions.jhH15PqV.js +0 -1
  272. streamlit/static/static/js/Particles.DUsputn1.js +0 -1
  273. streamlit/static/static/js/data-grid-overlay-editor.2Ufgxc6y.js +0 -1
  274. streamlit/static/static/js/index.B1ZQh4P1.js +0 -1
  275. streamlit/static/static/js/index.BKstZk0M.js +0 -27
  276. streamlit/static/static/js/index.BMcFsUee.js +0 -1
  277. streamlit/static/static/js/index.BR-IdcTb.js +0 -2
  278. streamlit/static/static/js/index.BgnZEMVh.js +0 -1
  279. streamlit/static/static/js/index.BohqXifI.js +0 -1
  280. streamlit/static/static/js/index.Br5nxKNj.js +0 -2
  281. streamlit/static/static/js/index.BrIKVbNc.js +0 -3
  282. streamlit/static/static/js/index.BtWUPzle.js +0 -1
  283. streamlit/static/static/js/index.C0RLraek.js +0 -1
  284. streamlit/static/static/js/index.CAIjskgG.js +0 -1
  285. streamlit/static/static/js/index.CAj-7vWz.js +0 -949
  286. streamlit/static/static/js/index.CMtEit2O.js +0 -1
  287. streamlit/static/static/js/index.CkRlykEE.js +0 -12
  288. streamlit/static/static/js/index.CmN3FXfI.js +0 -1617
  289. streamlit/static/static/js/index.CwbFI1_-.js +0 -1
  290. streamlit/static/static/js/index.D2KPNy7e.js +0 -1
  291. streamlit/static/static/js/index.DGAh7DMq.js +0 -1
  292. streamlit/static/static/js/index.DKb_NvmG.js +0 -197
  293. streamlit/static/static/js/index.DMqgUYKq.js +0 -1
  294. streamlit/static/static/js/index.DX1xY89g.js +0 -1
  295. streamlit/static/static/js/index.DYATBCsq.js +0 -2
  296. streamlit/static/static/js/index.DaSmGJ76.js +0 -3
  297. streamlit/static/static/js/index.Dd7bMeLP.js +0 -1
  298. streamlit/static/static/js/index.DjmmgI5U.js +0 -1
  299. streamlit/static/static/js/index.Dq56CyM2.js +0 -1
  300. streamlit/static/static/js/index.DuiXaS5_.js +0 -7
  301. streamlit/static/static/js/index.DvFidMLe.js +0 -2
  302. streamlit/static/static/js/index.DwkhC5Pc.js +0 -1
  303. streamlit/static/static/js/index.Q-3sFn1v.js +0 -1
  304. streamlit/static/static/js/index.QJ5QO9sJ.js +0 -1
  305. streamlit/static/static/js/index.VwTaeety.js +0 -1
  306. streamlit/static/static/js/index.YOqQbeX8.js +0 -1
  307. streamlit/static/static/js/number-overlay-editor.DRwAw1In.js +0 -9
  308. streamlit/static/static/js/uniqueId.oG4Gvj1v.js +0 -1
  309. streamlit/static/static/js/useUpdateUiValue.F2R3eTeR.js +0 -1
  310. streamlit/static/static/js/withFullScreenWrapper.zothJIsI.js +0 -1
  311. {streamlit-1.51.0.data → streamlit-1.52.0.data}/scripts/streamlit.cmd +0 -0
  312. {streamlit-1.51.0.dist-info → streamlit-1.52.0.dist-info}/WHEEL +0 -0
  313. {streamlit-1.51.0.dist-info → streamlit-1.52.0.dist-info}/entry_points.txt +0 -0
  314. {streamlit-1.51.0.dist-info → streamlit-1.52.0.dist-info}/top_level.txt +0 -0
@@ -47,7 +47,7 @@ def marshall_styler(proto: ArrowProto, styler: Styler, default_uuid: str) -> Non
47
47
  """
48
48
  import pandas as pd
49
49
 
50
- styler_data_df: pd.DataFrame = styler.data
50
+ styler_data_df: pd.DataFrame = styler.data # type: ignore[attr-defined]
51
51
  if styler_data_df.size > int(pd.options.styler.render.max_elements):
52
52
  raise StreamlitAPIException(
53
53
  f"The dataframe has `{styler_data_df.size}` cells, but the maximum number "
@@ -62,9 +62,9 @@ def marshall_styler(proto: ArrowProto, styler: Styler, default_uuid: str) -> Non
62
62
 
63
63
  # We're using protected members of pandas.Styler to get styles,
64
64
  # which is not ideal and could break if the interface changes.
65
- styler._compute()
65
+ styler._compute() # type: ignore
66
66
 
67
- pandas_styles = styler._translate(False, False)
67
+ pandas_styles = styler._translate(False, False) # type: ignore
68
68
 
69
69
  _marshall_caption(proto, styler)
70
70
  _marshall_styles(proto, styler, pandas_styles)
@@ -86,10 +86,10 @@ def _marshall_uuid(proto: ArrowProto, styler: Styler, default_uuid: str) -> None
86
86
  If pandas.Styler uuid is not provided, this value will be used.
87
87
 
88
88
  """
89
- if styler.uuid is None:
89
+ if styler.uuid is None: # type: ignore[attr-defined]
90
90
  styler.set_uuid(default_uuid)
91
91
 
92
- proto.styler.uuid = str(styler.uuid)
92
+ proto.styler.uuid = str(styler.uuid) # type: ignore[attr-defined]
93
93
 
94
94
 
95
95
  def _marshall_caption(proto: ArrowProto, styler: Styler) -> None:
@@ -104,8 +104,8 @@ def _marshall_caption(proto: ArrowProto, styler: Styler) -> None:
104
104
  Helps style a DataFrame or Series according to the data with HTML and CSS.
105
105
 
106
106
  """
107
- if styler.caption is not None:
108
- proto.styler.caption = styler.caption
107
+ if styler.caption is not None: # type: ignore[attr-defined]
108
+ proto.styler.caption = styler.caption # type: ignore[attr-defined]
109
109
 
110
110
 
111
111
  def _marshall_styles(
@@ -134,7 +134,10 @@ def _marshall_styles(
134
134
  # styles in "table_styles" have a space
135
135
  # between the uuid and selector.
136
136
  rule = _pandas_style_to_css(
137
- "table_styles", style, styler.uuid, separator=" "
137
+ "table_styles",
138
+ style,
139
+ styler.uuid, # type: ignore[attr-defined]
140
+ separator=" ",
138
141
  )
139
142
  css_rules.append(rule)
140
143
 
@@ -142,7 +145,12 @@ def _marshall_styles(
142
145
  cellstyle = styles["cellstyle"]
143
146
  cellstyle = _trim_pandas_styles(cellstyle)
144
147
  for style in cellstyle:
145
- rule = _pandas_style_to_css("cell_style", style, styler.uuid, separator="_")
148
+ rule = _pandas_style_to_css(
149
+ "cell_style",
150
+ style,
151
+ styler.uuid, # type: ignore[attr-defined]
152
+ separator="_",
153
+ )
146
154
  css_rules.append(rule)
147
155
 
148
156
  if len(css_rules) > 0:
@@ -0,0 +1,152 @@
1
+ # Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import (
19
+ Final,
20
+ )
21
+
22
+ from streamlit.errors import (
23
+ StreamlitAPIException,
24
+ )
25
+
26
+ _MODIFIER_ALIASES: Final[dict[str, str]] = {
27
+ "ctrl": "ctrl",
28
+ "control": "ctrl",
29
+ "cmd": "cmd",
30
+ "command": "cmd",
31
+ "meta": "cmd",
32
+ "alt": "alt",
33
+ "option": "alt",
34
+ "shift": "shift",
35
+ "mod": "ctrl",
36
+ }
37
+
38
+ _MODIFIER_ORDER: Final[tuple[str, ...]] = ("ctrl", "cmd", "alt", "shift")
39
+
40
+ _KEY_ALIASES: Final[dict[str, str]] = {
41
+ "enter": "enter",
42
+ "return": "enter",
43
+ "space": "space",
44
+ "spacebar": "space",
45
+ "tab": "tab",
46
+ "escape": "escape",
47
+ "esc": "escape",
48
+ "backspace": "backspace",
49
+ "delete": "delete",
50
+ "del": "delete",
51
+ "home": "home",
52
+ "end": "end",
53
+ "pageup": "pageup",
54
+ "pagedown": "pagedown",
55
+ "left": "left",
56
+ "arrowleft": "left",
57
+ "right": "right",
58
+ "arrowright": "right",
59
+ "up": "up",
60
+ "arrowup": "up",
61
+ "down": "down",
62
+ "arrowdown": "down",
63
+ }
64
+
65
+ _RESERVED_KEYS: Final[set[str]] = {"c", "r"}
66
+
67
+
68
+ def _normalize_key_token(lower_token: str) -> str:
69
+ """Normalize a key token to a format that can be used on the client side."""
70
+
71
+ if lower_token in _KEY_ALIASES:
72
+ return _KEY_ALIASES[lower_token]
73
+
74
+ if len(lower_token) == 1 and lower_token.isalnum():
75
+ return lower_token
76
+
77
+ if lower_token.startswith("f") and lower_token[1:].isdigit():
78
+ return lower_token
79
+
80
+ raise StreamlitAPIException(
81
+ "shortcut must include a single character or one of the supported keys "
82
+ "(e.g. Enter, Space, Tab, Escape)."
83
+ )
84
+
85
+
86
+ def normalize_shortcut(shortcut: str) -> str:
87
+ """Normalize a shortcut string to a format that can be used on the client side.
88
+
89
+ Parameters
90
+ ----------
91
+ shortcut : str
92
+ The shortcut string to normalize.
93
+
94
+ Returns
95
+ -------
96
+ str
97
+ The normalized shortcut string.
98
+
99
+ Raises
100
+ ------
101
+ StreamlitAPIException
102
+ If the shortcut is not a string value.
103
+ If the shortcut does not contain at least one key or modifier.
104
+ If the shortcut contains a single non-modifier key.
105
+ If the shortcut uses the keys 'C' or 'R', with or without modifiers.
106
+ If the shortcut does not include a non-modifier key.
107
+ """
108
+ if not isinstance(shortcut, str):
109
+ raise StreamlitAPIException("shortcut must be a string value.")
110
+
111
+ tokens = [token.strip() for token in shortcut.split("+") if token.strip()]
112
+ if not tokens:
113
+ raise StreamlitAPIException(
114
+ "The `shortcut` must contain at least one key or modifier."
115
+ )
116
+
117
+ modifiers: list[str] = []
118
+ key: str | None = None
119
+
120
+ for raw_token in tokens:
121
+ lower_token = raw_token.lower()
122
+ if lower_token in _MODIFIER_ALIASES:
123
+ normalized_modifier = _MODIFIER_ALIASES[lower_token]
124
+ if normalized_modifier not in modifiers:
125
+ modifiers.append(normalized_modifier)
126
+ continue
127
+
128
+ if key is not None:
129
+ raise StreamlitAPIException(
130
+ "The `shortcut` may only specify a single non-modifier key."
131
+ )
132
+
133
+ normalized_key = _normalize_key_token(lower_token)
134
+ if normalized_key in _RESERVED_KEYS:
135
+ raise StreamlitAPIException(
136
+ "The `shortcut` cannot use the keys 'C' or 'R', with or without modifiers."
137
+ )
138
+
139
+ key = normalized_key
140
+
141
+ if key is None:
142
+ raise StreamlitAPIException(
143
+ "The `shortcut` must include a non-modifier key such as 'K' or 'Ctrl+K'."
144
+ )
145
+
146
+ normalized_tokens: list[str] = [
147
+ modifier for modifier in _MODIFIER_ORDER if modifier in modifiers
148
+ ]
149
+ if key is not None:
150
+ normalized_tokens.append(key)
151
+
152
+ return "+".join(normalized_tokens)
@@ -18,6 +18,7 @@ from typing import TYPE_CHECKING, Final, Literal, cast
18
18
 
19
19
  from streamlit.elements.lib.layout_utils import (
20
20
  LayoutConfig,
21
+ TextAlignment,
21
22
  Width,
22
23
  WidthWithoutContent,
23
24
  validate_width,
@@ -44,6 +45,7 @@ class MarkdownMixin:
44
45
  *, # keyword-only arguments:
45
46
  help: str | None = None,
46
47
  width: Width = "stretch",
48
+ text_alignment: TextAlignment = "left",
47
49
  ) -> DeltaGenerator:
48
50
  r"""Display string formatted as Markdown.
49
51
 
@@ -129,6 +131,22 @@ class MarkdownMixin:
129
131
  the parent container, the width of the element matches the width
130
132
  of the parent container.
131
133
 
134
+ text_alignment : "left", "center", "right", or "justify"
135
+ The horizontal alignment of the text within the element. This can
136
+ be one of the following:
137
+
138
+ - ``"left"`` (default): Text is aligned to the left edge.
139
+ - ``"center"``: Text is centered.
140
+ - ``"right"``: Text is aligned to the right edge.
141
+ - ``"justify"``: Text is justified (stretched to fill the available
142
+ width with the last line left-aligned).
143
+
144
+ .. note::
145
+ For text alignment to have a visible effect, the element's
146
+ width must be wider than its content. If you use
147
+ ``width="content"`` with short text, the alignment may not be
148
+ noticeable.
149
+
132
150
  Examples
133
151
  --------
134
152
  >>> import streamlit as st
@@ -161,7 +179,7 @@ class MarkdownMixin:
161
179
  markdown_proto.help = help
162
180
 
163
181
  validate_width(width, allow_content=True)
164
- layout_config = LayoutConfig(width=width)
182
+ layout_config = LayoutConfig(width=width, text_alignment=text_alignment)
165
183
 
166
184
  return self.dg._enqueue("markdown", markdown_proto, layout_config=layout_config)
167
185
 
@@ -173,6 +191,7 @@ class MarkdownMixin:
173
191
  *, # keyword-only arguments:
174
192
  help: str | None = None,
175
193
  width: Width = "stretch",
194
+ text_alignment: TextAlignment = "left",
176
195
  ) -> DeltaGenerator:
177
196
  """Display text in small font.
178
197
 
@@ -224,6 +243,22 @@ class MarkdownMixin:
224
243
  the parent container, the width of the element matches the width
225
244
  of the parent container.
226
245
 
246
+ text_alignment : "left", "center", "right", or "justify"
247
+ The horizontal alignment of the text within the element. This can
248
+ be one of the following:
249
+
250
+ - ``"left"`` (default): Text is aligned to the left edge.
251
+ - ``"center"``: Text is centered.
252
+ - ``"right"``: Text is aligned to the right edge.
253
+ - ``"justify"``: Text is justified (stretched to fill the available
254
+ width with the last line left-aligned).
255
+
256
+ .. note::
257
+ For text alignment to have a visible effect, the element's
258
+ width must be wider than its content. If you use
259
+ ``width="content"`` with short text, the alignment may not be
260
+ noticeable.
261
+
227
262
  Examples
228
263
  --------
229
264
  >>> import streamlit as st
@@ -241,7 +276,7 @@ class MarkdownMixin:
241
276
  caption_proto.help = help
242
277
 
243
278
  validate_width(width, allow_content=True)
244
- layout_config = LayoutConfig(width=width)
279
+ layout_config = LayoutConfig(width=width, text_alignment=text_alignment)
245
280
 
246
281
  return self.dg._enqueue("markdown", caption_proto, layout_config=layout_config)
247
282
 
@@ -370,6 +405,7 @@ class MarkdownMixin:
370
405
  "primary",
371
406
  ] = "blue",
372
407
  width: Width = "content",
408
+ help: str | None = None,
373
409
  ) -> DeltaGenerator:
374
410
  """Display a colored badge with an icon and label.
375
411
 
@@ -437,6 +473,14 @@ class MarkdownMixin:
437
473
  the parent container, the width of the element matches the width
438
474
  of the parent container.
439
475
 
476
+ help : str or None
477
+ A tooltip to display when hovering over the badge. If this is
478
+ ``None`` (default), no tooltip is displayed.
479
+
480
+ The tooltip can optionally contain GitHub-flavored Markdown,
481
+ including the Markdown directives described in the ``body``
482
+ parameter of ``st.markdown``.
483
+
440
484
  Examples
441
485
  --------
442
486
  Create standalone badges with ``st.badge`` (with or without icons). If
@@ -452,7 +496,7 @@ class MarkdownMixin:
452
496
  >>> ":violet-badge[:material/star: Favorite] :orange-badge[⚠️ Needs review] :gray-badge[Deprecated]"
453
497
  >>> )
454
498
 
455
- .. output ::
499
+ .. output::
456
500
  https://doc-badge.streamlit.app/
457
501
  height: 220px
458
502
 
@@ -466,6 +510,9 @@ class MarkdownMixin:
466
510
  badge_proto.body = f":{color}-badge[{icon_str}{escaped_label}]"
467
511
  badge_proto.element_type = MarkdownProto.Type.NATIVE
468
512
 
513
+ if help is not None:
514
+ badge_proto.help = help
515
+
469
516
  validate_width(width, allow_content=True)
470
517
  layout_config = LayoutConfig(width=width)
471
518
 
@@ -31,7 +31,7 @@ from streamlit.elements.lib.utils import (
31
31
  LabelVisibility,
32
32
  get_label_visibility_proto_value,
33
33
  )
34
- from streamlit.errors import StreamlitAPIException
34
+ from streamlit.errors import StreamlitAPIException, StreamlitValueError
35
35
  from streamlit.proto.Metric_pb2 import Metric as MetricProto
36
36
  from streamlit.runtime.metrics_util import gather_metrics
37
37
  from streamlit.string_util import AnyNumber, clean_text, from_number
@@ -43,6 +43,7 @@ if TYPE_CHECKING:
43
43
  Value: TypeAlias = AnyNumber | str | None
44
44
  Delta: TypeAlias = AnyNumber | str | None
45
45
  DeltaColor: TypeAlias = Literal["normal", "inverse", "off"]
46
+ DeltaArrow: TypeAlias = Literal["auto", "up", "down", "off"]
46
47
 
47
48
 
48
49
  @dataclass(frozen=True)
@@ -67,6 +68,7 @@ class MetricMixin:
67
68
  height: Height = "content",
68
69
  chart_data: OptionSequence[Any] | None = None,
69
70
  chart_type: Literal["line", "bar", "area"] = "line",
71
+ delta_arrow: DeltaArrow = "auto",
70
72
  ) -> DeltaGenerator:
71
73
  r"""Display a metric in big bold font, with an optional indicator of how the metric changed.
72
74
 
@@ -172,6 +174,17 @@ class MetricMixin:
172
174
  - ``"area"``: A sparkline with area shading.
173
175
  - ``"bar"``: A bar chart.
174
176
 
177
+ delta_arrow : "auto", "up", "down", or "off"
178
+ Controls the direction of the delta indicator arrow. This can be
179
+ one of the following strings:
180
+
181
+ - ``"auto"`` (default): The arrow direction follows the sign of
182
+ ``delta``.
183
+ - ``"up"`` or ``"down"``: The arrow is forced to point in the
184
+ specified direction.
185
+ - ``"off"``: No arrow is shown, but the delta value remains
186
+ visible.
187
+
175
188
  Examples
176
189
  --------
177
190
  **Example 1: Show a metric**
@@ -280,6 +293,17 @@ class MetricMixin:
280
293
  )
281
294
  metric_proto.color = color_and_direction.color
282
295
  metric_proto.direction = color_and_direction.direction
296
+ parsed_delta_arrow = _parse_delta_arrow(
297
+ cast("DeltaArrow", clean_text(delta_arrow))
298
+ )
299
+
300
+ if parsed_delta_arrow != "auto":
301
+ if parsed_delta_arrow == "off":
302
+ metric_proto.direction = MetricProto.MetricDirection.NONE
303
+ elif parsed_delta_arrow == "up":
304
+ metric_proto.direction = MetricProto.MetricDirection.UP
305
+ elif parsed_delta_arrow == "down":
306
+ metric_proto.direction = MetricProto.MetricDirection.DOWN
283
307
  metric_proto.label_visibility.value = get_label_visibility_proto_value(
284
308
  label_visibility
285
309
  )
@@ -322,6 +346,12 @@ def _parse_chart_type(
322
346
  return MetricProto.ChartType.LINE
323
347
 
324
348
 
349
+ def _parse_delta_arrow(delta_arrow: DeltaArrow) -> DeltaArrow:
350
+ if delta_arrow not in {"auto", "up", "down", "off"}:
351
+ raise StreamlitValueError("delta_arrow", ["auto", "up", "down", "off"])
352
+ return delta_arrow
353
+
354
+
325
355
  def _parse_label(label: str) -> str:
326
356
  if not isinstance(label, str):
327
357
  raise TypeError(
@@ -37,8 +37,10 @@ from streamlit.deprecation_util import (
37
37
  )
38
38
  from streamlit.elements.lib.form_utils import current_form_id
39
39
  from streamlit.elements.lib.layout_utils import (
40
+ Height,
40
41
  LayoutConfig,
41
42
  Width,
43
+ validate_height,
42
44
  validate_width,
43
45
  )
44
46
  from streamlit.elements.lib.policies import check_widget_policies
@@ -324,6 +326,53 @@ def _resolve_content_width(width: Width, figure: Any) -> Width:
324
326
  return 700
325
327
 
326
328
 
329
+ def _resolve_content_height(height: Height, figure: Any) -> Height:
330
+ """Resolve "content" height by inspecting the figure's layout height.
331
+
332
+ For content height, we check if the plotly figure has an explicit height
333
+ in its layout. If so, we use that as a pixel height. If not, we default
334
+ to 450 pixels which matches the plotly.js default height.
335
+
336
+ Args
337
+ ----
338
+ height : Height
339
+ The original height parameter
340
+ figure : Any
341
+ The plotly figure object (Figure, dict, or other supported formats)
342
+
343
+ Returns
344
+ -------
345
+ Height
346
+ The resolved height (either original height, figure height as pixels, or 450)
347
+ """
348
+
349
+ if height != "content":
350
+ return height
351
+
352
+ # Extract height from the figure's layout
353
+ # plotly.tools.mpl_to_plotly() returns Figure objects with .layout attribute
354
+ # plotly.tools.return_figure_from_figure_or_data() returns dictionaries
355
+ figure_height = None
356
+ if isinstance(figure, dict):
357
+ figure_height = figure.get("layout", {}).get("height")
358
+ else:
359
+ # Handle Figure objects from matplotlib conversion
360
+ try:
361
+ figure_height = figure.layout.height
362
+ except (AttributeError, TypeError):
363
+ _LOGGER.debug("Could not parse height from figure")
364
+
365
+ if (
366
+ figure_height is not None
367
+ and isinstance(figure_height, (int, float))
368
+ and figure_height > 0
369
+ ):
370
+ return int(figure_height)
371
+
372
+ # Default to 450 pixels (plotly.js default) when no height is specified
373
+ return 450
374
+
375
+
327
376
  class PlotlyMixin:
328
377
  @overload
329
378
  def plotly_chart(
@@ -332,6 +381,7 @@ class PlotlyMixin:
332
381
  use_container_width: bool | None = None,
333
382
  *,
334
383
  width: Width = "stretch",
384
+ height: Height = "content",
335
385
  theme: Literal["streamlit"] | None = "streamlit",
336
386
  key: Key | None = None,
337
387
  on_select: Literal["ignore"], # No default value here to make it work with mypy
@@ -350,6 +400,7 @@ class PlotlyMixin:
350
400
  use_container_width: bool | None = None,
351
401
  *,
352
402
  width: Width = "stretch",
403
+ height: Height = "content",
353
404
  theme: Literal["streamlit"] | None = "streamlit",
354
405
  key: Key | None = None,
355
406
  on_select: Literal["rerun"] | WidgetCallback = "rerun",
@@ -368,6 +419,7 @@ class PlotlyMixin:
368
419
  use_container_width: bool | None = None,
369
420
  *,
370
421
  width: Width = "stretch",
422
+ height: Height = "content",
371
423
  theme: Literal["streamlit"] | None = "streamlit",
372
424
  key: Key | None = None,
373
425
  on_select: Literal["rerun", "ignore"] | WidgetCallback = "ignore",
@@ -429,6 +481,19 @@ class PlotlyMixin:
429
481
  the parent container, the width of the element matches the width
430
482
  of the parent container.
431
483
 
484
+ height : "content", "stretch", or int
485
+ The height of the chart element. This can be one of the following:
486
+
487
+ - ``"content"`` (default): The height of the element matches the
488
+ height of its content.
489
+ - ``"stretch"``: The height of the element matches the height of
490
+ its content or the height of the parent container, whichever is
491
+ larger. If the element is not in a parent container, the height
492
+ of the element matches the height of its content.
493
+ - An integer specifying the height in pixels: The element has a
494
+ fixed height. If the content is larger than the specified
495
+ height, scrolling is enabled.
496
+
432
497
  use_container_width : bool or None
433
498
  Whether to override the figure's native width with the width of
434
499
  the parent container. This can be one of the following:
@@ -595,6 +660,7 @@ class PlotlyMixin:
595
660
  width = "content"
596
661
 
597
662
  validate_width(width, allow_content=True)
663
+ validate_height(height, allow_content=True)
598
664
 
599
665
  import plotly.io
600
666
  import plotly.tools
@@ -605,9 +671,10 @@ class PlotlyMixin:
605
671
 
606
672
  if kwargs:
607
673
  show_deprecation_warning(
608
- "The keyword arguments have been deprecated and will be removed "
609
- "in a future release. Use `config` instead to specify Plotly "
610
- "configuration options."
674
+ "Variable keyword arguments for `st.plotly_chart` have been "
675
+ "deprecated and will be removed in a future release. Use the "
676
+ "`config` argument instead to specify Plotly configuration "
677
+ "options."
611
678
  )
612
679
 
613
680
  if theme not in ["streamlit", None]:
@@ -671,10 +738,12 @@ class PlotlyMixin:
671
738
  is_selection_activated=is_selection_activated,
672
739
  theme=theme,
673
740
  width=width,
741
+ height=height,
674
742
  )
675
743
 
676
- # Handle "content" width by inspecting the figure's natural width
744
+ # Handle "content" width and height by inspecting the figure's natural dimensions
677
745
  final_width = _resolve_content_width(width, figure)
746
+ final_height = _resolve_content_height(height, figure)
678
747
 
679
748
  if is_selection_activated:
680
749
  # Selections are activated, treat plotly chart as a widget:
@@ -693,13 +762,13 @@ class PlotlyMixin:
693
762
  value_type="string_value",
694
763
  )
695
764
 
696
- layout_config = LayoutConfig(width=final_width)
765
+ layout_config = LayoutConfig(width=final_width, height=final_height)
697
766
  self.dg._enqueue(
698
767
  "plotly_chart", plotly_chart_proto, layout_config=layout_config
699
768
  )
700
769
  return widget_state.value
701
770
 
702
- layout_config = LayoutConfig(width=final_width)
771
+ layout_config = LayoutConfig(width=final_width, height=final_height)
703
772
  return self.dg._enqueue(
704
773
  "plotly_chart", plotly_chart_proto, layout_config=layout_config
705
774
  )
@@ -88,7 +88,7 @@ def spinner(
88
88
  >>> st.success("Done!")
89
89
  >>> st.button("Rerun")
90
90
 
91
- .. output ::
91
+ .. output::
92
92
  https://doc-spinner.streamlit.app/
93
93
  height: 210px
94
94
 
@@ -23,7 +23,7 @@ from streamlit.string_util import clean_text
23
23
 
24
24
  if TYPE_CHECKING:
25
25
  from streamlit.delta_generator import DeltaGenerator
26
- from streamlit.elements.lib.layout_utils import Width
26
+ from streamlit.elements.lib.layout_utils import TextAlignment, Width
27
27
  from streamlit.type_util import SupportsStr
28
28
 
29
29
 
@@ -35,6 +35,7 @@ class TextMixin:
35
35
  *, # keyword-only arguments:
36
36
  help: str | None = None,
37
37
  width: Width = "content",
38
+ text_alignment: TextAlignment = "left",
38
39
  ) -> DeltaGenerator:
39
40
  r"""Write text without Markdown or HTML parsing.
40
41
 
@@ -69,13 +70,29 @@ class TextMixin:
69
70
  the parent container, the width of the element matches the width
70
71
  of the parent container.
71
72
 
73
+ text_alignment : "left", "center", "right", or "justify"
74
+ The horizontal alignment of the text within the element. This can
75
+ be one of the following:
76
+
77
+ - ``"left"`` (default): Text is aligned to the left edge.
78
+ - ``"center"``: Text is centered.
79
+ - ``"right"``: Text is aligned to the right edge.
80
+ - ``"justify"``: Text is justified (stretched to fill the available
81
+ width with the last line left-aligned).
82
+
83
+ .. note::
84
+ For text alignment to have a visible effect, the element's
85
+ width must be wider than its content. If you use
86
+ ``width="content"`` with short text, the alignment may not be
87
+ noticeable.
88
+
72
89
  Example
73
90
  -------
74
91
  >>> import streamlit as st
75
92
  >>>
76
93
  >>> st.text("This is text\n[and more text](that's not a Markdown link).")
77
94
 
78
- .. output ::
95
+ .. output::
79
96
  https://doc-text.streamlit.app/
80
97
  height: 220px
81
98
 
@@ -86,7 +103,7 @@ class TextMixin:
86
103
  text_proto.help = help
87
104
 
88
105
  validate_width(width, allow_content=True)
89
- layout_config = LayoutConfig(width=width)
106
+ layout_config = LayoutConfig(width=width, text_alignment=text_alignment)
90
107
 
91
108
  return self.dg._enqueue("text", text_proto, layout_config=layout_config)
92
109
 
@@ -80,6 +80,8 @@ class ToastMixin:
80
80
  <https://fonts.google.com/icons?icon.set=Material+Symbols&icon.style=Rounded>`_
81
81
  font library.
82
82
 
83
+ - ``"spinner"``: Displays a spinner as an icon.
84
+
83
85
  duration : "short", "long", "infinite", or int
84
86
  The time to display the toast message. This can be one of the
85
87
  following: