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.
- streamlit/__init__.py +5 -1
- streamlit/commands/execution_control.py +89 -14
- streamlit/commands/navigation.py +4 -6
- streamlit/commands/page_config.py +4 -6
- streamlit/components/v1/component_arrow.py +7 -7
- streamlit/components/v2/__init__.py +514 -0
- streamlit/components/v2/bidi_component/__init__.py +20 -0
- streamlit/components/v2/bidi_component/constants.py +29 -0
- streamlit/components/v2/bidi_component/main.py +534 -0
- streamlit/components/v2/bidi_component/serialization.py +272 -0
- streamlit/components/v2/bidi_component/state.py +92 -0
- streamlit/components/v2/component_definition_resolver.py +143 -0
- streamlit/components/v2/component_file_watcher.py +403 -0
- streamlit/components/v2/component_manager.py +439 -0
- streamlit/components/v2/component_manifest_handler.py +122 -0
- streamlit/components/v2/component_path_utils.py +245 -0
- streamlit/components/v2/component_registry.py +426 -0
- streamlit/components/v2/get_bidi_component_manager.py +51 -0
- streamlit/components/v2/manifest_scanner.py +615 -0
- streamlit/components/v2/presentation.py +198 -0
- streamlit/components/v2/types.py +324 -0
- streamlit/config.py +456 -53
- streamlit/config_option.py +4 -1
- streamlit/config_util.py +650 -1
- streamlit/connections/snowflake_connection.py +1 -1
- streamlit/connections/snowpark_connection.py +1 -1
- streamlit/dataframe_util.py +33 -26
- streamlit/delta_generator.py +13 -4
- streamlit/delta_generator_singletons.py +11 -15
- streamlit/deprecation_util.py +17 -6
- streamlit/elements/alert.py +16 -0
- streamlit/elements/arrow.py +68 -10
- streamlit/elements/bokeh_chart.py +10 -78
- streamlit/elements/code.py +2 -2
- streamlit/elements/deck_gl_json_chart.py +98 -40
- streamlit/elements/dialog_decorator.py +2 -1
- streamlit/elements/exception.py +4 -2
- streamlit/elements/form.py +27 -0
- streamlit/elements/graphviz_chart.py +1 -3
- streamlit/elements/heading.py +63 -10
- streamlit/elements/html.py +13 -2
- streamlit/elements/image.py +3 -5
- streamlit/elements/layouts.py +59 -33
- streamlit/elements/lib/built_in_chart_utils.py +50 -19
- streamlit/elements/lib/color_util.py +9 -19
- streamlit/elements/lib/column_config_utils.py +9 -12
- streamlit/elements/lib/column_types.py +40 -12
- streamlit/elements/lib/dialog.py +2 -2
- streamlit/elements/lib/image_utils.py +3 -5
- streamlit/elements/lib/layout_utils.py +100 -13
- streamlit/elements/lib/mutable_status_container.py +2 -2
- streamlit/elements/lib/options_selector_utils.py +2 -2
- streamlit/elements/lib/pandas_styler_utils.py +17 -9
- streamlit/elements/lib/shortcut_utils.py +152 -0
- streamlit/elements/lib/utils.py +4 -4
- streamlit/elements/map.py +80 -37
- streamlit/elements/markdown.py +50 -3
- streamlit/elements/media.py +5 -7
- streamlit/elements/metric.py +34 -6
- streamlit/elements/pdf.py +2 -4
- streamlit/elements/plotly_chart.py +197 -20
- streamlit/elements/progress.py +2 -4
- streamlit/elements/space.py +113 -0
- streamlit/elements/spinner.py +1 -1
- streamlit/elements/text.py +20 -3
- streamlit/elements/toast.py +2 -0
- streamlit/elements/vega_charts.py +356 -149
- streamlit/elements/widgets/audio_input.py +12 -11
- streamlit/elements/widgets/button.py +280 -43
- streamlit/elements/widgets/button_group.py +60 -9
- streamlit/elements/widgets/camera_input.py +3 -5
- streamlit/elements/widgets/chat.py +307 -43
- streamlit/elements/widgets/color_picker.py +8 -1
- streamlit/elements/widgets/data_editor.py +88 -44
- streamlit/elements/widgets/file_uploader.py +9 -11
- streamlit/elements/widgets/multiselect.py +4 -3
- streamlit/elements/widgets/number_input.py +4 -4
- streamlit/elements/widgets/radio.py +10 -3
- streamlit/elements/widgets/select_slider.py +8 -5
- streamlit/elements/widgets/selectbox.py +6 -3
- streamlit/elements/widgets/slider.py +38 -42
- streamlit/elements/widgets/text_widgets.py +2 -0
- streamlit/elements/widgets/time_widgets.py +587 -21
- streamlit/elements/write.py +27 -6
- streamlit/emojis.py +1 -1
- streamlit/errors.py +137 -0
- streamlit/git_util.py +1 -1
- streamlit/hello/hello.py +8 -0
- streamlit/hello/utils.py +2 -1
- streamlit/material_icon_names.py +1 -1
- streamlit/navigation/page.py +11 -1
- streamlit/net_util.py +2 -2
- streamlit/proto/Alert_pb2.pyi +3 -3
- streamlit/proto/AppPage_pb2.pyi +7 -1
- streamlit/proto/ArrowData_pb2.py +27 -0
- streamlit/proto/ArrowData_pb2.pyi +52 -0
- streamlit/proto/ArrowNamedDataSet_pb2.pyi +7 -1
- streamlit/proto/ArrowVegaLiteChart_pb2.pyi +7 -1
- streamlit/proto/Arrow_pb2.py +10 -10
- streamlit/proto/Arrow_pb2.pyi +19 -12
- streamlit/proto/AudioInput_pb2.pyi +7 -1
- streamlit/proto/Audio_pb2.pyi +7 -1
- streamlit/proto/AuthRedirect_pb2.pyi +7 -1
- streamlit/proto/AutoRerun_pb2.pyi +7 -1
- streamlit/proto/BackMsg_pb2.py +4 -2
- streamlit/proto/BackMsg_pb2.pyi +34 -4
- streamlit/proto/Balloons_pb2.pyi +7 -1
- streamlit/proto/BidiComponent_pb2.py +34 -0
- streamlit/proto/BidiComponent_pb2.pyi +159 -0
- streamlit/proto/Block_pb2.py +7 -7
- streamlit/proto/Block_pb2.pyi +39 -36
- streamlit/proto/BokehChart_pb2.pyi +7 -1
- streamlit/proto/ButtonGroup_pb2.pyi +9 -9
- streamlit/proto/Button_pb2.py +2 -2
- streamlit/proto/Button_pb2.pyi +11 -2
- streamlit/proto/CameraInput_pb2.pyi +7 -1
- streamlit/proto/ChatInput_pb2.py +6 -6
- streamlit/proto/ChatInput_pb2.pyi +18 -6
- streamlit/proto/Checkbox_pb2.pyi +3 -3
- streamlit/proto/ClientState_pb2.pyi +10 -4
- streamlit/proto/Code_pb2.pyi +7 -1
- streamlit/proto/ColorPicker_pb2.pyi +7 -1
- streamlit/proto/Common_pb2.py +3 -3
- streamlit/proto/Common_pb2.pyi +35 -23
- streamlit/proto/Components_pb2.pyi +19 -13
- streamlit/proto/DataFrame_pb2.pyi +55 -49
- streamlit/proto/DateInput_pb2.pyi +7 -1
- streamlit/proto/DateTimeInput_pb2.py +28 -0
- streamlit/proto/DateTimeInput_pb2.pyi +92 -0
- streamlit/proto/DeckGlJsonChart_pb2.py +10 -4
- streamlit/proto/DeckGlJsonChart_pb2.pyi +12 -6
- streamlit/proto/Delta_pb2.pyi +7 -1
- streamlit/proto/DocString_pb2.pyi +10 -4
- streamlit/proto/DownloadButton_pb2.py +2 -2
- streamlit/proto/DownloadButton_pb2.pyi +16 -2
- streamlit/proto/Element_pb2.py +7 -3
- streamlit/proto/Element_pb2.pyi +33 -5
- streamlit/proto/Empty_pb2.pyi +7 -1
- streamlit/proto/Exception_pb2.pyi +7 -1
- streamlit/proto/Favicon_pb2.pyi +7 -1
- streamlit/proto/FileUploader_pb2.pyi +7 -1
- streamlit/proto/ForwardMsg_pb2.py +12 -10
- streamlit/proto/ForwardMsg_pb2.pyi +42 -15
- streamlit/proto/GapSize_pb2.pyi +4 -4
- streamlit/proto/GitInfo_pb2.pyi +3 -3
- streamlit/proto/GraphVizChart_pb2.pyi +7 -1
- streamlit/proto/Heading_pb2.pyi +7 -1
- streamlit/proto/HeightConfig_pb2.py +2 -2
- streamlit/proto/HeightConfig_pb2.pyi +13 -4
- streamlit/proto/Html_pb2.py +2 -2
- streamlit/proto/Html_pb2.pyi +11 -2
- streamlit/proto/IFrame_pb2.pyi +7 -1
- streamlit/proto/Image_pb2.pyi +10 -4
- streamlit/proto/Json_pb2.pyi +7 -1
- streamlit/proto/LabelVisibilityMessage_pb2.pyi +3 -3
- streamlit/proto/LinkButton_pb2.py +2 -2
- streamlit/proto/LinkButton_pb2.pyi +15 -2
- streamlit/proto/Logo_pb2.pyi +7 -1
- streamlit/proto/Markdown_pb2.pyi +3 -3
- streamlit/proto/Metric_pb2.pyi +7 -7
- streamlit/proto/MetricsEvent_pb2.pyi +10 -4
- streamlit/proto/MultiSelect_pb2.pyi +7 -1
- streamlit/proto/NamedDataSet_pb2.pyi +7 -1
- streamlit/proto/Navigation_pb2.pyi +3 -3
- streamlit/proto/NewSession_pb2.py +18 -18
- streamlit/proto/NewSession_pb2.pyi +59 -40
- streamlit/proto/NumberInput_pb2.pyi +3 -3
- streamlit/proto/PageConfig_pb2.pyi +7 -7
- streamlit/proto/PageInfo_pb2.pyi +7 -1
- streamlit/proto/PageLink_pb2.py +2 -2
- streamlit/proto/PageLink_pb2.pyi +11 -2
- streamlit/proto/PageNotFound_pb2.pyi +7 -1
- streamlit/proto/PageProfile_pb2.pyi +13 -7
- streamlit/proto/PagesChanged_pb2.pyi +7 -1
- streamlit/proto/ParentMessage_pb2.pyi +7 -1
- streamlit/proto/PlotlyChart_pb2.py +8 -6
- streamlit/proto/PlotlyChart_pb2.pyi +9 -7
- streamlit/proto/Progress_pb2.pyi +7 -1
- streamlit/proto/Radio_pb2.pyi +7 -1
- streamlit/proto/RootContainer_pb2.pyi +1 -1
- streamlit/proto/Selectbox_pb2.pyi +7 -1
- streamlit/proto/SessionEvent_pb2.pyi +7 -1
- streamlit/proto/SessionStatus_pb2.pyi +7 -1
- streamlit/proto/Skeleton_pb2.pyi +3 -3
- streamlit/proto/Slider_pb2.pyi +5 -5
- streamlit/proto/Snow_pb2.pyi +7 -1
- streamlit/proto/Space_pb2.py +27 -0
- streamlit/proto/Space_pb2.pyi +48 -0
- streamlit/proto/Spinner_pb2.pyi +7 -1
- streamlit/proto/TextAlignmentConfig_pb2.py +29 -0
- streamlit/proto/TextAlignmentConfig_pb2.pyi +68 -0
- streamlit/proto/TextArea_pb2.pyi +7 -1
- streamlit/proto/TextInput_pb2.pyi +3 -3
- streamlit/proto/Text_pb2.pyi +7 -1
- streamlit/proto/TimeInput_pb2.pyi +7 -1
- streamlit/proto/Toast_pb2.pyi +7 -1
- streamlit/proto/VegaLiteChart_pb2.pyi +7 -1
- streamlit/proto/Video_pb2.pyi +6 -6
- streamlit/proto/WidgetStates_pb2.py +2 -2
- streamlit/proto/WidgetStates_pb2.pyi +23 -7
- streamlit/proto/WidthConfig_pb2.py +2 -2
- streamlit/proto/WidthConfig_pb2.pyi +13 -4
- streamlit/proto/openmetrics_data_model_pb2.pyi +52 -52
- streamlit/runtime/app_session.py +65 -2
- streamlit/runtime/caching/cache_data_api.py +5 -5
- streamlit/runtime/caching/cache_errors.py +4 -1
- streamlit/runtime/caching/cache_resource_api.py +5 -4
- streamlit/runtime/caching/cache_utils.py +3 -2
- streamlit/runtime/caching/cached_message_replay.py +3 -3
- streamlit/runtime/caching/hashing.py +4 -5
- streamlit/runtime/caching/legacy_cache_api.py +2 -1
- streamlit/runtime/connection_factory.py +1 -3
- streamlit/runtime/download_data_util.py +53 -0
- streamlit/runtime/forward_msg_queue.py +5 -1
- streamlit/runtime/fragment.py +2 -1
- streamlit/runtime/media_file_manager.py +178 -2
- streamlit/runtime/memory_media_file_storage.py +1 -1
- streamlit/runtime/metrics_util.py +91 -3
- streamlit/runtime/runtime.py +14 -0
- streamlit/runtime/scriptrunner/exec_code.py +2 -1
- streamlit/runtime/scriptrunner/script_runner.py +5 -3
- streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -6
- streamlit/runtime/secrets.py +2 -4
- streamlit/runtime/session_manager.py +3 -1
- streamlit/runtime/state/common.py +30 -5
- streamlit/runtime/state/presentation.py +85 -0
- streamlit/runtime/state/query_params.py +80 -29
- streamlit/runtime/state/safe_session_state.py +2 -2
- streamlit/runtime/state/session_state.py +221 -17
- streamlit/runtime/state/widgets.py +19 -3
- streamlit/runtime/websocket_session_manager.py +3 -1
- streamlit/source_util.py +2 -2
- streamlit/static/index.html +2 -2
- streamlit/static/manifest.json +557 -239
- streamlit/static/static/css/{index.CIiu7Ygf.css → index.BpABIXK9.css} +1 -1
- streamlit/static/static/css/index.DgR7E2CV.css +1 -0
- streamlit/static/static/js/{ErrorOutline.esm.DUpR0_Ka.js → ErrorOutline.esm.ZJDbmVTx.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.CN4j9-1w.js → FileDownload.esm.Dx0vI3vH.js} +1 -1
- streamlit/static/static/js/{FileHelper.CaIUKG91.js → FileHelper.B7Ero7qQ.js} +3 -3
- streamlit/static/static/js/{FormClearHelper.DTcdrasw.js → FormClearHelper.CG2XN1_g.js} +1 -1
- streamlit/static/static/js/IFrameUtil.DefezniK.js +1 -0
- streamlit/static/static/js/InputInstructions.Cj5-1zf6.js +1 -0
- streamlit/static/static/js/Particles.BfWfv0Aw.js +1 -0
- streamlit/static/static/js/{ProgressBar.DetlP5aY.js → ProgressBar.CGQ8OgfO.js} +2 -2
- streamlit/static/static/js/StreamlitSyntaxHighlighter.DTKLpwhl.js +20 -0
- streamlit/static/static/js/{Toolbar.C77ar7rq.js → Toolbar.B2qFUmd9.js} +1 -1
- streamlit/static/static/js/_arrayIncludes.B19Iyn2B.js +1 -0
- streamlit/static/static/js/_baseIndexOf.BTknn6Gb.js +1 -0
- streamlit/static/static/js/{base-input.BQft14La.js → base-input.o9tL8MDP.js} +4 -4
- streamlit/static/static/js/{checkbox.yZOfXCeX.js → checkbox.0BeV1IBL.js} +1 -1
- streamlit/static/static/js/{createSuper.Dh9w1cs8.js → createSuper.RBO59fEm.js} +1 -1
- streamlit/static/static/js/data-grid-overlay-editor.CiTkUy0t.js +1 -0
- streamlit/static/static/js/{downloader.MeHtkq8r.js → downloader.DwNZg3Mw.js} +1 -1
- streamlit/static/static/js/embed.XT9xNd3F.js +195 -0
- streamlit/static/static/js/{es6.VpBPGCnM.js → es6.x9KsYQg-.js} +2 -2
- streamlit/static/static/js/{iframeResizer.contentWindow.yMw_ARIL.js → iframeResizer.contentWindow.ZVXpMPi0.js} +1 -1
- streamlit/static/static/js/index.5VPOamri.js +1 -0
- streamlit/static/static/js/index.8HslT92O.js +14 -0
- streamlit/static/static/js/index.AnXMIBz3.js +7 -0
- streamlit/static/static/js/index.B0yp3bM1.js +6 -0
- streamlit/static/static/js/index.B1fRb5wF.js +1 -0
- streamlit/static/static/js/index.B527JZdO.js +3 -0
- streamlit/static/static/js/index.BHgV-yW4.js +1 -0
- streamlit/static/static/js/index.BQr-XwGV.js +1 -0
- streamlit/static/static/js/index.BTtmaLDB.js +1 -0
- streamlit/static/static/js/index.BWB_91TA.js +1 -0
- streamlit/static/static/js/index.BfEKaEmw.js +1 -0
- streamlit/static/static/js/index.BfXjTO8b.js +1 -0
- streamlit/static/static/js/index.Bjy4NRu9.js +3 -0
- streamlit/static/static/js/index.Bu5JWpT_.js +1 -0
- streamlit/static/static/js/index.BuCx76ZV.js +1 -0
- streamlit/static/static/js/index.BxjzhVUb.js +2 -0
- streamlit/static/static/js/index.By55VdPY.js +1 -0
- streamlit/static/static/js/index.CF5MxTbK.js +1 -0
- streamlit/static/static/js/index.CLmq_z9K.js +1 -0
- streamlit/static/static/js/index.CNH4rdSz.js +1 -0
- streamlit/static/static/js/{index.B0H9IXUJ.js → index.CTgm_-jO.js} +10 -41
- streamlit/static/static/js/index.C_rK-Swb.js +188 -0
- streamlit/static/static/js/index.CjozwSzS.js +1 -0
- streamlit/static/static/js/{index.CH1tqnSs.js → index.CkGVt6-G.js} +1 -1
- streamlit/static/static/js/index.CuvXOyER.js +2 -0
- streamlit/static/static/js/{index.FFOzOWzC.js → index.CyUHWoCC.js} +2 -2
- streamlit/static/static/js/index.CyroQtI4.js +2 -0
- streamlit/static/static/js/index.D6HmkoDm.js +263 -0
- streamlit/static/static/js/index.DAqCNvsO.js +1 -0
- streamlit/static/static/js/index.DB_w_CZQ.js +1 -0
- streamlit/static/static/js/index.DBalctjj.js +2 -0
- streamlit/static/static/js/index.DK0RFJUG.js +11 -0
- streamlit/static/static/js/index.DMxc2XFp.js +151 -0
- streamlit/static/static/js/index.DO5utP74.js +2 -0
- streamlit/static/static/js/index.DS7lf09n.js +1 -0
- streamlit/static/static/js/index.DWexTVLY.js +1 -0
- streamlit/static/static/js/index.DXxnU5ej.js +1 -0
- streamlit/static/static/js/index.DcU3uDvB.js +2 -0
- streamlit/static/static/js/index.DlltaH7J.js +1 -0
- streamlit/static/static/js/index.DpNTZz82.js +27 -0
- streamlit/static/static/js/index.Dr9HIhQw.js +1 -0
- streamlit/static/static/js/index.DsgAU5lc.js +1 -0
- streamlit/static/static/js/{index.64ejlaaT.js → index.KfXqjDYy.js} +1 -1
- streamlit/static/static/js/index.PaidgjCs.js +1 -0
- streamlit/static/static/js/index.RJZuWCGA.js +1 -0
- streamlit/static/static/js/{index.Ctn27_AE.js → index.hbeqcRTn.js} +53 -122
- streamlit/static/static/js/index.q5hIQwAY.js +1 -0
- streamlit/static/static/js/index.rORSX6IW.js +1 -0
- streamlit/static/static/js/index.uSX757_v.js +1 -0
- streamlit/static/static/js/index.x_QRaLMd.js +1 -0
- streamlit/static/static/js/{input.s6pjQ49A.js → input.D5oh9-aB.js} +2 -2
- streamlit/static/static/js/main.q9oGOg0H.js +13 -0
- streamlit/static/static/js/{memory.Cuvsdfrl.js → memory.5kCSFUJS.js} +1 -1
- streamlit/static/static/js/moment.C3j7ZXd7.js +4 -0
- streamlit/static/static/js/number-overlay-editor.Cn_LsK8N.js +9 -0
- streamlit/static/static/js/pandasStylerUtils.BqhXt51_.js +1 -0
- streamlit/static/static/js/{possibleConstructorReturn.CqidKeei.js → possibleConstructorReturn.DD9NK1Z8.js} +1 -1
- streamlit/static/static/js/record.B-tDciZb.js +1 -0
- streamlit/static/static/js/{sandbox.CCQREcJx.js → sandbox.DACSyz29.js} +1 -1
- streamlit/static/static/js/styled-components.C3R090At.js +1 -0
- streamlit/static/static/js/threshold.Q1mXg5rX.js +1 -0
- streamlit/static/static/js/throttle.B0GR3Iyz.js +1 -0
- streamlit/static/static/js/{timepicker.mkJF97Bb.js → timepicker.BdhzPxrv.js} +1 -1
- streamlit/static/static/js/timer.C2hYhUse.js +1 -0
- streamlit/static/static/js/{toConsumableArray.De7I7KVR.js → toConsumableArray.Db2pdqM2.js} +1 -1
- streamlit/static/static/js/uniqueId.CtqIr-Yh.js +1 -0
- streamlit/static/static/js/urls.BwSlolu9.js +1 -0
- streamlit/static/static/js/{useBasicWidgetState.CedkNjUW.js → useBasicWidgetState.Bfp6TnSw.js} +1 -1
- streamlit/static/static/js/useIntlLocale.hRV75Xgj.js +12 -0
- streamlit/static/static/js/{useTextInputAutoExpand.Ca7w8dVs.js → useTextInputAutoExpand.QepX7n8Y.js} +1 -1
- streamlit/static/static/js/useUpdateUiValue.DHx8TzX6.js +1 -0
- streamlit/static/static/js/useWaveformController.WxVzpzEX.js +1 -0
- streamlit/static/static/js/value.B4vHRSi7.js +1 -0
- streamlit/static/static/js/wavesurfer.esm.vI8Eid4k.js +73 -0
- streamlit/static/static/js/withCalculatedWidth.DcKeRSWJ.js +1 -0
- streamlit/static/static/js/withFullScreenWrapper.CrHddARq.js +1 -0
- streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
- streamlit/string_util.py +9 -4
- streamlit/testing/v1/app_test.py +17 -2
- streamlit/testing/v1/element_tree.py +85 -9
- streamlit/testing/v1/util.py +2 -2
- streamlit/type_util.py +3 -4
- streamlit/url_util.py +1 -3
- streamlit/user_info.py +1 -2
- streamlit/util.py +3 -1
- streamlit/watcher/event_based_path_watcher.py +23 -12
- streamlit/watcher/local_sources_watcher.py +11 -1
- streamlit/watcher/path_watcher.py +9 -6
- streamlit/watcher/polling_path_watcher.py +4 -1
- streamlit/watcher/util.py +2 -2
- streamlit/web/bootstrap.py +24 -0
- streamlit/web/cli.py +51 -22
- streamlit/web/server/bidi_component_request_handler.py +193 -0
- streamlit/web/server/component_file_utils.py +97 -0
- streamlit/web/server/component_request_handler.py +8 -21
- streamlit/web/server/oauth_authlib_routes.py +5 -2
- streamlit/web/server/oidc_mixin.py +3 -1
- streamlit/web/server/routes.py +2 -2
- streamlit/web/server/server.py +9 -0
- streamlit/web/server/server_util.py +3 -1
- streamlit/web/server/upload_file_request_handler.py +19 -1
- {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/METADATA +10 -7
- streamlit-1.52.0.dist-info/RECORD +620 -0
- streamlit/static/static/css/index.CHEnSPGk.css +0 -1
- streamlit/static/static/js/Hooks.BRba_Own.js +0 -1
- streamlit/static/static/js/InputInstructions.xnSDuYeQ.js +0 -1
- streamlit/static/static/js/Particles.CElH0XX2.js +0 -1
- streamlit/static/static/js/data-grid-overlay-editor.DcuHuCyW.js +0 -1
- streamlit/static/static/js/index.6xX1278W.js +0 -975
- streamlit/static/static/js/index.B-hiXRzw.js +0 -1
- streamlit/static/static/js/index.B4cAbHP6.js +0 -1
- streamlit/static/static/js/index.B4dUQfni.js +0 -1
- streamlit/static/static/js/index.BPQo7BKk.js +0 -1
- streamlit/static/static/js/index.Baqa90pe.js +0 -2
- streamlit/static/static/js/index.Bj9JgOEC.js +0 -1
- streamlit/static/static/js/index.BjCwMzj4.js +0 -3
- streamlit/static/static/js/index.Bm3VbPB5.js +0 -1
- streamlit/static/static/js/index.Bxz2yX3P.js +0 -1
- streamlit/static/static/js/index.BycLveZ4.js +0 -1
- streamlit/static/static/js/index.C9BdUqTi.js +0 -1
- streamlit/static/static/js/index.CFMf5_ez.js +0 -197
- streamlit/static/static/js/index.CGYqqs6j.js +0 -1
- streamlit/static/static/js/index.CMItVsFA.js +0 -1
- streamlit/static/static/js/index.CTBk8Vk2.js +0 -1
- streamlit/static/static/js/index.CiAQIz1H.js +0 -7
- streamlit/static/static/js/index.Cj7DSzVR.js +0 -73
- streamlit/static/static/js/index.Ck8rQ9OL.js +0 -1
- streamlit/static/static/js/index.ClELlchS.js +0 -1617
- streamlit/static/static/js/index.Cnpi3o3E.js +0 -1
- streamlit/static/static/js/index.D2QEXQq_.js +0 -1
- streamlit/static/static/js/index.DH71Ezyj.js +0 -1
- streamlit/static/static/js/index.DHh-U0dK.js +0 -3
- streamlit/static/static/js/index.DK7hD7_w.js +0 -1
- streamlit/static/static/js/index.DKv_lNO7.js +0 -2
- streamlit/static/static/js/index.DNLrMXgm.js +0 -12
- streamlit/static/static/js/index.DW0Grddz.js +0 -1
- streamlit/static/static/js/index.Dbe-Q3C-.js +0 -2
- streamlit/static/static/js/index.DcPNYEUo.js +0 -1
- streamlit/static/static/js/index.DuxqVQpd.js +0 -1
- streamlit/static/static/js/index.GRUzrudl.js +0 -1
- streamlit/static/static/js/number-overlay-editor.DdgVR5m3.js +0 -9
- streamlit/static/static/js/uniqueId.RI1LJdtz.js +0 -1
- streamlit/static/static/js/useUpdateUiValue.DeXelfRH.js +0 -1
- streamlit/static/static/js/withFullScreenWrapper.C3561XxJ.js +0 -1
- streamlit/static/static/media/MaterialSymbols-Rounded.DeCZgS-4.woff2 +0 -0
- streamlit-1.50.0.dist-info/RECORD +0 -557
- {streamlit-1.50.0.data → streamlit-1.52.0.data}/scripts/streamlit.cmd +0 -0
- {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/WHEEL +0 -0
- {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/entry_points.txt +0 -0
- {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/top_level.txt +0 -0
streamlit/testing/v1/app_test.py
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
509
|
-
DateValue: TypeAlias =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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":
|
streamlit/testing/v1/util.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
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,
|
|
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
|
|
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 =
|
|
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
|
|
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,
|
|
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
|
streamlit/web/bootstrap.py
CHANGED
|
@@ -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
|
|
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",
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
232
|
-
_download_remote(main_script_path,
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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:
|