streamlit 1.50.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 (406) hide show
  1. streamlit/__init__.py +5 -1
  2. streamlit/commands/execution_control.py +89 -14
  3. streamlit/commands/navigation.py +4 -6
  4. streamlit/commands/page_config.py +4 -6
  5. streamlit/components/v1/component_arrow.py +7 -7
  6. streamlit/components/v2/__init__.py +514 -0
  7. streamlit/components/v2/bidi_component/__init__.py +20 -0
  8. streamlit/components/v2/bidi_component/constants.py +29 -0
  9. streamlit/components/v2/bidi_component/main.py +534 -0
  10. streamlit/components/v2/bidi_component/serialization.py +272 -0
  11. streamlit/components/v2/bidi_component/state.py +92 -0
  12. streamlit/components/v2/component_definition_resolver.py +143 -0
  13. streamlit/components/v2/component_file_watcher.py +403 -0
  14. streamlit/components/v2/component_manager.py +439 -0
  15. streamlit/components/v2/component_manifest_handler.py +122 -0
  16. streamlit/components/v2/component_path_utils.py +245 -0
  17. streamlit/components/v2/component_registry.py +426 -0
  18. streamlit/components/v2/get_bidi_component_manager.py +51 -0
  19. streamlit/components/v2/manifest_scanner.py +615 -0
  20. streamlit/components/v2/presentation.py +198 -0
  21. streamlit/components/v2/types.py +324 -0
  22. streamlit/config.py +456 -53
  23. streamlit/config_option.py +4 -1
  24. streamlit/config_util.py +650 -1
  25. streamlit/connections/snowflake_connection.py +1 -1
  26. streamlit/connections/snowpark_connection.py +1 -1
  27. streamlit/dataframe_util.py +33 -26
  28. streamlit/delta_generator.py +13 -4
  29. streamlit/delta_generator_singletons.py +11 -15
  30. streamlit/deprecation_util.py +17 -6
  31. streamlit/elements/alert.py +16 -0
  32. streamlit/elements/arrow.py +68 -10
  33. streamlit/elements/bokeh_chart.py +10 -78
  34. streamlit/elements/code.py +2 -2
  35. streamlit/elements/deck_gl_json_chart.py +98 -40
  36. streamlit/elements/dialog_decorator.py +2 -1
  37. streamlit/elements/exception.py +4 -2
  38. streamlit/elements/form.py +27 -0
  39. streamlit/elements/graphviz_chart.py +1 -3
  40. streamlit/elements/heading.py +63 -10
  41. streamlit/elements/html.py +13 -2
  42. streamlit/elements/image.py +3 -5
  43. streamlit/elements/layouts.py +59 -33
  44. streamlit/elements/lib/built_in_chart_utils.py +50 -19
  45. streamlit/elements/lib/color_util.py +9 -19
  46. streamlit/elements/lib/column_config_utils.py +9 -12
  47. streamlit/elements/lib/column_types.py +40 -12
  48. streamlit/elements/lib/dialog.py +2 -2
  49. streamlit/elements/lib/image_utils.py +3 -5
  50. streamlit/elements/lib/layout_utils.py +100 -13
  51. streamlit/elements/lib/mutable_status_container.py +2 -2
  52. streamlit/elements/lib/options_selector_utils.py +2 -2
  53. streamlit/elements/lib/pandas_styler_utils.py +17 -9
  54. streamlit/elements/lib/shortcut_utils.py +152 -0
  55. streamlit/elements/lib/utils.py +4 -4
  56. streamlit/elements/map.py +80 -37
  57. streamlit/elements/markdown.py +50 -3
  58. streamlit/elements/media.py +5 -7
  59. streamlit/elements/metric.py +34 -6
  60. streamlit/elements/pdf.py +2 -4
  61. streamlit/elements/plotly_chart.py +197 -20
  62. streamlit/elements/progress.py +2 -4
  63. streamlit/elements/space.py +113 -0
  64. streamlit/elements/spinner.py +1 -1
  65. streamlit/elements/text.py +20 -3
  66. streamlit/elements/toast.py +2 -0
  67. streamlit/elements/vega_charts.py +356 -149
  68. streamlit/elements/widgets/audio_input.py +12 -11
  69. streamlit/elements/widgets/button.py +280 -43
  70. streamlit/elements/widgets/button_group.py +60 -9
  71. streamlit/elements/widgets/camera_input.py +3 -5
  72. streamlit/elements/widgets/chat.py +307 -43
  73. streamlit/elements/widgets/color_picker.py +8 -1
  74. streamlit/elements/widgets/data_editor.py +88 -44
  75. streamlit/elements/widgets/file_uploader.py +9 -11
  76. streamlit/elements/widgets/multiselect.py +4 -3
  77. streamlit/elements/widgets/number_input.py +4 -4
  78. streamlit/elements/widgets/radio.py +10 -3
  79. streamlit/elements/widgets/select_slider.py +8 -5
  80. streamlit/elements/widgets/selectbox.py +6 -3
  81. streamlit/elements/widgets/slider.py +38 -42
  82. streamlit/elements/widgets/text_widgets.py +2 -0
  83. streamlit/elements/widgets/time_widgets.py +587 -21
  84. streamlit/elements/write.py +27 -6
  85. streamlit/emojis.py +1 -1
  86. streamlit/errors.py +137 -0
  87. streamlit/git_util.py +1 -1
  88. streamlit/hello/hello.py +8 -0
  89. streamlit/hello/utils.py +2 -1
  90. streamlit/material_icon_names.py +1 -1
  91. streamlit/navigation/page.py +11 -1
  92. streamlit/net_util.py +2 -2
  93. streamlit/proto/Alert_pb2.pyi +3 -3
  94. streamlit/proto/AppPage_pb2.pyi +7 -1
  95. streamlit/proto/ArrowData_pb2.py +27 -0
  96. streamlit/proto/ArrowData_pb2.pyi +52 -0
  97. streamlit/proto/ArrowNamedDataSet_pb2.pyi +7 -1
  98. streamlit/proto/ArrowVegaLiteChart_pb2.pyi +7 -1
  99. streamlit/proto/Arrow_pb2.py +10 -10
  100. streamlit/proto/Arrow_pb2.pyi +19 -12
  101. streamlit/proto/AudioInput_pb2.pyi +7 -1
  102. streamlit/proto/Audio_pb2.pyi +7 -1
  103. streamlit/proto/AuthRedirect_pb2.pyi +7 -1
  104. streamlit/proto/AutoRerun_pb2.pyi +7 -1
  105. streamlit/proto/BackMsg_pb2.py +4 -2
  106. streamlit/proto/BackMsg_pb2.pyi +34 -4
  107. streamlit/proto/Balloons_pb2.pyi +7 -1
  108. streamlit/proto/BidiComponent_pb2.py +34 -0
  109. streamlit/proto/BidiComponent_pb2.pyi +159 -0
  110. streamlit/proto/Block_pb2.py +7 -7
  111. streamlit/proto/Block_pb2.pyi +39 -36
  112. streamlit/proto/BokehChart_pb2.pyi +7 -1
  113. streamlit/proto/ButtonGroup_pb2.pyi +9 -9
  114. streamlit/proto/Button_pb2.py +2 -2
  115. streamlit/proto/Button_pb2.pyi +11 -2
  116. streamlit/proto/CameraInput_pb2.pyi +7 -1
  117. streamlit/proto/ChatInput_pb2.py +6 -6
  118. streamlit/proto/ChatInput_pb2.pyi +18 -6
  119. streamlit/proto/Checkbox_pb2.pyi +3 -3
  120. streamlit/proto/ClientState_pb2.pyi +10 -4
  121. streamlit/proto/Code_pb2.pyi +7 -1
  122. streamlit/proto/ColorPicker_pb2.pyi +7 -1
  123. streamlit/proto/Common_pb2.py +3 -3
  124. streamlit/proto/Common_pb2.pyi +35 -23
  125. streamlit/proto/Components_pb2.pyi +19 -13
  126. streamlit/proto/DataFrame_pb2.pyi +55 -49
  127. streamlit/proto/DateInput_pb2.pyi +7 -1
  128. streamlit/proto/DateTimeInput_pb2.py +28 -0
  129. streamlit/proto/DateTimeInput_pb2.pyi +92 -0
  130. streamlit/proto/DeckGlJsonChart_pb2.py +10 -4
  131. streamlit/proto/DeckGlJsonChart_pb2.pyi +12 -6
  132. streamlit/proto/Delta_pb2.pyi +7 -1
  133. streamlit/proto/DocString_pb2.pyi +10 -4
  134. streamlit/proto/DownloadButton_pb2.py +2 -2
  135. streamlit/proto/DownloadButton_pb2.pyi +16 -2
  136. streamlit/proto/Element_pb2.py +7 -3
  137. streamlit/proto/Element_pb2.pyi +33 -5
  138. streamlit/proto/Empty_pb2.pyi +7 -1
  139. streamlit/proto/Exception_pb2.pyi +7 -1
  140. streamlit/proto/Favicon_pb2.pyi +7 -1
  141. streamlit/proto/FileUploader_pb2.pyi +7 -1
  142. streamlit/proto/ForwardMsg_pb2.py +12 -10
  143. streamlit/proto/ForwardMsg_pb2.pyi +42 -15
  144. streamlit/proto/GapSize_pb2.pyi +4 -4
  145. streamlit/proto/GitInfo_pb2.pyi +3 -3
  146. streamlit/proto/GraphVizChart_pb2.pyi +7 -1
  147. streamlit/proto/Heading_pb2.pyi +7 -1
  148. streamlit/proto/HeightConfig_pb2.py +2 -2
  149. streamlit/proto/HeightConfig_pb2.pyi +13 -4
  150. streamlit/proto/Html_pb2.py +2 -2
  151. streamlit/proto/Html_pb2.pyi +11 -2
  152. streamlit/proto/IFrame_pb2.pyi +7 -1
  153. streamlit/proto/Image_pb2.pyi +10 -4
  154. streamlit/proto/Json_pb2.pyi +7 -1
  155. streamlit/proto/LabelVisibilityMessage_pb2.pyi +3 -3
  156. streamlit/proto/LinkButton_pb2.py +2 -2
  157. streamlit/proto/LinkButton_pb2.pyi +15 -2
  158. streamlit/proto/Logo_pb2.pyi +7 -1
  159. streamlit/proto/Markdown_pb2.pyi +3 -3
  160. streamlit/proto/Metric_pb2.pyi +7 -7
  161. streamlit/proto/MetricsEvent_pb2.pyi +10 -4
  162. streamlit/proto/MultiSelect_pb2.pyi +7 -1
  163. streamlit/proto/NamedDataSet_pb2.pyi +7 -1
  164. streamlit/proto/Navigation_pb2.pyi +3 -3
  165. streamlit/proto/NewSession_pb2.py +18 -18
  166. streamlit/proto/NewSession_pb2.pyi +59 -40
  167. streamlit/proto/NumberInput_pb2.pyi +3 -3
  168. streamlit/proto/PageConfig_pb2.pyi +7 -7
  169. streamlit/proto/PageInfo_pb2.pyi +7 -1
  170. streamlit/proto/PageLink_pb2.py +2 -2
  171. streamlit/proto/PageLink_pb2.pyi +11 -2
  172. streamlit/proto/PageNotFound_pb2.pyi +7 -1
  173. streamlit/proto/PageProfile_pb2.pyi +13 -7
  174. streamlit/proto/PagesChanged_pb2.pyi +7 -1
  175. streamlit/proto/ParentMessage_pb2.pyi +7 -1
  176. streamlit/proto/PlotlyChart_pb2.py +8 -6
  177. streamlit/proto/PlotlyChart_pb2.pyi +9 -7
  178. streamlit/proto/Progress_pb2.pyi +7 -1
  179. streamlit/proto/Radio_pb2.pyi +7 -1
  180. streamlit/proto/RootContainer_pb2.pyi +1 -1
  181. streamlit/proto/Selectbox_pb2.pyi +7 -1
  182. streamlit/proto/SessionEvent_pb2.pyi +7 -1
  183. streamlit/proto/SessionStatus_pb2.pyi +7 -1
  184. streamlit/proto/Skeleton_pb2.pyi +3 -3
  185. streamlit/proto/Slider_pb2.pyi +5 -5
  186. streamlit/proto/Snow_pb2.pyi +7 -1
  187. streamlit/proto/Space_pb2.py +27 -0
  188. streamlit/proto/Space_pb2.pyi +48 -0
  189. streamlit/proto/Spinner_pb2.pyi +7 -1
  190. streamlit/proto/TextAlignmentConfig_pb2.py +29 -0
  191. streamlit/proto/TextAlignmentConfig_pb2.pyi +68 -0
  192. streamlit/proto/TextArea_pb2.pyi +7 -1
  193. streamlit/proto/TextInput_pb2.pyi +3 -3
  194. streamlit/proto/Text_pb2.pyi +7 -1
  195. streamlit/proto/TimeInput_pb2.pyi +7 -1
  196. streamlit/proto/Toast_pb2.pyi +7 -1
  197. streamlit/proto/VegaLiteChart_pb2.pyi +7 -1
  198. streamlit/proto/Video_pb2.pyi +6 -6
  199. streamlit/proto/WidgetStates_pb2.py +2 -2
  200. streamlit/proto/WidgetStates_pb2.pyi +23 -7
  201. streamlit/proto/WidthConfig_pb2.py +2 -2
  202. streamlit/proto/WidthConfig_pb2.pyi +13 -4
  203. streamlit/proto/openmetrics_data_model_pb2.pyi +52 -52
  204. streamlit/runtime/app_session.py +65 -2
  205. streamlit/runtime/caching/cache_data_api.py +5 -5
  206. streamlit/runtime/caching/cache_errors.py +4 -1
  207. streamlit/runtime/caching/cache_resource_api.py +5 -4
  208. streamlit/runtime/caching/cache_utils.py +3 -2
  209. streamlit/runtime/caching/cached_message_replay.py +3 -3
  210. streamlit/runtime/caching/hashing.py +4 -5
  211. streamlit/runtime/caching/legacy_cache_api.py +2 -1
  212. streamlit/runtime/connection_factory.py +1 -3
  213. streamlit/runtime/download_data_util.py +53 -0
  214. streamlit/runtime/forward_msg_queue.py +5 -1
  215. streamlit/runtime/fragment.py +2 -1
  216. streamlit/runtime/media_file_manager.py +178 -2
  217. streamlit/runtime/memory_media_file_storage.py +1 -1
  218. streamlit/runtime/metrics_util.py +91 -3
  219. streamlit/runtime/runtime.py +14 -0
  220. streamlit/runtime/scriptrunner/exec_code.py +2 -1
  221. streamlit/runtime/scriptrunner/script_runner.py +5 -3
  222. streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -6
  223. streamlit/runtime/secrets.py +2 -4
  224. streamlit/runtime/session_manager.py +3 -1
  225. streamlit/runtime/state/common.py +30 -5
  226. streamlit/runtime/state/presentation.py +85 -0
  227. streamlit/runtime/state/query_params.py +80 -29
  228. streamlit/runtime/state/safe_session_state.py +2 -2
  229. streamlit/runtime/state/session_state.py +221 -17
  230. streamlit/runtime/state/widgets.py +19 -3
  231. streamlit/runtime/websocket_session_manager.py +3 -1
  232. streamlit/source_util.py +2 -2
  233. streamlit/static/index.html +2 -2
  234. streamlit/static/manifest.json +557 -239
  235. streamlit/static/static/css/{index.CIiu7Ygf.css → index.BpABIXK9.css} +1 -1
  236. streamlit/static/static/css/index.DgR7E2CV.css +1 -0
  237. streamlit/static/static/js/{ErrorOutline.esm.DUpR0_Ka.js → ErrorOutline.esm.ZJDbmVTx.js} +1 -1
  238. streamlit/static/static/js/{FileDownload.esm.CN4j9-1w.js → FileDownload.esm.Dx0vI3vH.js} +1 -1
  239. streamlit/static/static/js/{FileHelper.CaIUKG91.js → FileHelper.B7Ero7qQ.js} +3 -3
  240. streamlit/static/static/js/{FormClearHelper.DTcdrasw.js → FormClearHelper.CG2XN1_g.js} +1 -1
  241. streamlit/static/static/js/IFrameUtil.DefezniK.js +1 -0
  242. streamlit/static/static/js/InputInstructions.Cj5-1zf6.js +1 -0
  243. streamlit/static/static/js/Particles.BfWfv0Aw.js +1 -0
  244. streamlit/static/static/js/{ProgressBar.DetlP5aY.js → ProgressBar.CGQ8OgfO.js} +2 -2
  245. streamlit/static/static/js/StreamlitSyntaxHighlighter.DTKLpwhl.js +20 -0
  246. streamlit/static/static/js/{Toolbar.C77ar7rq.js → Toolbar.B2qFUmd9.js} +1 -1
  247. streamlit/static/static/js/_arrayIncludes.B19Iyn2B.js +1 -0
  248. streamlit/static/static/js/_baseIndexOf.BTknn6Gb.js +1 -0
  249. streamlit/static/static/js/{base-input.BQft14La.js → base-input.o9tL8MDP.js} +4 -4
  250. streamlit/static/static/js/{checkbox.yZOfXCeX.js → checkbox.0BeV1IBL.js} +1 -1
  251. streamlit/static/static/js/{createSuper.Dh9w1cs8.js → createSuper.RBO59fEm.js} +1 -1
  252. streamlit/static/static/js/data-grid-overlay-editor.CiTkUy0t.js +1 -0
  253. streamlit/static/static/js/{downloader.MeHtkq8r.js → downloader.DwNZg3Mw.js} +1 -1
  254. streamlit/static/static/js/embed.XT9xNd3F.js +195 -0
  255. streamlit/static/static/js/{es6.VpBPGCnM.js → es6.x9KsYQg-.js} +2 -2
  256. streamlit/static/static/js/{iframeResizer.contentWindow.yMw_ARIL.js → iframeResizer.contentWindow.ZVXpMPi0.js} +1 -1
  257. streamlit/static/static/js/index.5VPOamri.js +1 -0
  258. streamlit/static/static/js/index.8HslT92O.js +14 -0
  259. streamlit/static/static/js/index.AnXMIBz3.js +7 -0
  260. streamlit/static/static/js/index.B0yp3bM1.js +6 -0
  261. streamlit/static/static/js/index.B1fRb5wF.js +1 -0
  262. streamlit/static/static/js/index.B527JZdO.js +3 -0
  263. streamlit/static/static/js/index.BHgV-yW4.js +1 -0
  264. streamlit/static/static/js/index.BQr-XwGV.js +1 -0
  265. streamlit/static/static/js/index.BTtmaLDB.js +1 -0
  266. streamlit/static/static/js/index.BWB_91TA.js +1 -0
  267. streamlit/static/static/js/index.BfEKaEmw.js +1 -0
  268. streamlit/static/static/js/index.BfXjTO8b.js +1 -0
  269. streamlit/static/static/js/index.Bjy4NRu9.js +3 -0
  270. streamlit/static/static/js/index.Bu5JWpT_.js +1 -0
  271. streamlit/static/static/js/index.BuCx76ZV.js +1 -0
  272. streamlit/static/static/js/index.BxjzhVUb.js +2 -0
  273. streamlit/static/static/js/index.By55VdPY.js +1 -0
  274. streamlit/static/static/js/index.CF5MxTbK.js +1 -0
  275. streamlit/static/static/js/index.CLmq_z9K.js +1 -0
  276. streamlit/static/static/js/index.CNH4rdSz.js +1 -0
  277. streamlit/static/static/js/{index.B0H9IXUJ.js → index.CTgm_-jO.js} +10 -41
  278. streamlit/static/static/js/index.C_rK-Swb.js +188 -0
  279. streamlit/static/static/js/index.CjozwSzS.js +1 -0
  280. streamlit/static/static/js/{index.CH1tqnSs.js → index.CkGVt6-G.js} +1 -1
  281. streamlit/static/static/js/index.CuvXOyER.js +2 -0
  282. streamlit/static/static/js/{index.FFOzOWzC.js → index.CyUHWoCC.js} +2 -2
  283. streamlit/static/static/js/index.CyroQtI4.js +2 -0
  284. streamlit/static/static/js/index.D6HmkoDm.js +263 -0
  285. streamlit/static/static/js/index.DAqCNvsO.js +1 -0
  286. streamlit/static/static/js/index.DB_w_CZQ.js +1 -0
  287. streamlit/static/static/js/index.DBalctjj.js +2 -0
  288. streamlit/static/static/js/index.DK0RFJUG.js +11 -0
  289. streamlit/static/static/js/index.DMxc2XFp.js +151 -0
  290. streamlit/static/static/js/index.DO5utP74.js +2 -0
  291. streamlit/static/static/js/index.DS7lf09n.js +1 -0
  292. streamlit/static/static/js/index.DWexTVLY.js +1 -0
  293. streamlit/static/static/js/index.DXxnU5ej.js +1 -0
  294. streamlit/static/static/js/index.DcU3uDvB.js +2 -0
  295. streamlit/static/static/js/index.DlltaH7J.js +1 -0
  296. streamlit/static/static/js/index.DpNTZz82.js +27 -0
  297. streamlit/static/static/js/index.Dr9HIhQw.js +1 -0
  298. streamlit/static/static/js/index.DsgAU5lc.js +1 -0
  299. streamlit/static/static/js/{index.64ejlaaT.js → index.KfXqjDYy.js} +1 -1
  300. streamlit/static/static/js/index.PaidgjCs.js +1 -0
  301. streamlit/static/static/js/index.RJZuWCGA.js +1 -0
  302. streamlit/static/static/js/{index.Ctn27_AE.js → index.hbeqcRTn.js} +53 -122
  303. streamlit/static/static/js/index.q5hIQwAY.js +1 -0
  304. streamlit/static/static/js/index.rORSX6IW.js +1 -0
  305. streamlit/static/static/js/index.uSX757_v.js +1 -0
  306. streamlit/static/static/js/index.x_QRaLMd.js +1 -0
  307. streamlit/static/static/js/{input.s6pjQ49A.js → input.D5oh9-aB.js} +2 -2
  308. streamlit/static/static/js/main.q9oGOg0H.js +13 -0
  309. streamlit/static/static/js/{memory.Cuvsdfrl.js → memory.5kCSFUJS.js} +1 -1
  310. streamlit/static/static/js/moment.C3j7ZXd7.js +4 -0
  311. streamlit/static/static/js/number-overlay-editor.Cn_LsK8N.js +9 -0
  312. streamlit/static/static/js/pandasStylerUtils.BqhXt51_.js +1 -0
  313. streamlit/static/static/js/{possibleConstructorReturn.CqidKeei.js → possibleConstructorReturn.DD9NK1Z8.js} +1 -1
  314. streamlit/static/static/js/record.B-tDciZb.js +1 -0
  315. streamlit/static/static/js/{sandbox.CCQREcJx.js → sandbox.DACSyz29.js} +1 -1
  316. streamlit/static/static/js/styled-components.C3R090At.js +1 -0
  317. streamlit/static/static/js/threshold.Q1mXg5rX.js +1 -0
  318. streamlit/static/static/js/throttle.B0GR3Iyz.js +1 -0
  319. streamlit/static/static/js/{timepicker.mkJF97Bb.js → timepicker.BdhzPxrv.js} +1 -1
  320. streamlit/static/static/js/timer.C2hYhUse.js +1 -0
  321. streamlit/static/static/js/{toConsumableArray.De7I7KVR.js → toConsumableArray.Db2pdqM2.js} +1 -1
  322. streamlit/static/static/js/uniqueId.CtqIr-Yh.js +1 -0
  323. streamlit/static/static/js/urls.BwSlolu9.js +1 -0
  324. streamlit/static/static/js/{useBasicWidgetState.CedkNjUW.js → useBasicWidgetState.Bfp6TnSw.js} +1 -1
  325. streamlit/static/static/js/useIntlLocale.hRV75Xgj.js +12 -0
  326. streamlit/static/static/js/{useTextInputAutoExpand.Ca7w8dVs.js → useTextInputAutoExpand.QepX7n8Y.js} +1 -1
  327. streamlit/static/static/js/useUpdateUiValue.DHx8TzX6.js +1 -0
  328. streamlit/static/static/js/useWaveformController.WxVzpzEX.js +1 -0
  329. streamlit/static/static/js/value.B4vHRSi7.js +1 -0
  330. streamlit/static/static/js/wavesurfer.esm.vI8Eid4k.js +73 -0
  331. streamlit/static/static/js/withCalculatedWidth.DcKeRSWJ.js +1 -0
  332. streamlit/static/static/js/withFullScreenWrapper.CrHddARq.js +1 -0
  333. streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
  334. streamlit/string_util.py +9 -4
  335. streamlit/testing/v1/app_test.py +17 -2
  336. streamlit/testing/v1/element_tree.py +85 -9
  337. streamlit/testing/v1/util.py +2 -2
  338. streamlit/type_util.py +3 -4
  339. streamlit/url_util.py +1 -3
  340. streamlit/user_info.py +1 -2
  341. streamlit/util.py +3 -1
  342. streamlit/watcher/event_based_path_watcher.py +23 -12
  343. streamlit/watcher/local_sources_watcher.py +11 -1
  344. streamlit/watcher/path_watcher.py +9 -6
  345. streamlit/watcher/polling_path_watcher.py +4 -1
  346. streamlit/watcher/util.py +2 -2
  347. streamlit/web/bootstrap.py +24 -0
  348. streamlit/web/cli.py +51 -22
  349. streamlit/web/server/bidi_component_request_handler.py +193 -0
  350. streamlit/web/server/component_file_utils.py +97 -0
  351. streamlit/web/server/component_request_handler.py +8 -21
  352. streamlit/web/server/oauth_authlib_routes.py +5 -2
  353. streamlit/web/server/oidc_mixin.py +3 -1
  354. streamlit/web/server/routes.py +2 -2
  355. streamlit/web/server/server.py +9 -0
  356. streamlit/web/server/server_util.py +3 -1
  357. streamlit/web/server/upload_file_request_handler.py +19 -1
  358. {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/METADATA +10 -7
  359. streamlit-1.52.0.dist-info/RECORD +620 -0
  360. streamlit/static/static/css/index.CHEnSPGk.css +0 -1
  361. streamlit/static/static/js/Hooks.BRba_Own.js +0 -1
  362. streamlit/static/static/js/InputInstructions.xnSDuYeQ.js +0 -1
  363. streamlit/static/static/js/Particles.CElH0XX2.js +0 -1
  364. streamlit/static/static/js/data-grid-overlay-editor.DcuHuCyW.js +0 -1
  365. streamlit/static/static/js/index.6xX1278W.js +0 -975
  366. streamlit/static/static/js/index.B-hiXRzw.js +0 -1
  367. streamlit/static/static/js/index.B4cAbHP6.js +0 -1
  368. streamlit/static/static/js/index.B4dUQfni.js +0 -1
  369. streamlit/static/static/js/index.BPQo7BKk.js +0 -1
  370. streamlit/static/static/js/index.Baqa90pe.js +0 -2
  371. streamlit/static/static/js/index.Bj9JgOEC.js +0 -1
  372. streamlit/static/static/js/index.BjCwMzj4.js +0 -3
  373. streamlit/static/static/js/index.Bm3VbPB5.js +0 -1
  374. streamlit/static/static/js/index.Bxz2yX3P.js +0 -1
  375. streamlit/static/static/js/index.BycLveZ4.js +0 -1
  376. streamlit/static/static/js/index.C9BdUqTi.js +0 -1
  377. streamlit/static/static/js/index.CFMf5_ez.js +0 -197
  378. streamlit/static/static/js/index.CGYqqs6j.js +0 -1
  379. streamlit/static/static/js/index.CMItVsFA.js +0 -1
  380. streamlit/static/static/js/index.CTBk8Vk2.js +0 -1
  381. streamlit/static/static/js/index.CiAQIz1H.js +0 -7
  382. streamlit/static/static/js/index.Cj7DSzVR.js +0 -73
  383. streamlit/static/static/js/index.Ck8rQ9OL.js +0 -1
  384. streamlit/static/static/js/index.ClELlchS.js +0 -1617
  385. streamlit/static/static/js/index.Cnpi3o3E.js +0 -1
  386. streamlit/static/static/js/index.D2QEXQq_.js +0 -1
  387. streamlit/static/static/js/index.DH71Ezyj.js +0 -1
  388. streamlit/static/static/js/index.DHh-U0dK.js +0 -3
  389. streamlit/static/static/js/index.DK7hD7_w.js +0 -1
  390. streamlit/static/static/js/index.DKv_lNO7.js +0 -2
  391. streamlit/static/static/js/index.DNLrMXgm.js +0 -12
  392. streamlit/static/static/js/index.DW0Grddz.js +0 -1
  393. streamlit/static/static/js/index.Dbe-Q3C-.js +0 -2
  394. streamlit/static/static/js/index.DcPNYEUo.js +0 -1
  395. streamlit/static/static/js/index.DuxqVQpd.js +0 -1
  396. streamlit/static/static/js/index.GRUzrudl.js +0 -1
  397. streamlit/static/static/js/number-overlay-editor.DdgVR5m3.js +0 -9
  398. streamlit/static/static/js/uniqueId.RI1LJdtz.js +0 -1
  399. streamlit/static/static/js/useUpdateUiValue.DeXelfRH.js +0 -1
  400. streamlit/static/static/js/withFullScreenWrapper.C3561XxJ.js +0 -1
  401. streamlit/static/static/media/MaterialSymbols-Rounded.DeCZgS-4.woff2 +0 -0
  402. streamlit-1.50.0.dist-info/RECORD +0 -557
  403. {streamlit-1.50.0.data → streamlit-1.52.0.data}/scripts/streamlit.cmd +0 -0
  404. {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/WHEEL +0 -0
  405. {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/entry_points.txt +0 -0
  406. {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/top_level.txt +0 -0
@@ -23,13 +23,11 @@ from typing import (
23
23
  Any,
24
24
  Final,
25
25
  Literal,
26
- Union,
26
+ TypeAlias,
27
27
  cast,
28
28
  overload,
29
29
  )
30
30
 
31
- from typing_extensions import TypeAlias
32
-
33
31
  from streamlit.elements.lib.form_utils import current_form_id
34
32
  from streamlit.elements.lib.layout_utils import (
35
33
  LayoutConfig,
@@ -49,6 +47,7 @@ from streamlit.elements.lib.utils import (
49
47
  )
50
48
  from streamlit.errors import StreamlitAPIException
51
49
  from streamlit.proto.DateInput_pb2 import DateInput as DateInputProto
50
+ from streamlit.proto.DateTimeInput_pb2 import DateTimeInput as DateTimeInputProto
52
51
  from streamlit.proto.TimeInput_pb2 import TimeInput as TimeInputProto
53
52
  from streamlit.runtime.metrics_util import gather_metrics
54
53
  from streamlit.runtime.scriptrunner import ScriptRunContext, get_script_run_ctx
@@ -65,27 +64,28 @@ if TYPE_CHECKING:
65
64
  from streamlit.delta_generator import DeltaGenerator
66
65
 
67
66
  # Type for things that point to a specific time (even if a default time, though not None).
68
- TimeValue: TypeAlias = Union[time, datetime, str, Literal["now"]]
67
+ TimeValue: TypeAlias = time | datetime | str | Literal["now"]
68
+ DateTimeScalarValue: TypeAlias = datetime | date | time | str | Literal["now"]
69
+ DateTimeValue: TypeAlias = DateTimeScalarValue | None
69
70
 
70
71
  # Type for things that point to a specific date (even if a default date, including None).
71
- NullableScalarDateValue: TypeAlias = Union[date, datetime, str, Literal["today"], None]
72
+ NullableScalarDateValue: TypeAlias = date | datetime | str | Literal["today"] | None
72
73
 
73
74
  # The accepted input value for st.date_input. Can be a date scalar or a date range.
74
- DateValue: TypeAlias = Union[NullableScalarDateValue, Sequence[NullableScalarDateValue]]
75
+ DateValue: TypeAlias = NullableScalarDateValue | Sequence[NullableScalarDateValue]
75
76
 
76
77
  # The return value of st.date_input.
77
- DateWidgetRangeReturn: TypeAlias = Union[
78
- tuple[()],
79
- tuple[date],
80
- tuple[date, date],
81
- ]
82
- DateWidgetReturn: TypeAlias = Union[date, DateWidgetRangeReturn, None]
78
+ DateWidgetRangeReturn: TypeAlias = tuple[()] | tuple[date] | tuple[date, date]
79
+ DateWidgetReturn: TypeAlias = date | DateWidgetRangeReturn | None
83
80
 
84
81
 
85
82
  DEFAULT_STEP_MINUTES: Final = 15
86
83
  ALLOWED_DATE_FORMATS: Final = re.compile(
87
84
  r"^(YYYY[/.\-]MM[/.\-]DD|DD[/.\-]MM[/.\-]YYYY|MM[/.\-]DD[/.\-]YYYY)$"
88
85
  )
86
+ _DATETIME_UI_FORMAT: Final = "%Y/%m/%d, %H:%M"
87
+ _DEFAULT_MIN_BOUND_TIME: Final = time(hour=0, minute=0)
88
+ _DEFAULT_MAX_BOUND_TIME: Final = time(hour=23, minute=59)
89
89
 
90
90
 
91
91
  def _convert_timelike_to_time(value: TimeValue) -> time:
@@ -164,7 +164,7 @@ def _parse_date_value(value: DateValue) -> tuple[list[date] | None, bool]:
164
164
  "0 - 2 date/datetime values"
165
165
  )
166
166
 
167
- parsed_dates = [_convert_datelike_to_date(v) for v in value_tuple]
167
+ parsed_dates = [_convert_datelike_to_date(v) for v in value_tuple] # ty: ignore[invalid-argument-type]
168
168
 
169
169
  return parsed_dates, is_range
170
170
 
@@ -207,6 +207,171 @@ def _parse_max_date(
207
207
  return parsed_max_date
208
208
 
209
209
 
210
+ def _normalize_time(value: time) -> time:
211
+ """Return a time without seconds, microseconds, or timezone info."""
212
+ return value.replace(second=0, microsecond=0, tzinfo=None)
213
+
214
+
215
+ def _normalize_datetime_value(value: datetime) -> datetime:
216
+ """Return a datetime without seconds, microseconds, or timezone info."""
217
+ if value.tzinfo is not None:
218
+ value = value.replace(tzinfo=None)
219
+ return value.replace(second=0, microsecond=0)
220
+
221
+
222
+ def _combine_date_time(component_date: date, component_time: time) -> datetime:
223
+ """Combine a date and time into a normalized datetime."""
224
+ return datetime.combine(component_date, _normalize_time(component_time))
225
+
226
+
227
+ def _try_parse_datetime_with_format(value: str, fmt: str) -> datetime | None:
228
+ """Try to parse a datetime string with a specific format."""
229
+ try:
230
+ return datetime.strptime(value, fmt)
231
+ except ValueError:
232
+ return None
233
+
234
+
235
+ def _convert_datetimelike_to_datetime(
236
+ value: DateTimeScalarValue,
237
+ *,
238
+ fallback_date: date,
239
+ fallback_time: time,
240
+ ) -> datetime:
241
+ """Convert supported datetime inputs into a normalized datetime."""
242
+ fallback_time = _normalize_time(fallback_time)
243
+
244
+ if value == "now":
245
+ return _normalize_datetime_value(datetime.now())
246
+
247
+ if isinstance(value, datetime):
248
+ return _normalize_datetime_value(value)
249
+
250
+ if isinstance(value, date) and not isinstance(value, datetime):
251
+ return _combine_date_time(value, fallback_time)
252
+
253
+ if isinstance(value, time):
254
+ return _combine_date_time(fallback_date, value)
255
+
256
+ if isinstance(value, str):
257
+ stripped_value = value.strip()
258
+
259
+ try:
260
+ parsed_dt = datetime.fromisoformat(stripped_value)
261
+ return _normalize_datetime_value(parsed_dt)
262
+ except ValueError:
263
+ pass
264
+
265
+ for fmt in (
266
+ "%Y/%m/%d %H:%M",
267
+ "%Y/%m/%d %H:%M:%S",
268
+ "%Y-%m-%d %H:%M",
269
+ "%Y-%m-%d %H:%M:%S",
270
+ ):
271
+ maybe_parsed_dt = _try_parse_datetime_with_format(stripped_value, fmt)
272
+ if maybe_parsed_dt is not None:
273
+ return _normalize_datetime_value(maybe_parsed_dt)
274
+
275
+ try:
276
+ parsed_date = date.fromisoformat(stripped_value)
277
+ return _combine_date_time(parsed_date, fallback_time)
278
+ except ValueError:
279
+ pass
280
+
281
+ try:
282
+ parsed_time = time.fromisoformat(stripped_value)
283
+ return _combine_date_time(fallback_date, parsed_time)
284
+ except ValueError:
285
+ pass
286
+
287
+ raise StreamlitAPIException(
288
+ "The type of value should be one of datetime, date, time, ISO string, or 'now'."
289
+ )
290
+
291
+
292
+ def _default_min_datetime(base_date: date) -> datetime:
293
+ return _combine_date_time(
294
+ adjust_years(base_date, years=-10), _DEFAULT_MIN_BOUND_TIME
295
+ )
296
+
297
+
298
+ def _default_max_datetime(base_date: date) -> datetime:
299
+ return _combine_date_time(
300
+ adjust_years(base_date, years=10), _DEFAULT_MAX_BOUND_TIME
301
+ )
302
+
303
+
304
+ def _datetime_to_proto_string(value: datetime) -> str:
305
+ return _normalize_datetime_value(value).strftime(_DATETIME_UI_FORMAT)
306
+
307
+
308
+ @dataclass(frozen=True)
309
+ class _DateTimeInputValues:
310
+ value: datetime | None
311
+ min: datetime
312
+ max: datetime
313
+
314
+ @classmethod
315
+ def from_raw_values(
316
+ cls,
317
+ value: DateTimeValue,
318
+ min_value: DateTimeValue,
319
+ max_value: DateTimeValue,
320
+ ) -> _DateTimeInputValues:
321
+ parsed_value = (
322
+ None
323
+ if value is None
324
+ else _convert_datetimelike_to_datetime(
325
+ value,
326
+ fallback_date=date.today(),
327
+ fallback_time=_DEFAULT_MIN_BOUND_TIME,
328
+ )
329
+ )
330
+
331
+ base_date_for_bounds = (
332
+ parsed_value.date() if parsed_value is not None else date.today()
333
+ )
334
+
335
+ parsed_min = (
336
+ _default_min_datetime(base_date_for_bounds)
337
+ if min_value is None
338
+ else _convert_datetimelike_to_datetime(
339
+ min_value,
340
+ fallback_date=base_date_for_bounds,
341
+ fallback_time=_DEFAULT_MIN_BOUND_TIME,
342
+ )
343
+ )
344
+
345
+ parsed_max = (
346
+ _default_max_datetime(base_date_for_bounds)
347
+ if max_value is None
348
+ else _convert_datetimelike_to_datetime(
349
+ max_value,
350
+ fallback_date=base_date_for_bounds,
351
+ fallback_time=_DEFAULT_MAX_BOUND_TIME,
352
+ )
353
+ )
354
+
355
+ return cls(
356
+ value=parsed_value,
357
+ min=parsed_min,
358
+ max=parsed_max,
359
+ )
360
+
361
+ def __post_init__(self) -> None:
362
+ if self.min > self.max:
363
+ raise StreamlitAPIException(
364
+ f"The `min_value`, set to {self.min}, shouldn't be larger "
365
+ f"than the `max_value`, set to {self.max}."
366
+ )
367
+
368
+ if self.value is not None and (self.value < self.min or self.value > self.max):
369
+ raise StreamlitAPIException(
370
+ f"The default `value` of {self.value} must lie between the `min_value` "
371
+ f"of {self.min} and the `max_value` of {self.max}, inclusively."
372
+ )
373
+
374
+
210
375
  @dataclass(frozen=True)
211
376
  class _DateInputValues:
212
377
  value: Sequence[date] | None
@@ -264,6 +429,30 @@ class _DateInputValues:
264
429
  )
265
430
 
266
431
 
432
+ @dataclass
433
+ class DateTimeInputSerde:
434
+ value: datetime | None
435
+ min: datetime
436
+ max: datetime
437
+
438
+ def deserialize(self, ui_value: list[str] | None) -> datetime | None:
439
+ if ui_value is not None and len(ui_value) > 0:
440
+ deserialized = _normalize_datetime_value(
441
+ datetime.strptime(ui_value[0], _DATETIME_UI_FORMAT)
442
+ )
443
+ # Validate against min/max bounds
444
+ # If the value is out of bounds, return the previous valid value
445
+ if deserialized < self.min or deserialized > self.max:
446
+ return self.value
447
+ return deserialized
448
+ return self.value
449
+
450
+ def serialize(self, v: datetime | None) -> list[str]:
451
+ if v is None:
452
+ return []
453
+ return [_datetime_to_proto_string(v)]
454
+
455
+
267
456
  @dataclass
268
457
  class TimeInputSerde:
269
458
  value: time | None
@@ -397,9 +586,9 @@ class TimeWidgetsMixin:
397
586
  - ``"now"`` (default): The widget initializes with the current time.
398
587
  - A ``datetime.time`` or ``datetime.datetime`` object: The widget
399
588
  initializes with the given time, ignoring any date if included.
400
- - An ISO-formatted time ("hh:mm", "hh:mm:ss", or "hh:mm:ss.sss") or
401
- datetime ("YYYY-MM-DD hh:mm:ss") string: The widget initializes
402
- with the given time, ignoring any date if included.
589
+ - An ISO-formatted time (hh:mm[:ss.sss]) or datetime
590
+ (YYYY-MM-DD hh:mm[:ss]) string: The widget initializes with the
591
+ given time, ignoring any date if included.
403
592
  - ``None``: The widget initializes with no time and returns
404
593
  ``None`` until the user selects a time.
405
594
 
@@ -437,8 +626,9 @@ class TimeWidgetsMixin:
437
626
  If this is ``"collapsed"``, Streamlit displays no label or spacer.
438
627
 
439
628
  step : int or timedelta
440
- The stepping interval in seconds. Defaults to 900, i.e. 15 minutes.
441
- You can also pass a datetime.timedelta object.
629
+ The stepping interval in seconds. This defaults to ``900`` (15
630
+ minutes). You can also pass a ``datetime.timedelta`` object. The
631
+ value must be between 60 seconds and 23 hours.
442
632
 
443
633
  width : "stretch" or int
444
634
  The width of the time input widget. This can be one of the following:
@@ -458,6 +648,8 @@ class TimeWidgetsMixin:
458
648
 
459
649
  Example
460
650
  -------
651
+ **Example 1: Basic usage**
652
+
461
653
  >>> import datetime
462
654
  >>> import streamlit as st
463
655
  >>>
@@ -468,6 +660,8 @@ class TimeWidgetsMixin:
468
660
  https://doc-time-input.streamlit.app/
469
661
  height: 260px
470
662
 
663
+ **Example 2: Empty initial value**
664
+
471
665
  To initialize an empty time input, use ``None`` as the value:
472
666
 
473
667
  >>> import datetime
@@ -593,6 +787,372 @@ class TimeWidgetsMixin:
593
787
  self.dg._enqueue("time_input", time_input_proto, layout_config=layout_config)
594
788
  return widget_state.value
595
789
 
790
+ @overload
791
+ def datetime_input(
792
+ self,
793
+ label: str,
794
+ value: None,
795
+ min_value: DateTimeValue = None,
796
+ max_value: DateTimeValue = None,
797
+ *, # keyword-only arguments:
798
+ key: Key | None = None,
799
+ help: str | None = None,
800
+ on_change: WidgetCallback | None = None,
801
+ args: WidgetArgs | None = None,
802
+ kwargs: WidgetKwargs | None = None,
803
+ format: str = "YYYY/MM/DD",
804
+ step: int | timedelta = timedelta(minutes=DEFAULT_STEP_MINUTES),
805
+ disabled: bool = False,
806
+ label_visibility: LabelVisibility = "visible",
807
+ width: WidthWithoutContent = "stretch",
808
+ ) -> datetime | None: ...
809
+
810
+ @overload
811
+ def datetime_input(
812
+ self,
813
+ label: str,
814
+ value: DateTimeScalarValue = "now",
815
+ min_value: DateTimeValue = None,
816
+ max_value: DateTimeValue = None,
817
+ *, # keyword-only arguments:
818
+ key: Key | None = None,
819
+ help: str | None = None,
820
+ on_change: WidgetCallback | None = None,
821
+ args: WidgetArgs | None = None,
822
+ kwargs: WidgetKwargs | None = None,
823
+ format: str = "YYYY/MM/DD",
824
+ step: int | timedelta = timedelta(minutes=DEFAULT_STEP_MINUTES),
825
+ disabled: bool = False,
826
+ label_visibility: LabelVisibility = "visible",
827
+ width: WidthWithoutContent = "stretch",
828
+ ) -> datetime: ...
829
+
830
+ @gather_metrics("datetime_input")
831
+ def datetime_input(
832
+ self,
833
+ label: str,
834
+ value: DateTimeValue = "now",
835
+ min_value: DateTimeValue = None,
836
+ max_value: DateTimeValue = None,
837
+ *, # keyword-only arguments:
838
+ key: Key | None = None,
839
+ help: str | None = None,
840
+ on_change: WidgetCallback | None = None,
841
+ args: WidgetArgs | None = None,
842
+ kwargs: WidgetKwargs | None = None,
843
+ format: str = "YYYY/MM/DD",
844
+ step: int | timedelta = timedelta(minutes=DEFAULT_STEP_MINUTES),
845
+ disabled: bool = False,
846
+ label_visibility: LabelVisibility = "visible",
847
+ width: WidthWithoutContent = "stretch",
848
+ ) -> datetime | None:
849
+ r"""Display a date and time input widget.
850
+
851
+ Parameters
852
+ ----------
853
+ label : str
854
+ A short label explaining to the user what this datetime input is for.
855
+ The label can optionally contain GitHub-flavored Markdown of the
856
+ following types: Bold, Italics, Strikethroughs, Inline Code, Links,
857
+ and Images. Images display like icons, with a max height equal to
858
+ the font height.
859
+
860
+ Unsupported Markdown elements are unwrapped so only their children
861
+ (text contents) render. Display unsupported elements as literal
862
+ characters by backslash-escaping them. E.g.,
863
+ ``"1\. Not an ordered list"``.
864
+
865
+ See the ``body`` parameter of |st.markdown|_ for additional,
866
+ supported Markdown directives.
867
+
868
+ For accessibility reasons, you should never set an empty label, but
869
+ you can hide it with ``label_visibility`` if needed. In the future,
870
+ we may disallow empty labels by raising an exception.
871
+
872
+ .. |st.markdown| replace:: ``st.markdown``
873
+ .. _st.markdown: https://docs.streamlit.io/develop/api-reference/text/st.markdown
874
+
875
+ value : "now", datetime.datetime, datetime.date, datetime.time, str, or None
876
+ The value of this widget when it first renders. This can be one of
877
+ the following:
878
+
879
+ - ``"now"`` (default): The widget initializes with the current date and time.
880
+ - A ``datetime.datetime`` object: The widget initializes with the given
881
+ datetime, stripping any timezone information.
882
+ - A ``datetime.date`` object: The widget initializes with the given date
883
+ at 00:00.
884
+ - A ``datetime.time`` object: The widget initializes with today's date
885
+ and the provided time.
886
+ - An ISO-formatted datetime (YYYY-MM-DD hh:mm[:ss]) or date/time
887
+ string: The widget initializes with the parsed value.
888
+ - ``None``: The widget initializes with no value and returns ``None``
889
+ until the user selects a datetime.
890
+
891
+ min_value : "now", datetime.datetime, datetime.date, datetime.time, str, or None
892
+ The minimum selectable datetime. This can be any of the datetime
893
+ types accepted by ``value``.
894
+
895
+ If this is ``None`` (default), the minimum selectable datetime is
896
+ ten years before the initial value. If no initial value is set, the
897
+ minimum selectable datetime is ten years before today at 00:00.
898
+
899
+ max_value : "now", datetime.datetime, datetime.date, datetime.time, str, or None
900
+ The maximum selectable datetime. This can be any of the datetime
901
+ types accepted by ``value``.
902
+
903
+ If this is ``None`` (default), the maximum selectable datetime is
904
+ ten years after the initial value. If no initial value is set, the
905
+ maximum selectable datetime is ten years after today at 23:59.
906
+
907
+ key : str or int
908
+ An optional string or integer to use as the unique key for the widget.
909
+ If this is omitted, a key will be generated for the widget based on its
910
+ content. No two widgets may have the same key.
911
+
912
+ help : str or None
913
+ A tooltip that gets displayed next to the widget label. Streamlit
914
+ only displays the tooltip when ``label_visibility="visible"``. If
915
+ this is ``None`` (default), no tooltip is displayed.
916
+
917
+ The tooltip can optionally contain GitHub-flavored Markdown,
918
+ including the Markdown directives described in the ``body``
919
+ parameter of ``st.markdown``.
920
+
921
+ on_change : callable
922
+ An optional callback invoked when this datetime_input's value changes.
923
+
924
+ args : list or tuple
925
+ An optional list or tuple of args to pass to the callback.
926
+
927
+ kwargs : dict
928
+ An optional dict of kwargs to pass to the callback.
929
+
930
+ format : str
931
+ A format string controlling how the interface displays dates.
932
+ Supports ``"YYYY/MM/DD"`` (default), ``"DD/MM/YYYY"``, or ``"MM/DD/YYYY"``.
933
+ You may also use a period (.) or hyphen (-) as separators. This
934
+ doesn't affect the time format.
935
+
936
+ step : int or timedelta
937
+ The stepping interval in seconds. This defaults to ``900`` (15
938
+ minutes). You can also pass a ``datetime.timedelta`` object. The
939
+ value must be between 60 seconds and 23 hours.
940
+
941
+ disabled : bool
942
+ An optional boolean that disables the widget if set to ``True``.
943
+ The default is ``False``.
944
+
945
+ label_visibility : "visible", "hidden", or "collapsed"
946
+ The visibility of the label. The default is ``"visible"``. If this
947
+ is ``"hidden"``, Streamlit displays an empty spacer instead of the
948
+ label, which can help keep the widget aligned with other widgets.
949
+ If this is ``"collapsed"``, Streamlit displays no label or spacer.
950
+
951
+ width : "stretch" or int
952
+ The width of the widget. This can be one of the following:
953
+
954
+ - ``"stretch"`` (default): The width of the widget matches the width
955
+ of the parent container.
956
+ - An integer specifying the width in pixels: The widget has a fixed
957
+ width. If the specified width is greater than the width of the
958
+ parent container, the widget matches the container width.
959
+
960
+ Returns
961
+ -------
962
+ datetime.datetime or None
963
+ The current value of the datetime input widget (without timezone)
964
+ or ``None`` if no value has been selected.
965
+
966
+ Examples
967
+ --------
968
+ **Example 1: Basic usage**
969
+
970
+ >>> import datetime
971
+ >>> import streamlit as st
972
+ >>>
973
+ >>> event_time = st.datetime_input(
974
+ ... "Schedule your event",
975
+ ... datetime.datetime(2025, 11, 19, 16, 45),
976
+ ... )
977
+ >>> st.write("Event scheduled for", event_time)
978
+
979
+ .. output::
980
+ https://doc-datetime-input.streamlit.app/
981
+ height: 500px
982
+
983
+ **Example 2: Empty initial value**
984
+
985
+ To initialize an empty datetime input, use ``None`` as the value:
986
+
987
+ >>> import datetime
988
+ >>> import streamlit as st
989
+ >>>
990
+ >>> event_time = st.datetime_input("Schedule your event", value=None)
991
+ >>> st.write("Event scheduled for", event_time)
992
+
993
+ .. output::
994
+ https://doc-datetime-input-empty.streamlit.app/
995
+ height: 500px
996
+
997
+ """
998
+ ctx = get_script_run_ctx()
999
+ return self._datetime_input(
1000
+ label=label,
1001
+ value=value,
1002
+ min_value=min_value,
1003
+ max_value=max_value,
1004
+ key=key,
1005
+ help=help,
1006
+ on_change=on_change,
1007
+ args=args,
1008
+ kwargs=kwargs,
1009
+ format=format,
1010
+ step=step,
1011
+ disabled=disabled,
1012
+ label_visibility=label_visibility,
1013
+ width=width,
1014
+ ctx=ctx,
1015
+ )
1016
+
1017
+ def _datetime_input(
1018
+ self,
1019
+ label: str,
1020
+ value: DateTimeValue = "now",
1021
+ min_value: DateTimeValue = None,
1022
+ max_value: DateTimeValue = None,
1023
+ *, # keyword-only arguments:
1024
+ key: Key | None = None,
1025
+ help: str | None = None,
1026
+ on_change: WidgetCallback | None = None,
1027
+ args: WidgetArgs | None = None,
1028
+ kwargs: WidgetKwargs | None = None,
1029
+ format: str = "YYYY/MM/DD",
1030
+ step: int | timedelta = timedelta(minutes=DEFAULT_STEP_MINUTES),
1031
+ disabled: bool = False,
1032
+ label_visibility: LabelVisibility = "visible",
1033
+ width: WidthWithoutContent = "stretch",
1034
+ ctx: ScriptRunContext | None = None,
1035
+ ) -> datetime | None:
1036
+ key = to_key(key)
1037
+
1038
+ check_widget_policies(
1039
+ self.dg,
1040
+ key,
1041
+ on_change,
1042
+ default_value=value if value != "now" else None,
1043
+ )
1044
+ maybe_raise_label_warnings(label, label_visibility)
1045
+
1046
+ datetime_values = _DateTimeInputValues.from_raw_values(
1047
+ value=value,
1048
+ min_value=min_value,
1049
+ max_value=max_value,
1050
+ )
1051
+
1052
+ default_value = datetime_values.value
1053
+ min_value_proto = _datetime_to_proto_string(datetime_values.min)
1054
+ max_value_proto = _datetime_to_proto_string(datetime_values.max)
1055
+
1056
+ if isinstance(value, (datetime, date, time)):
1057
+ value_for_id: Any = (
1058
+ None
1059
+ if default_value is None
1060
+ else _datetime_to_proto_string(default_value)
1061
+ )
1062
+ else:
1063
+ value_for_id = value
1064
+
1065
+ element_id = compute_and_register_element_id(
1066
+ "date_time_input",
1067
+ user_key=key,
1068
+ # Ensure stable IDs when the key is provided; whitelist parameters that
1069
+ # affect the selectable range or formatting.
1070
+ key_as_main_identity={"min_value", "max_value", "format", "step"},
1071
+ dg=self.dg,
1072
+ label=label,
1073
+ value=value_for_id,
1074
+ min_value=min_value_proto,
1075
+ max_value=max_value_proto,
1076
+ help=help,
1077
+ format=format,
1078
+ step=step,
1079
+ width=width,
1080
+ )
1081
+ del value
1082
+
1083
+ if not bool(ALLOWED_DATE_FORMATS.match(format)):
1084
+ raise StreamlitAPIException(
1085
+ f"The provided format (`{format}`) is not valid. DateTimeInput format "
1086
+ "should be one of `YYYY/MM/DD`, `DD/MM/YYYY`, or `MM/DD/YYYY` "
1087
+ "and can also use a period (.) or hyphen (-) as separators."
1088
+ )
1089
+
1090
+ if not isinstance(step, (int, timedelta)):
1091
+ raise StreamlitAPIException(
1092
+ f"`step` can only be `int` or `timedelta` but {type(step)} is provided."
1093
+ )
1094
+ step_seconds = (
1095
+ int(step.total_seconds()) if isinstance(step, timedelta) else step
1096
+ )
1097
+ if step_seconds < 60 or step_seconds > timedelta(hours=23).seconds:
1098
+ raise StreamlitAPIException(
1099
+ f"`step` must be between 60 seconds and 23 hours but is currently set to {step_seconds} seconds."
1100
+ )
1101
+
1102
+ session_state = get_session_state().filtered_state
1103
+ default_value_for_proto = default_value
1104
+ if key is not None and key in session_state and session_state[key] is None:
1105
+ default_value_for_proto = None
1106
+
1107
+ date_time_input_proto = DateTimeInputProto()
1108
+ date_time_input_proto.id = element_id
1109
+ date_time_input_proto.label = label
1110
+ if default_value_for_proto is not None:
1111
+ date_time_input_proto.default[:] = [
1112
+ _datetime_to_proto_string(default_value_for_proto)
1113
+ ]
1114
+ date_time_input_proto.min = min_value_proto
1115
+ date_time_input_proto.max = max_value_proto
1116
+ date_time_input_proto.form_id = current_form_id(self.dg)
1117
+ date_time_input_proto.step = step_seconds
1118
+ date_time_input_proto.disabled = disabled
1119
+ date_time_input_proto.label_visibility.value = get_label_visibility_proto_value(
1120
+ label_visibility
1121
+ )
1122
+ date_time_input_proto.format = format
1123
+ date_time_input_proto.is_range = False
1124
+
1125
+ if help is not None:
1126
+ date_time_input_proto.help = dedent(help)
1127
+
1128
+ serde = DateTimeInputSerde(
1129
+ value=default_value_for_proto,
1130
+ min=datetime_values.min,
1131
+ max=datetime_values.max,
1132
+ )
1133
+ widget_state = register_widget(
1134
+ date_time_input_proto.id,
1135
+ on_change_handler=on_change,
1136
+ args=args,
1137
+ kwargs=kwargs,
1138
+ deserializer=serde.deserialize,
1139
+ serializer=serde.serialize,
1140
+ ctx=ctx,
1141
+ value_type="string_array_value",
1142
+ )
1143
+
1144
+ if widget_state.value_changed:
1145
+ date_time_input_proto.value[:] = serde.serialize(widget_state.value)
1146
+ date_time_input_proto.set_value = True
1147
+
1148
+ validate_width(width)
1149
+ layout_config = LayoutConfig(width=width)
1150
+
1151
+ self.dg._enqueue(
1152
+ "date_time_input", date_time_input_proto, layout_config=layout_config
1153
+ )
1154
+ return widget_state.value
1155
+
596
1156
  @overload
597
1157
  def date_input(
598
1158
  self,
@@ -707,8 +1267,8 @@ class TimeWidgetsMixin:
707
1267
  - ``"today"`` (default): The widget initializes with the current date.
708
1268
  - A ``datetime.date`` or ``datetime.datetime`` object: The widget
709
1269
  initializes with the given date, ignoring any time if included.
710
- - An ISO-formatted date ("YYYY-MM-DD") or datetime
711
- ("YYYY-MM-DD hh:mm:ss") string: The widget initializes with the
1270
+ - An ISO-formatted date (YYYY-MM-DD) or datetime
1271
+ (YYYY-MM-DD hh:mm:ss) string: The widget initializes with the
712
1272
  given date, ignoring any time if included.
713
1273
  - A list or tuple with up to two of the above: The widget will
714
1274
  initialize with the given date interval and return a tuple of the
@@ -763,7 +1323,7 @@ class TimeWidgetsMixin:
763
1323
 
764
1324
  format : str
765
1325
  A format string controlling how the interface should display dates.
766
- Supports "YYYY/MM/DD" (default), "DD/MM/YYYY", or "MM/DD/YYYY".
1326
+ Supports ``"YYYY/MM/DD"`` (default), ``"DD/MM/YYYY"``, or ``"MM/DD/YYYY"``.
767
1327
  You may also use a period (.) or hyphen (-) as separators.
768
1328
 
769
1329
  disabled : bool
@@ -794,6 +1354,8 @@ class TimeWidgetsMixin:
794
1354
 
795
1355
  Examples
796
1356
  --------
1357
+ **Example 1: Basic usage**
1358
+
797
1359
  >>> import datetime
798
1360
  >>> import streamlit as st
799
1361
  >>>
@@ -804,6 +1366,8 @@ class TimeWidgetsMixin:
804
1366
  https://doc-date-input.streamlit.app/
805
1367
  height: 380px
806
1368
 
1369
+ **Example 2: Date range**
1370
+
807
1371
  >>> import datetime
808
1372
  >>> import streamlit as st
809
1373
  >>>
@@ -825,6 +1389,8 @@ class TimeWidgetsMixin:
825
1389
  https://doc-date-input1.streamlit.app/
826
1390
  height: 380px
827
1391
 
1392
+ **Example 3: Empty initial value**
1393
+
828
1394
  To initialize an empty date input, use ``None`` as the value:
829
1395
 
830
1396
  >>> import datetime