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
@@ -18,7 +18,7 @@ import tempfile
18
18
  import textwrap
19
19
  import traceback
20
20
  from pathlib import Path
21
- from typing import TYPE_CHECKING, Any, Callable
21
+ from typing import TYPE_CHECKING, Any
22
22
  from unittest.mock import MagicMock
23
23
  from urllib import parse
24
24
 
@@ -48,6 +48,7 @@ from streamlit.testing.v1.element_tree import (
48
48
  Column,
49
49
  Dataframe,
50
50
  DateInput,
51
+ DateTimeInput,
51
52
  Divider,
52
53
  ElementList,
53
54
  ElementTree,
@@ -88,7 +89,7 @@ from streamlit.testing.v1.util import patch_config_options
88
89
  from streamlit.util import calc_md5
89
90
 
90
91
  if TYPE_CHECKING:
91
- from collections.abc import Iterator, Sequence
92
+ from collections.abc import Callable, Iterator, Sequence
92
93
 
93
94
  from streamlit.proto.WidgetStates_pb2 import WidgetStates
94
95
 
@@ -608,6 +609,20 @@ class AppTest:
608
609
  """
609
610
  return self._tree.date_input
610
611
 
612
+ @property
613
+ def datetime_input(self) -> WidgetList[DateTimeInput]:
614
+ """Sequence of all ``st.datetime_input`` widgets.
615
+
616
+ Returns
617
+ -------
618
+ WidgetList of DateTimeInput
619
+ Sequence of all ``st.datetime_input`` widgets. Individual widgets can
620
+ be accessed from a WidgetList by index (order on the page) or key.
621
+ For example, ``at.datetime_input[0]`` for the first widget or
622
+ ``at.datetime_input(key="my_key")`` for a widget with a given key.
623
+ """
624
+ return self._tree.datetime_input
625
+
611
626
  @property
612
627
  def divider(self) -> ElementList[Divider]:
613
628
  """Sequence of all ``st.divider`` elements.
@@ -19,21 +19,20 @@ from __future__ import annotations
19
19
 
20
20
  import textwrap
21
21
  from abc import ABC, abstractmethod
22
- from collections.abc import Iterator, Sequence
22
+ from collections.abc import Callable, Iterator, Sequence
23
23
  from dataclasses import dataclass, field, fields, is_dataclass
24
24
  from datetime import date, datetime, time, timedelta
25
25
  from typing import (
26
26
  TYPE_CHECKING,
27
27
  Any,
28
- Callable,
29
28
  Generic,
29
+ TypeAlias,
30
30
  TypeVar,
31
- Union,
32
31
  cast,
33
32
  overload,
34
33
  )
35
34
 
36
- from typing_extensions import Self, TypeAlias
35
+ from typing_extensions import Self
37
36
 
38
37
  from streamlit import dataframe_util, util
39
38
  from streamlit.elements.heading import HeadingProtoTag
@@ -41,6 +40,7 @@ from streamlit.elements.widgets.select_slider import SelectSliderSerde
41
40
  from streamlit.elements.widgets.slider import SliderSerde, SliderStep
42
41
  from streamlit.elements.widgets.time_widgets import (
43
42
  DateInputSerde,
43
+ DateTimeInputSerde,
44
44
  DateWidgetReturn,
45
45
  TimeInputSerde,
46
46
  _parse_date_value,
@@ -63,6 +63,7 @@ if TYPE_CHECKING:
63
63
  from streamlit.proto.Code_pb2 import Code as CodeProto
64
64
  from streamlit.proto.ColorPicker_pb2 import ColorPicker as ColorPickerProto
65
65
  from streamlit.proto.DateInput_pb2 import DateInput as DateInputProto
66
+ from streamlit.proto.DateTimeInput_pb2 import DateTimeInput as DateTimeInputProto
66
67
  from streamlit.proto.Element_pb2 import Element as ElementProto
67
68
  from streamlit.proto.Exception_pb2 import Exception as ExceptionProto
68
69
  from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
@@ -73,6 +74,7 @@ if TYPE_CHECKING:
73
74
  from streamlit.proto.NumberInput_pb2 import NumberInput as NumberInputProto
74
75
  from streamlit.proto.Radio_pb2 import Radio as RadioProto
75
76
  from streamlit.proto.Selectbox_pb2 import Selectbox as SelectboxProto
77
+ from streamlit.proto.Space_pb2 import Space as SpaceProto
76
78
  from streamlit.proto.Text_pb2 import Text as TextProto
77
79
  from streamlit.proto.TextArea_pb2 import TextArea as TextAreaProto
78
80
  from streamlit.proto.TextInput_pb2 import TextInput as TextInputProto
@@ -505,8 +507,8 @@ class Dataframe(Element):
505
507
  return dataframe_util.convert_arrow_bytes_to_pandas_df(self.proto.data)
506
508
 
507
509
 
508
- SingleDateValue: TypeAlias = Union[date, datetime]
509
- DateValue: TypeAlias = Union[SingleDateValue, Sequence[SingleDateValue], None]
510
+ SingleDateValue: TypeAlias = date | datetime
511
+ DateValue: TypeAlias = SingleDateValue | Sequence[SingleDateValue] | None
510
512
 
511
513
 
512
514
  @dataclass(repr=False)
@@ -670,6 +672,20 @@ class Latex(Markdown):
670
672
  self.type = "latex"
671
673
 
672
674
 
675
+ @dataclass(repr=False)
676
+ class Space(Element):
677
+ """A representation of st.space for testing."""
678
+
679
+ proto: SpaceProto = field(repr=False)
680
+
681
+ key: None = None
682
+
683
+ def __init__(self, proto: SpaceProto, root: ElementTree) -> None:
684
+ self.proto = proto
685
+ self.root = root
686
+ self.type = "space"
687
+
688
+
673
689
  @dataclass(repr=False)
674
690
  class Metric(Element):
675
691
  proto: MetricProto
@@ -861,7 +877,7 @@ class Multiselect(Widget, Generic[T]):
861
877
  return self
862
878
 
863
879
 
864
- Number = Union[int, float]
880
+ Number: TypeAlias = int | float
865
881
 
866
882
 
867
883
  @dataclass(repr=False)
@@ -1308,7 +1324,8 @@ class TextInput(Widget):
1308
1324
  return self.set_value(v)
1309
1325
 
1310
1326
 
1311
- TimeValue: TypeAlias = Union[time, datetime]
1327
+ TimeValue: TypeAlias = time | datetime
1328
+ DateTimeWidgetValue: TypeAlias = datetime
1312
1329
 
1313
1330
 
1314
1331
  @dataclass(repr=False)
@@ -1368,6 +1385,59 @@ class TimeInput(Widget):
1368
1385
  return self.set_value(dt.time())
1369
1386
 
1370
1387
 
1388
+ @dataclass(repr=False)
1389
+ class DateTimeInput(Widget):
1390
+ """A representation of ``st.datetime_input``."""
1391
+
1392
+ _value: DateTimeWidgetValue | None | InitialValue
1393
+ proto: DateTimeInputProto = field(repr=False)
1394
+ label: str
1395
+ format: str
1396
+ min: str
1397
+ max: str
1398
+ step: int
1399
+ help: str
1400
+ form_id: str
1401
+
1402
+ def __init__(self, proto: DateTimeInputProto, root: ElementTree) -> None:
1403
+ super().__init__(proto, root)
1404
+ self._value = InitialValue()
1405
+ self.type = "date_time_input"
1406
+
1407
+ def set_value(self, v: DateTimeWidgetValue | None) -> DateTimeInput:
1408
+ """Set the value of the widget."""
1409
+ self._value = v
1410
+ return self
1411
+
1412
+ @property
1413
+ def _widget_state(self) -> WidgetState:
1414
+ from datetime import datetime
1415
+
1416
+ datetime_ui_format = "%Y/%m/%d, %H:%M"
1417
+
1418
+ ws = WidgetState()
1419
+ ws.id = self.id
1420
+
1421
+ # Parse min and max values for validation
1422
+ min_dt = datetime.strptime(self.min, datetime_ui_format)
1423
+ max_dt = datetime.strptime(self.max, datetime_ui_format)
1424
+
1425
+ serde = DateTimeInputSerde(value=None, min=min_dt, max=max_dt)
1426
+ serialized_value = serde.serialize(self.value)
1427
+ if serialized_value is not None:
1428
+ ws.string_array_value.data[:] = serialized_value
1429
+ return ws
1430
+
1431
+ @property
1432
+ def value(self) -> datetime | None:
1433
+ """The current value of the widget. (datetime)""" # noqa: D400
1434
+ if not isinstance(self._value, InitialValue):
1435
+ return self._value
1436
+ state = self.root.session_state
1437
+ assert state
1438
+ return state[self.id] # type: ignore
1439
+
1440
+
1371
1441
  @dataclass(repr=False)
1372
1442
  class Toast(Element):
1373
1443
  proto: ToastProto = field(repr=False)
@@ -1518,6 +1588,10 @@ class Block:
1518
1588
  def date_input(self) -> WidgetList[DateInput]:
1519
1589
  return WidgetList(self.get("date_input")) # type: ignore
1520
1590
 
1591
+ @property
1592
+ def datetime_input(self) -> WidgetList[DateTimeInput]:
1593
+ return WidgetList(self.get("date_time_input")) # type: ignore
1594
+
1521
1595
  @property
1522
1596
  def divider(self) -> ElementList[Divider]:
1523
1597
  return ElementList(self.get("divider")) # type: ignore
@@ -1828,7 +1902,7 @@ class Tab(Block):
1828
1902
  self.label = proto.label
1829
1903
 
1830
1904
 
1831
- Node: TypeAlias = Union[Element, Block]
1905
+ Node: TypeAlias = Element | Block
1832
1906
 
1833
1907
 
1834
1908
  def get_widget_state(node: Node) -> WidgetState | None:
@@ -1972,6 +2046,8 @@ def parse_tree_from_messages(messages: list[ForwardMsg]) -> ElementTree:
1972
2046
  new_node = ColorPicker(elt.color_picker, root=root)
1973
2047
  elif ty == "date_input":
1974
2048
  new_node = DateInput(elt.date_input, root=root)
2049
+ elif ty == "date_time_input":
2050
+ new_node = DateTimeInput(elt.date_time_input, root=root)
1975
2051
  elif ty == "exception":
1976
2052
  new_node = Exception(elt.exception, root=root)
1977
2053
  elif ty == "heading":
@@ -15,12 +15,12 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from contextlib import contextmanager
18
- from typing import TYPE_CHECKING, Any, Callable
18
+ from typing import TYPE_CHECKING, Any
19
19
 
20
20
  from streamlit import config
21
21
 
22
22
  if TYPE_CHECKING:
23
- from collections.abc import Generator
23
+ from collections.abc import Callable, Generator
24
24
 
25
25
 
26
26
  @contextmanager
streamlit/type_util.py CHANGED
@@ -38,12 +38,11 @@ from typing import (
38
38
  Literal,
39
39
  NamedTuple,
40
40
  Protocol,
41
- Union,
41
+ TypeAlias,
42
+ TypeGuard,
42
43
  overload,
43
44
  )
44
45
 
45
- from typing_extensions import TypeAlias, TypeGuard
46
-
47
46
  from streamlit.errors import StreamlitAPIException
48
47
 
49
48
  if TYPE_CHECKING:
@@ -149,7 +148,7 @@ _BYTES_LIKE_TYPES: Final[tuple[type, ...]] = (
149
148
  bytearray,
150
149
  )
151
150
 
152
- BytesLike: TypeAlias = Union[bytes, bytearray]
151
+ BytesLike: TypeAlias = bytes | bytearray
153
152
 
154
153
 
155
154
  def is_bytes_like(obj: object) -> TypeGuard[BytesLike]:
streamlit/url_util.py CHANGED
@@ -15,11 +15,9 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import re
18
- from typing import Final, Literal
18
+ from typing import Final, Literal, TypeAlias
19
19
  from urllib.parse import urlparse
20
20
 
21
- from typing_extensions import TypeAlias
22
-
23
21
  UrlSchema: TypeAlias = Literal["http", "https", "mailto", "data"]
24
22
 
25
23
 
streamlit/user_info.py CHANGED
@@ -20,7 +20,6 @@ from typing import (
20
20
  Any,
21
21
  Final,
22
22
  NoReturn,
23
- Union,
24
23
  )
25
24
 
26
25
  from streamlit import config, logger, runtime
@@ -379,7 +378,7 @@ def _get_user_info() -> UserInfo:
379
378
  return context_user_info
380
379
 
381
380
 
382
- class UserInfoProxy(Mapping[str, Union[str, bool, None]]):
381
+ class UserInfoProxy(Mapping[str, str | bool | None]):
383
382
  """
384
383
  A read-only, dict-like object for accessing information about the current\
385
384
  user.
streamlit/util.py CHANGED
@@ -19,11 +19,13 @@ from __future__ import annotations
19
19
  import dataclasses
20
20
  import functools
21
21
  import hashlib
22
- from typing import TYPE_CHECKING, Any, Callable
22
+ from typing import TYPE_CHECKING, Any
23
23
 
24
24
  from streamlit.proto.RootContainer_pb2 import RootContainer
25
25
 
26
26
  if TYPE_CHECKING:
27
+ from collections.abc import Callable
28
+
27
29
  from streamlit.delta_generator import DeltaGenerator
28
30
 
29
31
 
@@ -39,7 +39,7 @@ from __future__ import annotations
39
39
 
40
40
  import os
41
41
  import threading
42
- from typing import TYPE_CHECKING, Callable, Final, cast
42
+ from typing import TYPE_CHECKING, Final, cast
43
43
 
44
44
  from blinker import ANY, Signal
45
45
  from typing_extensions import Self
@@ -52,6 +52,8 @@ from streamlit.util import repr_
52
52
  from streamlit.watcher import util
53
53
 
54
54
  if TYPE_CHECKING:
55
+ from collections.abc import Callable
56
+
55
57
  from watchdog.observers.api import ObservedWatch
56
58
 
57
59
  _LOGGER: Final = get_logger(__name__)
@@ -372,11 +374,9 @@ class _FolderEventHandler(events.FileSystemEventHandler):
372
374
  _LOGGER.debug("Don't care about event type %s", event.event_type)
373
375
  return
374
376
 
375
- # Watchdog 5.X is supported Python >=3.9, so watchdog 4.X is used for Python 3.8.
376
- # In Watchdog 5.X, the path can be bytes or str, but in Watchdog 4.X, the path is always str,
377
- # that's why we convert the path to str, but we need to ignore the unreachable code warning for Python 3.8.
378
- if isinstance(changed_path, bytes): # type: ignore[unreachable, unused-ignore]
379
- changed_path = changed_path.decode("utf-8") # type: ignore[unreachable, unused-ignore]
377
+ # Watchdog 5.X emits bytes paths on some platforms, so we normalize to str.
378
+ if isinstance(changed_path, bytes):
379
+ changed_path = changed_path.decode("utf-8")
380
380
 
381
381
  if changed_path.endswith("~"):
382
382
  # Files ending with ~ are typically backup files created by editors.
@@ -397,12 +397,23 @@ class _FolderEventHandler(events.FileSystemEventHandler):
397
397
  # directories themselves.
398
398
  if changed_path_info is None:
399
399
  for path, info in self._watched_paths.items():
400
- if (
401
- os.path.isdir(path)
402
- and os.path.commonpath([path, abs_changed_path]) == path
403
- ):
404
- changed_path_info = info
405
- break
400
+ if not os.path.isdir(path):
401
+ continue
402
+ try:
403
+ if os.path.commonpath([path, abs_changed_path]) == path:
404
+ changed_path_info = info
405
+ break
406
+ except ValueError as ex:
407
+ # On Windows, os.path.commonpath raises ValueError when paths
408
+ # are on different drives. In that case, the changed path
409
+ # cannot be inside the watched directory.
410
+ _LOGGER.debug(
411
+ "Ignoring changed path %s.\nWatched_paths: %s",
412
+ abs_changed_path,
413
+ self._watched_paths,
414
+ exc_info=ex,
415
+ )
416
+ continue
406
417
 
407
418
  # If we still haven't found a matching path, ignore this event
408
419
  if changed_path_info is None:
@@ -16,7 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  import os
18
18
  import sys
19
- from typing import TYPE_CHECKING, Any, Callable, Final, NamedTuple
19
+ from typing import TYPE_CHECKING, Any, Final, NamedTuple
20
20
 
21
21
  from streamlit import config, file_util
22
22
  from streamlit.logger import get_logger
@@ -28,6 +28,7 @@ from streamlit.watcher.path_watcher import (
28
28
  )
29
29
 
30
30
  if TYPE_CHECKING:
31
+ from collections.abc import Callable
31
32
  from types import ModuleType
32
33
 
33
34
  from streamlit.runtime.pages_manager import PagesManager
@@ -46,6 +47,15 @@ PathWatcher: PathWatcherType | None = None
46
47
 
47
48
 
48
49
  class LocalSourcesWatcher:
50
+ """Watch local Python sources and pages to trigger app reruns.
51
+
52
+ Purpose
53
+ -------
54
+ This watcher powers Streamlit's core developer workflow: save a Python file
55
+ and the app reruns. It tracks Python modules, the main script directory, and
56
+ configured watch folders to notify the runtime when a relevant file changes.
57
+ """
58
+
49
59
  def __init__(self, pages_manager: PagesManager) -> None:
50
60
  self._pages_manager = pages_manager
51
61
  self._main_script_path = os.path.realpath(self._pages_manager.main_script_path)
@@ -15,12 +15,15 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import os
18
- from typing import Callable, Union
18
+ from typing import TYPE_CHECKING, TypeAlias
19
19
 
20
20
  import streamlit.watcher
21
21
  from streamlit import cli_util, config, env_util
22
22
  from streamlit.watcher.polling_path_watcher import PollingPathWatcher
23
23
 
24
+ if TYPE_CHECKING:
25
+ from collections.abc import Callable
26
+
24
27
 
25
28
  # local_sources_watcher.py caches the return value of
26
29
  # get_default_path_watcher_class(), so it needs to differentiate between the
@@ -45,11 +48,11 @@ class NoOpPathWatcher:
45
48
  # EventBasedPathWatcher will be a stub and have no functional
46
49
  # implementation if its import failed (due to missing watchdog module),
47
50
  # so we can't reference it directly in this type.
48
- PathWatcherType = Union[
49
- type["streamlit.watcher.event_based_path_watcher.EventBasedPathWatcher"],
50
- type[PollingPathWatcher],
51
- type[NoOpPathWatcher],
52
- ]
51
+ PathWatcherType: TypeAlias = (
52
+ type["streamlit.watcher.event_based_path_watcher.EventBasedPathWatcher"]
53
+ | type[PollingPathWatcher]
54
+ | type[NoOpPathWatcher]
55
+ )
53
56
 
54
57
 
55
58
  def _is_watchdog_available() -> bool:
@@ -19,13 +19,16 @@ from __future__ import annotations
19
19
  import time
20
20
  from concurrent.futures import ThreadPoolExecutor
21
21
  from pathlib import Path
22
- from typing import Callable, Final
22
+ from typing import TYPE_CHECKING, Final
23
23
 
24
24
  from streamlit.errors import StreamlitMaxRetriesError
25
25
  from streamlit.logger import get_logger
26
26
  from streamlit.util import repr_
27
27
  from streamlit.watcher import util
28
28
 
29
+ if TYPE_CHECKING:
30
+ from collections.abc import Callable
31
+
29
32
  _LOGGER: Final = get_logger(__name__)
30
33
 
31
34
  _MAX_WORKERS: Final = 4
streamlit/watcher/util.py CHANGED
@@ -23,13 +23,13 @@ from __future__ import annotations
23
23
  import os
24
24
  import time
25
25
  from pathlib import Path
26
- from typing import TYPE_CHECKING, Callable, TypeVar
26
+ from typing import TYPE_CHECKING, TypeVar
27
27
 
28
28
  from streamlit.errors import StreamlitMaxRetriesError
29
29
  from streamlit.util import calc_md5
30
30
 
31
31
  if TYPE_CHECKING:
32
- from collections.abc import Generator
32
+ from collections.abc import Callable, Generator
33
33
 
34
34
  # How many times to try to grab the MD5 hash.
35
35
  _MAX_RETRIES = 5
@@ -58,6 +58,29 @@ def _fix_sys_path(main_script_path: str) -> None:
58
58
  sys.path.insert(0, os.path.dirname(main_script_path))
59
59
 
60
60
 
61
+ def _maybe_install_uvloop(running_in_event_loop: bool) -> None:
62
+ """Install uvloop as the default event loop policy if available."""
63
+
64
+ if running_in_event_loop:
65
+ return
66
+
67
+ if env_util.IS_WINDOWS:
68
+ return
69
+
70
+ try:
71
+ import uvloop
72
+ except ModuleNotFoundError:
73
+ return
74
+
75
+ try:
76
+ uvloop.install()
77
+ _LOGGER.debug("uvloop installed as default event loop policy.")
78
+ except Exception:
79
+ _LOGGER.warning(
80
+ "Failed to install uvloop. Falling back to default loop.", exc_info=True
81
+ )
82
+
83
+
61
84
  def _fix_tornado_crash() -> None:
62
85
  """Set default asyncio policy to be compatible with Tornado 6.
63
86
 
@@ -326,6 +349,7 @@ def run(
326
349
  # This prevents the task from being garbage collected
327
350
  server._bootstrap_task = task
328
351
  else:
352
+ _maybe_install_uvloop(running_in_event_loop)
329
353
  # No running event loop, so we can use asyncio.run
330
354
  # This is the normal case when running streamlit from the command line
331
355
  _LOGGER.debug("Starting new event loop for server")
streamlit/web/cli.py CHANGED
@@ -18,7 +18,9 @@ from __future__ import annotations
18
18
 
19
19
  import os
20
20
  import sys
21
- from typing import TYPE_CHECKING, Any, Callable, Final, TypeVar
21
+ from collections.abc import Callable
22
+ from pathlib import Path
23
+ from typing import TYPE_CHECKING, Any, Final, TypeVar
22
24
 
23
25
  # We cannot lazy-load click here because its used via decorators.
24
26
  import click
@@ -195,46 +197,73 @@ def main_hello(**kwargs: Any) -> None:
195
197
 
196
198
  @main.command("run")
197
199
  @configurator_options
198
- @click.argument("target", required=True, envvar="STREAMLIT_RUN_TARGET")
200
+ @click.argument("target", default="streamlit_app.py", envvar="STREAMLIT_RUN_TARGET")
199
201
  @click.argument("args", nargs=-1)
200
202
  def main_run(target: str, args: list[str] | None = None, **kwargs: Any) -> None:
201
203
  """Run a Python script, piping stderr to Streamlit.
202
204
 
203
- The script can be local or it can be an url. In the latter case, Streamlit
204
- will download the script to a temporary file and runs this file.
205
+ If omitted, the target script will be assumed to be "streamlit_app.py".
205
206
 
207
+ Otherwise, the target script should be one of the following:
208
+ - The path to a local Python file.
209
+ - The path to a local folder where "streamlit_app.py" can be found.
210
+ - A URL pointing to a Python file. In this case Streamlit will download the
211
+ file to a temporary file and run it.
212
+
213
+ To pass command-line arguments to the script, add " -- " before them. For example:
214
+
215
+ $ streamlit run my_app.py -- --my_arg1=123 my_arg2
216
+
217
+ Your CLI args start after this.
206
218
  """
207
219
  from streamlit import url_util
208
220
 
209
- _, extension = os.path.splitext(target)
210
- if extension[1:] not in ACCEPTED_FILE_EXTENSIONS:
211
- if extension[1:] == "":
212
- raise click.BadArgumentUsage(
213
- "Streamlit requires raw Python (.py) files, but the provided file has no extension.\n"
214
- "For more information, please see https://docs.streamlit.io"
215
- )
216
- raise click.BadArgumentUsage(
217
- f"Streamlit requires raw Python (.py) files, not {extension}.\nFor more information, please see https://docs.streamlit.io"
218
- )
219
-
220
221
  if url_util.is_url(target):
221
222
  from streamlit.temporary_directory import TemporaryDirectory
222
223
 
223
224
  with TemporaryDirectory() as temp_dir:
224
225
  from urllib.parse import urlparse
225
226
 
226
- path = urlparse(target).path
227
+ url_subpath = urlparse(target).path
228
+
229
+ _check_extension_or_raise(url_subpath)
230
+
227
231
  main_script_path = os.path.join(
228
- temp_dir, path.strip("/").rsplit("/", 1)[-1]
232
+ temp_dir, url_subpath.strip("/").rsplit("/", 1)[-1]
229
233
  )
230
234
  # if this is a GitHub/Gist blob url, convert to a raw URL first.
231
- target = url_util.process_gitblob_url(target)
232
- _download_remote(main_script_path, target)
235
+ url = url_util.process_gitblob_url(target)
236
+ _download_remote(main_script_path, url)
233
237
  _main_run(main_script_path, args, flag_options=kwargs)
238
+
234
239
  else:
235
- if not os.path.exists(target):
236
- raise click.BadParameter(f"File does not exist: {target}")
237
- _main_run(target, args, flag_options=kwargs)
240
+ path = Path(target)
241
+
242
+ if path.is_dir():
243
+ path /= "streamlit_app.py"
244
+
245
+ path_str = str(path)
246
+ _check_extension_or_raise(path_str)
247
+
248
+ if not path.exists():
249
+ raise click.BadParameter(f"File does not exist: {path}")
250
+
251
+ _main_run(path_str, args, flag_options=kwargs)
252
+
253
+
254
+ def _check_extension_or_raise(path_str: str) -> None:
255
+ _, extension = os.path.splitext(path_str)
256
+
257
+ if extension[1:] not in ACCEPTED_FILE_EXTENSIONS:
258
+ if extension[1:] == "":
259
+ raise click.BadArgumentUsage(
260
+ "Streamlit requires raw Python (.py) files, but the provided file has no extension.\n"
261
+ "For more information, please see https://docs.streamlit.io"
262
+ )
263
+ raise click.BadArgumentUsage(
264
+ f"Streamlit requires raw Python (.py) files, not {extension}.\n"
265
+ "For more information, please see https://docs.streamlit.io"
266
+ )
238
267
 
239
268
 
240
269
  def _get_command_line_as_string() -> str | None: