streamlit 1.51.0__py3-none-any.whl → 1.52.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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.sMJdFExW.js} +1 -1
  170. streamlit/static/static/js/{FileDownload.esm.Ddx8VEYy.js → FileDownload.esm.CV-WYqBn.js} +1 -1
  171. streamlit/static/static/js/{FileHelper.90EtOmj9.js → FileHelper.5nCh9KDY.js} +3 -3
  172. streamlit/static/static/js/{FormClearHelper.BB1Km6eP.js → FormClearHelper.-9RbsnV0.js} +1 -1
  173. streamlit/static/static/js/IFrameUtil.DefezniK.js +1 -0
  174. streamlit/static/static/js/InputInstructions.2R3tBtW9.js +1 -0
  175. streamlit/static/static/js/Particles.DDHoXFxh.js +1 -0
  176. streamlit/static/static/js/{ProgressBar.DLY8H6nE.js → ProgressBar.BxmfHxKu.js} +2 -2
  177. streamlit/static/static/js/StreamlitSyntaxHighlighter.BFWV0oqR.js +20 -0
  178. streamlit/static/static/js/{Toolbar.D8nHCkuz.js → Toolbar.DMgU0Vgw.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.BXTqYbyG.js} +4 -4
  182. streamlit/static/static/js/{checkbox.Cpdd482O.js → checkbox.5xWaqPqm.js} +1 -1
  183. streamlit/static/static/js/{createSuper.CuQIogbW.js → createSuper.OIgV8wc-.js} +1 -1
  184. streamlit/static/static/js/data-grid-overlay-editor.B4RIu9cw.js +1 -0
  185. streamlit/static/static/js/{downloader.CN0K7xlu.js → downloader.DwCJck8O.js} +1 -1
  186. streamlit/static/static/js/embed.HKcgTiLB.js +195 -0
  187. streamlit/static/static/js/{es6.BJcsVXQ0.js → es6.4AP97RGk.js} +2 -2
  188. streamlit/static/static/js/{iframeResizer.contentWindow.XzUvQqcZ.js → iframeResizer.contentWindow.BZAsvL9q.js} +1 -1
  189. streamlit/static/static/js/index.-3selq_5.js +2 -0
  190. streamlit/static/static/js/index.1ylynMAS.js +7 -0
  191. streamlit/static/static/js/{index.CxIUUfab.js → index.6UunrySF.js} +53 -122
  192. streamlit/static/static/js/index.8HslT92O.js +14 -0
  193. streamlit/static/static/js/index.B0TPxAZ1.js +1 -0
  194. streamlit/static/static/js/index.B0yp3bM1.js +6 -0
  195. streamlit/static/static/js/index.BHWBaOWH.js +1 -0
  196. streamlit/static/static/js/index.BJas6XzW.js +1 -0
  197. streamlit/static/static/js/index.BKIlG7Ng.js +3 -0
  198. streamlit/static/static/js/index.BMU6zZRk.js +1 -0
  199. streamlit/static/static/js/index.BNMLO-0p.js +2 -0
  200. streamlit/static/static/js/index.BPmBNTel.js +1 -0
  201. streamlit/static/static/js/index.BVuohWM1.js +1 -0
  202. streamlit/static/static/js/index.B_AvdOKC.js +1 -0
  203. streamlit/static/static/js/index.BjQIH-3U.js +1 -0
  204. streamlit/static/static/js/index.BrqtKtSu.js +2 -0
  205. streamlit/static/static/js/index.Buc7XrOl.js +188 -0
  206. streamlit/static/static/js/index.CIC9pLsG.js +2 -0
  207. streamlit/static/static/js/index.CP2YZ73v.js +1 -0
  208. streamlit/static/static/js/index.CSbah0y4.js +27 -0
  209. streamlit/static/static/js/index.CbiYVMT1.js +1 -0
  210. streamlit/static/static/js/index.CbxllBj8.js +1 -0
  211. streamlit/static/static/js/index.Cd1D2eGF.js +263 -0
  212. streamlit/static/static/js/index.Ckcqwai8.js +2 -0
  213. streamlit/static/static/js/index.CqTPbV5Y.js +151 -0
  214. streamlit/static/static/js/index.CxXo5UKy.js +1 -0
  215. streamlit/static/static/js/index.CxbL5FgL.js +1 -0
  216. streamlit/static/static/js/index.D52dMvK5.js +1 -0
  217. streamlit/static/static/js/index.DBUdji-9.js +3 -0
  218. streamlit/static/static/js/index.DMU3coc2.js +1 -0
  219. streamlit/static/static/js/index.DN4sfQLP.js +1 -0
  220. streamlit/static/static/js/{index.DPUXkcQL.js → index.DRDE9rnx.js} +1 -1
  221. streamlit/static/static/js/{index.B_dWA3vd.js → index.DY9Ac89e.js} +2 -2
  222. streamlit/static/static/js/index.DYKCsDvl.js +1 -0
  223. streamlit/static/static/js/index.Da9gznCC.js +1 -0
  224. streamlit/static/static/js/index.DfIRibXG.js +1 -0
  225. streamlit/static/static/js/{index.D3GPA5k4.js → index.Dg5zbEp2.js} +9 -40
  226. streamlit/static/static/js/index.Di9I2cid.js +1 -0
  227. streamlit/static/static/js/index.DkpEv0uV.js +1 -0
  228. streamlit/static/static/js/index.DwJ9Vhsl.js +1 -0
  229. streamlit/static/static/js/index.L7erTnMm.js +1 -0
  230. streamlit/static/static/js/{index.DOFlg3dS.js → index.NaDyAN1s.js} +1 -1
  231. streamlit/static/static/js/index.RNTPpVde.js +1 -0
  232. streamlit/static/static/js/index.VFDFuf_7.js +1 -0
  233. streamlit/static/static/js/index.W-bl3NDo.js +1 -0
  234. streamlit/static/static/js/index.XYozEjwK.js +1 -0
  235. streamlit/static/static/js/index.oyLQ4pue.js +1 -0
  236. streamlit/static/static/js/index.q4fLUQtC.js +11 -0
  237. streamlit/static/static/js/index.q9puCQgK.js +2 -0
  238. streamlit/static/static/js/index.xZBTXGNC.js +1 -0
  239. streamlit/static/static/js/{input.D4MN_FzN.js → input.CcvrgErO.js} +2 -2
  240. streamlit/static/static/js/main.eVHOp4Th.js +13 -0
  241. streamlit/static/static/js/{memory.DrZjtdGT.js → memory.Ck_sLv5Y.js} +1 -1
  242. streamlit/static/static/js/moment.C3j7ZXd7.js +4 -0
  243. streamlit/static/static/js/number-overlay-editor.DgcLMWOy.js +9 -0
  244. streamlit/static/static/js/pandasStylerUtils.DqP0h70z.js +1 -0
  245. streamlit/static/static/js/{possibleConstructorReturn.exeeJQEP.js → possibleConstructorReturn.C_51n46K.js} +1 -1
  246. streamlit/static/static/js/{sandbox.ClO3IuUr.js → sandbox.Q-g3QIZJ.js} +1 -1
  247. streamlit/static/static/js/styled-components.e0V96rJw.js +1 -0
  248. streamlit/static/static/js/threshold.Q1mXg5rX.js +1 -0
  249. streamlit/static/static/js/throttle.D3b5WILl.js +1 -0
  250. streamlit/static/static/js/{timepicker.DAhu-vcF.js → timepicker.Bpn70xGc.js} +1 -1
  251. streamlit/static/static/js/timer.C2hYhUse.js +1 -0
  252. streamlit/static/static/js/{toConsumableArray.DNbljYEC.js → toConsumableArray.DIN_ys1J.js} +1 -1
  253. streamlit/static/static/js/uniqueId.B27POWT6.js +1 -0
  254. streamlit/static/static/js/urls.BwSlolu9.js +1 -0
  255. streamlit/static/static/js/{useBasicWidgetState.D6sOH6oI.js → useBasicWidgetState.DA3_qaXD.js} +1 -1
  256. streamlit/static/static/js/useIntlLocale.BSq6SANa.js +12 -0
  257. streamlit/static/static/js/{useTextInputAutoExpand.4u3_GcuN.js → useTextInputAutoExpand.ytEW5QmA.js} +1 -1
  258. streamlit/static/static/js/useUpdateUiValue.DOxWBNiI.js +1 -0
  259. streamlit/static/static/js/useWaveformController.BCmk6WLk.js +1 -0
  260. streamlit/static/static/js/value.B4vHRSi7.js +1 -0
  261. streamlit/static/static/js/withCalculatedWidth.ChdrMItN.js +1 -0
  262. streamlit/static/static/js/withFullScreenWrapper.7j_lzlaF.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.1.dist-info}/METADATA +9 -5
  270. {streamlit-1.51.0.dist-info → streamlit-1.52.1.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.1.data}/scripts/streamlit.cmd +0 -0
  312. {streamlit-1.51.0.dist-info → streamlit-1.52.1.dist-info}/WHEEL +0 -0
  313. {streamlit-1.51.0.dist-info → streamlit-1.52.1.dist-info}/entry_points.txt +0 -0
  314. {streamlit-1.51.0.dist-info → streamlit-1.52.1.dist-info}/top_level.txt +0 -0
@@ -47,6 +47,7 @@ from streamlit.elements.lib.utils import (
47
47
  )
48
48
  from streamlit.errors import StreamlitAPIException
49
49
  from streamlit.proto.DateInput_pb2 import DateInput as DateInputProto
50
+ from streamlit.proto.DateTimeInput_pb2 import DateTimeInput as DateTimeInputProto
50
51
  from streamlit.proto.TimeInput_pb2 import TimeInput as TimeInputProto
51
52
  from streamlit.runtime.metrics_util import gather_metrics
52
53
  from streamlit.runtime.scriptrunner import ScriptRunContext, get_script_run_ctx
@@ -64,6 +65,8 @@ if TYPE_CHECKING:
64
65
 
65
66
  # Type for things that point to a specific time (even if a default time, though not None).
66
67
  TimeValue: TypeAlias = time | datetime | str | Literal["now"]
68
+ DateTimeScalarValue: TypeAlias = datetime | date | time | str | Literal["now"]
69
+ DateTimeValue: TypeAlias = DateTimeScalarValue | None
67
70
 
68
71
  # Type for things that point to a specific date (even if a default date, including None).
69
72
  NullableScalarDateValue: TypeAlias = date | datetime | str | Literal["today"] | None
@@ -80,6 +83,9 @@ DEFAULT_STEP_MINUTES: Final = 15
80
83
  ALLOWED_DATE_FORMATS: Final = re.compile(
81
84
  r"^(YYYY[/.\-]MM[/.\-]DD|DD[/.\-]MM[/.\-]YYYY|MM[/.\-]DD[/.\-]YYYY)$"
82
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)
83
89
 
84
90
 
85
91
  def _convert_timelike_to_time(value: TimeValue) -> time:
@@ -158,7 +164,7 @@ def _parse_date_value(value: DateValue) -> tuple[list[date] | None, bool]:
158
164
  "0 - 2 date/datetime values"
159
165
  )
160
166
 
161
- 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]
162
168
 
163
169
  return parsed_dates, is_range
164
170
 
@@ -201,6 +207,171 @@ def _parse_max_date(
201
207
  return parsed_max_date
202
208
 
203
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
+
204
375
  @dataclass(frozen=True)
205
376
  class _DateInputValues:
206
377
  value: Sequence[date] | None
@@ -258,6 +429,30 @@ class _DateInputValues:
258
429
  )
259
430
 
260
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
+
261
456
  @dataclass
262
457
  class TimeInputSerde:
263
458
  value: time | None
@@ -391,9 +586,9 @@ class TimeWidgetsMixin:
391
586
  - ``"now"`` (default): The widget initializes with the current time.
392
587
  - A ``datetime.time`` or ``datetime.datetime`` object: The widget
393
588
  initializes with the given time, ignoring any date if included.
394
- - An ISO-formatted time ("hh:mm", "hh:mm:ss", or "hh:mm:ss.sss") or
395
- datetime ("YYYY-MM-DD hh:mm:ss") string: The widget initializes
396
- 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.
397
592
  - ``None``: The widget initializes with no time and returns
398
593
  ``None`` until the user selects a time.
399
594
 
@@ -431,8 +626,9 @@ class TimeWidgetsMixin:
431
626
  If this is ``"collapsed"``, Streamlit displays no label or spacer.
432
627
 
433
628
  step : int or timedelta
434
- The stepping interval in seconds. Defaults to 900, i.e. 15 minutes.
435
- 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.
436
632
 
437
633
  width : "stretch" or int
438
634
  The width of the time input widget. This can be one of the following:
@@ -452,6 +648,8 @@ class TimeWidgetsMixin:
452
648
 
453
649
  Example
454
650
  -------
651
+ **Example 1: Basic usage**
652
+
455
653
  >>> import datetime
456
654
  >>> import streamlit as st
457
655
  >>>
@@ -462,6 +660,8 @@ class TimeWidgetsMixin:
462
660
  https://doc-time-input.streamlit.app/
463
661
  height: 260px
464
662
 
663
+ **Example 2: Empty initial value**
664
+
465
665
  To initialize an empty time input, use ``None`` as the value:
466
666
 
467
667
  >>> import datetime
@@ -587,6 +787,372 @@ class TimeWidgetsMixin:
587
787
  self.dg._enqueue("time_input", time_input_proto, layout_config=layout_config)
588
788
  return widget_state.value
589
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
+
590
1156
  @overload
591
1157
  def date_input(
592
1158
  self,
@@ -701,8 +1267,8 @@ class TimeWidgetsMixin:
701
1267
  - ``"today"`` (default): The widget initializes with the current date.
702
1268
  - A ``datetime.date`` or ``datetime.datetime`` object: The widget
703
1269
  initializes with the given date, ignoring any time if included.
704
- - An ISO-formatted date ("YYYY-MM-DD") or datetime
705
- ("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
706
1272
  given date, ignoring any time if included.
707
1273
  - A list or tuple with up to two of the above: The widget will
708
1274
  initialize with the given date interval and return a tuple of the
@@ -757,7 +1323,7 @@ class TimeWidgetsMixin:
757
1323
 
758
1324
  format : str
759
1325
  A format string controlling how the interface should display dates.
760
- 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"``.
761
1327
  You may also use a period (.) or hyphen (-) as separators.
762
1328
 
763
1329
  disabled : bool
@@ -788,6 +1354,8 @@ class TimeWidgetsMixin:
788
1354
 
789
1355
  Examples
790
1356
  --------
1357
+ **Example 1: Basic usage**
1358
+
791
1359
  >>> import datetime
792
1360
  >>> import streamlit as st
793
1361
  >>>
@@ -798,6 +1366,8 @@ class TimeWidgetsMixin:
798
1366
  https://doc-date-input.streamlit.app/
799
1367
  height: 380px
800
1368
 
1369
+ **Example 2: Date range**
1370
+
801
1371
  >>> import datetime
802
1372
  >>> import streamlit as st
803
1373
  >>>
@@ -819,6 +1389,8 @@ class TimeWidgetsMixin:
819
1389
  https://doc-date-input1.streamlit.app/
820
1390
  height: 380px
821
1391
 
1392
+ **Example 3: Empty initial value**
1393
+
822
1394
  To initialize an empty date input, use ``None`` as the value:
823
1395
 
824
1396
  >>> import datetime