streamlit 1.45.1__py3-none-any.whl → 1.46.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.
- streamlit/__init__.py +5 -1
- streamlit/auth_util.py +12 -12
- streamlit/cli_util.py +4 -3
- streamlit/column_config.py +11 -9
- streamlit/commands/echo.py +6 -4
- streamlit/commands/execution_control.py +33 -32
- streamlit/commands/experimental_query_params.py +2 -2
- streamlit/commands/logo.py +9 -4
- streamlit/commands/navigation.py +61 -18
- streamlit/commands/page_config.py +57 -47
- streamlit/components/types/base_custom_component.py +7 -7
- streamlit/components/v1/component_registry.py +7 -3
- streamlit/components/v1/components.py +1 -1
- streamlit/components/v1/custom_component.py +8 -8
- streamlit/config.py +289 -144
- streamlit/config_option.py +19 -15
- streamlit/config_util.py +29 -23
- streamlit/connections/__init__.py +2 -2
- streamlit/connections/base_connection.py +5 -5
- streamlit/connections/snowflake_connection.py +13 -11
- streamlit/connections/snowpark_connection.py +3 -3
- streamlit/connections/sql_connection.py +20 -18
- streamlit/connections/util.py +2 -2
- streamlit/cursor.py +6 -6
- streamlit/dataframe_util.py +52 -52
- streamlit/delta_generator.py +46 -48
- streamlit/delta_generator_singletons.py +3 -3
- streamlit/deprecation_util.py +6 -6
- streamlit/elements/alert.py +37 -29
- streamlit/elements/arrow.py +40 -22
- streamlit/elements/code.py +46 -13
- streamlit/elements/deck_gl_json_chart.py +38 -27
- streamlit/elements/dialog_decorator.py +3 -4
- streamlit/elements/doc_string.py +64 -58
- streamlit/elements/exception.py +23 -27
- streamlit/elements/form.py +41 -0
- streamlit/elements/graphviz_chart.py +1 -1
- streamlit/elements/heading.py +60 -9
- streamlit/elements/html.py +3 -4
- streamlit/elements/image.py +8 -9
- streamlit/elements/json.py +21 -2
- streamlit/elements/layouts.py +120 -31
- streamlit/elements/lib/built_in_chart_utils.py +96 -73
- streamlit/elements/lib/color_util.py +3 -3
- streamlit/elements/lib/column_config_utils.py +2 -4
- streamlit/elements/lib/column_types.py +14 -8
- streamlit/elements/lib/dialog.py +9 -5
- streamlit/elements/lib/image_utils.py +39 -40
- streamlit/elements/lib/js_number.py +4 -4
- streamlit/elements/lib/layout_utils.py +65 -1
- streamlit/elements/lib/mutable_status_container.py +14 -3
- streamlit/elements/lib/options_selector_utils.py +22 -12
- streamlit/elements/lib/pandas_styler_utils.py +25 -21
- streamlit/elements/lib/policies.py +6 -5
- streamlit/elements/lib/streamlit_plotly_theme.py +54 -53
- streamlit/elements/lib/subtitle_utils.py +6 -9
- streamlit/elements/lib/utils.py +20 -5
- streamlit/elements/map.py +32 -56
- streamlit/elements/markdown.py +101 -12
- streamlit/elements/media.py +78 -21
- streamlit/elements/metric.py +32 -16
- streamlit/elements/plotly_chart.py +15 -15
- streamlit/elements/progress.py +33 -15
- streamlit/elements/spinner.py +31 -6
- streamlit/elements/text.py +21 -1
- streamlit/elements/toast.py +1 -2
- streamlit/elements/vega_charts.py +54 -23
- streamlit/elements/widgets/audio_input.py +24 -7
- streamlit/elements/widgets/button.py +26 -19
- streamlit/elements/widgets/button_group.py +10 -15
- streamlit/elements/widgets/camera_input.py +27 -7
- streamlit/elements/widgets/chat.py +91 -38
- streamlit/elements/widgets/checkbox.py +45 -4
- streamlit/elements/widgets/color_picker.py +40 -17
- streamlit/elements/widgets/data_editor.py +76 -37
- streamlit/elements/widgets/file_uploader.py +42 -13
- streamlit/elements/widgets/multiselect.py +7 -10
- streamlit/elements/widgets/number_input.py +123 -47
- streamlit/elements/widgets/radio.py +59 -13
- streamlit/elements/widgets/select_slider.py +35 -30
- streamlit/elements/widgets/selectbox.py +56 -9
- streamlit/elements/widgets/slider.py +190 -99
- streamlit/elements/widgets/text_widgets.py +54 -8
- streamlit/elements/widgets/time_widgets.py +53 -14
- streamlit/elements/write.py +5 -8
- streamlit/env_util.py +2 -7
- streamlit/error_util.py +16 -9
- streamlit/errors.py +69 -48
- streamlit/external/langchain/streamlit_callback_handler.py +10 -5
- streamlit/file_util.py +27 -10
- streamlit/git_util.py +29 -24
- streamlit/hello/animation_demo.py +9 -9
- streamlit/hello/dataframe_demo.py +5 -5
- streamlit/hello/hello.py +1 -0
- streamlit/hello/mapping_demo.py +7 -8
- streamlit/hello/plotting_demo.py +3 -3
- streamlit/hello/streamlit_app.py +28 -26
- streamlit/hello/utils.py +2 -1
- streamlit/logger.py +10 -11
- streamlit/navigation/page.py +11 -8
- streamlit/proto/Audio_pb2.py +4 -3
- streamlit/proto/Audio_pb2.pyi +8 -1
- streamlit/proto/Block_pb2.py +38 -29
- streamlit/proto/Block_pb2.pyi +72 -4
- streamlit/proto/ClientState_pb2.py +4 -4
- streamlit/proto/ClientState_pb2.pyi +7 -2
- streamlit/proto/Code_pb2.py +4 -2
- streamlit/proto/Code_pb2.pyi +1 -0
- streamlit/proto/DataFrame_pb2.pyi +1 -1
- streamlit/proto/DeckGlJsonChart_pb2.pyi +1 -1
- streamlit/proto/Element_pb2.py +5 -3
- streamlit/proto/Element_pb2.pyi +20 -3
- streamlit/proto/GapSize_pb2.py +29 -0
- streamlit/proto/GapSize_pb2.pyi +70 -0
- streamlit/proto/HeightConfig_pb2.py +27 -0
- streamlit/proto/HeightConfig_pb2.pyi +48 -0
- streamlit/proto/NamedDataSet_pb2.pyi +1 -1
- streamlit/proto/Navigation_pb2.py +3 -3
- streamlit/proto/Navigation_pb2.pyi +4 -0
- streamlit/proto/NewSession_pb2.py +18 -16
- streamlit/proto/NewSession_pb2.pyi +29 -3
- streamlit/proto/PageConfig_pb2.py +7 -7
- streamlit/proto/PageConfig_pb2.pyi +21 -1
- streamlit/proto/Video_pb2.py +8 -7
- streamlit/proto/Video_pb2.pyi +8 -1
- streamlit/proto/WidthConfig_pb2.py +2 -2
- streamlit/proto/WidthConfig_pb2.pyi +15 -1
- streamlit/runtime/__init__.py +1 -1
- streamlit/runtime/app_session.py +53 -40
- streamlit/runtime/caching/__init__.py +9 -9
- streamlit/runtime/caching/cache_data_api.py +36 -30
- streamlit/runtime/caching/cache_errors.py +4 -4
- streamlit/runtime/caching/cache_resource_api.py +8 -8
- streamlit/runtime/caching/cache_utils.py +15 -14
- streamlit/runtime/caching/cached_message_replay.py +14 -8
- streamlit/runtime/caching/hashing.py +91 -97
- streamlit/runtime/caching/legacy_cache_api.py +2 -2
- streamlit/runtime/caching/storage/cache_storage_protocol.py +1 -1
- streamlit/runtime/caching/storage/dummy_cache_storage.py +1 -1
- streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +12 -14
- streamlit/runtime/caching/storage/local_disk_cache_storage.py +6 -6
- streamlit/runtime/connection_factory.py +36 -36
- streamlit/runtime/context.py +58 -9
- streamlit/runtime/credentials.py +29 -40
- streamlit/runtime/forward_msg_queue.py +11 -11
- streamlit/runtime/fragment.py +7 -7
- streamlit/runtime/media_file_manager.py +3 -4
- streamlit/runtime/memory_media_file_storage.py +6 -5
- streamlit/runtime/memory_uploaded_file_manager.py +2 -2
- streamlit/runtime/metrics_util.py +11 -12
- streamlit/runtime/pages_manager.py +4 -6
- streamlit/runtime/runtime.py +8 -6
- streamlit/runtime/runtime_util.py +7 -6
- streamlit/runtime/scriptrunner/__init__.py +4 -4
- streamlit/runtime/scriptrunner/exec_code.py +12 -5
- streamlit/runtime/scriptrunner/magic.py +16 -12
- streamlit/runtime/scriptrunner/script_cache.py +1 -1
- streamlit/runtime/scriptrunner/script_runner.py +53 -29
- streamlit/runtime/scriptrunner_utils/exceptions.py +1 -1
- streamlit/runtime/scriptrunner_utils/script_requests.py +7 -4
- streamlit/runtime/scriptrunner_utils/script_run_context.py +10 -23
- streamlit/runtime/secrets.py +40 -35
- streamlit/runtime/session_manager.py +2 -1
- streamlit/runtime/state/__init__.py +5 -5
- streamlit/runtime/state/common.py +2 -2
- streamlit/runtime/state/query_params.py +13 -15
- streamlit/runtime/state/query_params_proxy.py +17 -13
- streamlit/runtime/state/safe_session_state.py +2 -2
- streamlit/runtime/state/session_state.py +52 -34
- streamlit/runtime/stats.py +2 -2
- streamlit/runtime/uploaded_file_manager.py +1 -1
- streamlit/runtime/websocket_session_manager.py +10 -6
- streamlit/source_util.py +8 -6
- streamlit/static/index.html +3 -17
- streamlit/static/manifest.json +1180 -0
- streamlit/static/static/css/{index.DqDwtg6_.css → index.CJVRHjQZ.css} +1 -1
- streamlit/static/static/js/{ErrorOutline.esm.DU9IrB3M.js → ErrorOutline.esm.DitPpe1Y.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.P9rKwKo8.js → FileDownload.esm.AI3watX9.js} +1 -1
- streamlit/static/static/js/{FileHelper.D7RMkx0e.js → FileHelper.kt7mhnu8.js} +5 -5
- streamlit/static/static/js/{FormClearHelper.B67tgll0.js → FormClearHelper.D1M9GM_c.js} +1 -1
- streamlit/static/static/js/{Hooks.ncTJktu9.js → Hooks.BGwHKeUc.js} +1 -1
- streamlit/static/static/js/{InputInstructions.D-Y8geDN.js → InputInstructions.DaZ89mzH.js} +1 -1
- streamlit/static/static/js/{ProgressBar.B-kexwwD.js → ProgressBar.C0zPMe-p.js} +2 -2
- streamlit/static/static/js/{RenderInPortalIfExists.BgaoZgep.js → RenderInPortalIfExists.Ox8gQvdz.js} +1 -1
- streamlit/static/static/js/Toolbar.KhlcEc0K.js +1 -0
- streamlit/static/static/js/UploadFileInfo.0DCkpDDf.js +6 -0
- streamlit/static/static/js/{base-input.BoAa1U94.js → base-input.BJ4qsfSq.js} +4 -4
- streamlit/static/static/js/{checkbox.Z6iSfe5F.js → checkbox.DSDh78Xz.js} +2 -2
- streamlit/static/static/js/{createSuper.B4oGDYRm.js → createSuper.wQ9SIXEJ.js} +1 -1
- streamlit/static/static/js/{data-grid-overlay-editor.msYws2Ou.js → data-grid-overlay-editor.DvbdPJ15.js} +1 -1
- streamlit/static/static/js/{downloader.kc14n2Hv.js → downloader.CD9rzih5.js} +1 -1
- streamlit/static/static/js/{es6.CxQz807-.js → es6.48Q9Qjgb.js} +2 -2
- streamlit/static/static/js/{iframeResizer.contentWindow.B19u0ONI.js → iframeResizer.contentWindow.CKdem3Bn.js} +1 -1
- streamlit/static/static/js/{index.LaIasviC.js → index.6md5Qhod.js} +1 -1
- streamlit/static/static/js/index.7hy6AeJ1.js +1 -0
- streamlit/static/static/js/index.B4CGJiBW.js +1 -0
- streamlit/static/static/js/index.B8oW0ZTD.js +1 -0
- streamlit/static/static/js/index.BU6RnlHI.js +73 -0
- streamlit/static/static/js/index.BUq9Wcf8.js +197 -0
- streamlit/static/static/js/{index.BFz9U2y0.js → index.BXXo-Yoj.js} +1 -1
- streamlit/static/static/js/index.Bae9H0OS.js +1 -0
- streamlit/static/static/js/{index.-5ruC9At.js → index.BhTl2Uyb.js} +1 -1
- streamlit/static/static/js/{index.BpILzHf_.js → index.BiSaCB1o.js} +20 -20
- streamlit/static/static/js/{index.xNQq3Ei5.js → index.BulSAJ9z.js} +1 -1
- streamlit/static/static/js/{index.9V1KdxfP.js → index.Bv-EuTKR.js} +1 -1
- streamlit/static/static/js/index.BvMLYCHi.js +1 -0
- streamlit/static/static/js/index.C1NIn1Y2.js +783 -0
- streamlit/static/static/js/index.CP-fthOJ.js +2 -0
- streamlit/static/static/js/{index.BoigZiu7.js → index.CS9guO3p.js} +1 -1
- streamlit/static/static/js/index.CYTBHth8.js +1 -0
- streamlit/static/static/js/{index.CmTAF0dM.js → index.CcJufcuD.js} +1 -1
- streamlit/static/static/js/index.CnENU1yn.js +1 -0
- streamlit/static/static/js/index.Cns13qBb.js +1 -0
- streamlit/static/static/js/index.Ct_xXq7w.js +1 -0
- streamlit/static/static/js/{index.BqfdT8-Q.js → index.CxGSemHL.js} +1 -1
- streamlit/static/static/js/index.D5S0ldVb.js +1 -0
- streamlit/static/static/js/index.D72B_ksb.js +2 -0
- streamlit/static/static/js/index.DI4yZ27M.js +1 -0
- streamlit/static/static/js/index.DN51vLxR.js +1 -0
- streamlit/static/static/js/index.DRtq5dka.js +1 -0
- streamlit/static/static/js/{index.BHXxWdde.js → index.DX-oiXlb.js} +1 -1
- streamlit/static/static/js/index.DlFE4_Aq.js +12 -0
- streamlit/static/static/js/{index.BHGGDa8K.js → index.J7BJwXOi.js} +2 -2
- streamlit/static/static/js/index.Jg38kJPP.js +1 -0
- streamlit/static/static/js/index.JhIO6abf.js +3 -0
- streamlit/static/static/js/{index.DeB9iKFW.js → index.NkRcWwc5.js} +255 -255
- streamlit/static/static/js/{index.BGga-hcS.js → index.prekPLrm.js} +25 -25
- streamlit/static/static/js/{index.BRXmLIsC.js → index.wyzngKUE.js} +1 -1
- streamlit/static/static/js/index.xW7mVdI8.js +1 -0
- streamlit/static/static/js/index.yk07dYGx.js +1 -0
- streamlit/static/static/js/{input.DsCfafm0.js → input.CxKZ5Wrc.js} +2 -2
- streamlit/static/static/js/{memory.nY_lMTtu.js → memory.DeZ9VUvl.js} +1 -1
- streamlit/static/static/js/{mergeWith.B_7zmsM4.js → mergeWith.CVkhrWUb.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.CSeVhHRU.js → number-overlay-editor.Bpkm3nTq.js} +1 -1
- streamlit/static/static/js/{possibleConstructorReturn.nNhsvgRd.js → possibleConstructorReturn.CIDCId52.js} +1 -1
- streamlit/static/static/js/{sandbox.Cgm3iuL6.js → sandbox.TrkMaokR.js} +1 -1
- streamlit/static/static/js/{textarea.BR8rlyih.js → textarea.QKjxR64N.js} +2 -2
- streamlit/static/static/js/{timepicker.w4XhAenH.js → timepicker.DJYmE1dK.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.CgkEPBwD.js → toConsumableArray.BZoworE-.js} +1 -1
- streamlit/static/static/js/{uniqueId.j-1rlNNH.js → uniqueId.O0UbJ2Bu.js} +1 -1
- streamlit/static/static/js/{useBasicWidgetState.zXY9CjFS.js → useBasicWidgetState.Ci89jaH5.js} +1 -1
- streamlit/static/static/js/useOnInputChange.Cxh6ExEn.js +1 -0
- streamlit/static/static/js/{withFullScreenWrapper.Ov13692o.js → withFullScreenWrapper.iW37lS8Z.js} +1 -1
- streamlit/static/static/media/SourceCodeVF-Italic.ttf.Ba1oaZG1.woff2 +0 -0
- streamlit/static/static/media/SourceCodeVF-Upright.ttf.BjWn63N-.woff2 +0 -0
- streamlit/static/static/media/SourceSansVF-Italic.ttf.Bt9VkdQ3.woff2 +0 -0
- streamlit/static/static/media/SourceSansVF-Upright.ttf.BsWL4Kly.woff2 +0 -0
- streamlit/static/static/media/SourceSerifVariable-Italic.ttf.CVdzAtxO.woff2 +0 -0
- streamlit/static/static/media/SourceSerifVariable-Roman.ttf.mdpVL9bi.woff2 +0 -0
- streamlit/string_util.py +14 -19
- streamlit/temporary_directory.py +13 -4
- streamlit/testing/v1/app_test.py +15 -10
- streamlit/testing/v1/element_tree.py +157 -178
- streamlit/testing/v1/local_script_runner.py +11 -15
- streamlit/testing/v1/util.py +11 -4
- streamlit/type_util.py +8 -12
- streamlit/url_util.py +1 -1
- streamlit/user_info.py +6 -5
- streamlit/util.py +25 -1
- streamlit/vendor/pympler/asizeof.py +3 -2
- streamlit/watcher/event_based_path_watcher.py +21 -2
- streamlit/watcher/folder_black_list.py +2 -2
- streamlit/watcher/local_sources_watcher.py +64 -18
- streamlit/watcher/path_watcher.py +6 -10
- streamlit/watcher/polling_path_watcher.py +8 -7
- streamlit/watcher/util.py +7 -6
- streamlit/web/bootstrap.py +16 -14
- streamlit/web/cli.py +52 -45
- streamlit/web/server/__init__.py +7 -3
- streamlit/web/server/app_static_file_handler.py +1 -1
- streamlit/web/server/authlib_tornado_integration.py +9 -4
- streamlit/web/server/browser_websocket_handler.py +8 -2
- streamlit/web/server/component_request_handler.py +14 -10
- streamlit/web/server/media_file_handler.py +14 -7
- streamlit/web/server/oauth_authlib_routes.py +41 -9
- streamlit/web/server/oidc_mixin.py +35 -17
- streamlit/web/server/routes.py +32 -22
- streamlit/web/server/server.py +13 -24
- streamlit/web/server/server_util.py +43 -9
- streamlit/web/server/stats_request_handler.py +7 -5
- streamlit/web/server/upload_file_request_handler.py +22 -19
- streamlit/web/server/websocket_headers.py +1 -1
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/METADATA +4 -4
- streamlit-1.46.1.dist-info/RECORD +559 -0
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/WHEEL +1 -1
- streamlit/elements/lib/event_utils.py +0 -39
- streamlit/static/static/js/Toolbar.D9RUZv9G.js +0 -1
- streamlit/static/static/js/UploadFileInfo.C-jY39rj.js +0 -1
- streamlit/static/static/js/index.8jhZBWF2.js +0 -3
- streamlit/static/static/js/index.BCx3C6e_.js +0 -1
- streamlit/static/static/js/index.BRuTz_S4.js +0 -1
- streamlit/static/static/js/index.Bcru_ti-.js +0 -1
- streamlit/static/static/js/index.Bl1FMJRd.js +0 -1
- streamlit/static/static/js/index.C1z8KpLA.js +0 -779
- streamlit/static/static/js/index.C32I2PUe.js +0 -2
- streamlit/static/static/js/index.C5GnDRB7.js +0 -1
- streamlit/static/static/js/index.CG4qPaaW.js +0 -2
- streamlit/static/static/js/index.C_msmT1u.js +0 -1
- streamlit/static/static/js/index.CbeNTdd6.js +0 -1
- streamlit/static/static/js/index.CnGQVJcw.js +0 -12
- streamlit/static/static/js/index.CopVVq4l.js +0 -1
- streamlit/static/static/js/index.CtXupx4d.js +0 -197
- streamlit/static/static/js/index.DGmCchO7.js +0 -1
- streamlit/static/static/js/index.DH6zBk0e.js +0 -1
- streamlit/static/static/js/index.DHVlVWsm.js +0 -1
- streamlit/static/static/js/index.DRKIVBoi.js +0 -1
- streamlit/static/static/js/index.DUd-lFXx.js +0 -73
- streamlit/static/static/js/index.D_uRBA4B.js +0 -1
- streamlit/static/static/js/index.QHNfgPJd.js +0 -1
- streamlit/static/static/js/index.a-RJocYL.js +0 -1
- streamlit/static/static/js/index.cvz4B1gy.js +0 -1
- streamlit/static/static/js/index.t--hEgTQ.js +0 -6
- streamlit/static/static/js/useOnInputChange.z04u96A8.js +0 -1
- streamlit/static/static/media/SourceCodePro-Bold.CFEfr7-q.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-BoldItalic.C-LkFXxa.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-Italic.CxFOx7N-.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-Regular.CBOlD63d.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-SemiBold.CFHwW3Wd.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-SemiBoldItalic.Cg2yRu82.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Bold.-6c9oR8J.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-BoldItalic.DmM_grLY.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Italic.I1ipWe7Q.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Regular.DZLUzqI4.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-SemiBold.sKQIyTMz.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-SemiBoldItalic.C0wP0icr.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Bold.8TUnKj4x.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-BoldItalic.CBVO7Ve7.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Italic.DkFgL2HZ.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Regular.CNJNET2S.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-SemiBold.CHyh9GC5.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-SemiBoldItalic.CBtz8sWN.woff2 +0 -0
- streamlit-1.45.1.dist-info/RECORD +0 -568
- {streamlit-1.45.1.data → streamlit-1.46.1.data}/scripts/streamlit.cmd +0 -0
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/entry_points.txt +0 -0
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/top_level.txt +0 -0
|
@@ -38,14 +38,13 @@ def _get_session_id() -> str:
|
|
|
38
38
|
# "streamlit run myscript.py". In which case the session ID doesn't
|
|
39
39
|
# matter and can just be a constant, as there's only ever "session".
|
|
40
40
|
return "dontcare"
|
|
41
|
-
|
|
42
|
-
return ctx.session_id
|
|
41
|
+
return ctx.session_id
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
class MediaFileMetadata:
|
|
46
45
|
"""Metadata that the MediaFileManager needs for each file it manages."""
|
|
47
46
|
|
|
48
|
-
def __init__(self, kind: MediaFileKind = MediaFileKind.MEDIA):
|
|
47
|
+
def __init__(self, kind: MediaFileKind = MediaFileKind.MEDIA) -> None:
|
|
49
48
|
self._kind = kind
|
|
50
49
|
self._is_marked_for_delete = False
|
|
51
50
|
|
|
@@ -80,7 +79,7 @@ class MediaFileManager:
|
|
|
80
79
|
we should address it at some point.)
|
|
81
80
|
"""
|
|
82
81
|
|
|
83
|
-
def __init__(self, storage: MediaFileStorage):
|
|
82
|
+
def __init__(self, storage: MediaFileStorage) -> None:
|
|
84
83
|
self._storage = storage
|
|
85
84
|
|
|
86
85
|
# Dict of [file_id -> MediaFileMetadata]
|
|
@@ -89,7 +89,7 @@ class MemoryFile(NamedTuple):
|
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
class MemoryMediaFileStorage(MediaFileStorage, CacheStatsProvider):
|
|
92
|
-
def __init__(self, media_endpoint: str):
|
|
92
|
+
def __init__(self, media_endpoint: str) -> None:
|
|
93
93
|
"""Create a new MemoryMediaFileStorage instance.
|
|
94
94
|
|
|
95
95
|
Parameters
|
|
@@ -110,10 +110,11 @@ class MemoryMediaFileStorage(MediaFileStorage, CacheStatsProvider):
|
|
|
110
110
|
) -> str:
|
|
111
111
|
"""Add a file to the manager and return its ID."""
|
|
112
112
|
file_data: bytes
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
file_data = (
|
|
114
|
+
self._read_file(path_or_data)
|
|
115
|
+
if isinstance(path_or_data, str)
|
|
116
|
+
else path_or_data
|
|
117
|
+
)
|
|
117
118
|
|
|
118
119
|
# Because our file_ids are stable, if we already have a file with the
|
|
119
120
|
# given ID, we don't need to create a new one.
|
|
@@ -35,7 +35,7 @@ class MemoryUploadedFileManager(UploadedFileManager):
|
|
|
35
35
|
This class can be used safely from multiple threads simultaneously.
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
|
-
def __init__(self, upload_endpoint: str):
|
|
38
|
+
def __init__(self, upload_endpoint: str) -> None:
|
|
39
39
|
self.file_storage: dict[str, dict[str, UploadedFileRec]] = defaultdict(dict)
|
|
40
40
|
self.endpoint = upload_endpoint
|
|
41
41
|
|
|
@@ -92,7 +92,7 @@ class MemoryUploadedFileManager(UploadedFileManager):
|
|
|
92
92
|
|
|
93
93
|
self.file_storage[session_id][file.file_id] = file
|
|
94
94
|
|
|
95
|
-
def remove_file(self, session_id, file_id):
|
|
95
|
+
def remove_file(self, session_id: str, file_id: str) -> None:
|
|
96
96
|
"""Remove file with given file_id associated with a given session."""
|
|
97
97
|
session_storage = self.file_storage[session_id]
|
|
98
98
|
session_storage.pop(file_id, None)
|
|
@@ -201,8 +201,8 @@ def _get_machine_id_v4() -> str:
|
|
|
201
201
|
stable_id = None
|
|
202
202
|
|
|
203
203
|
if os.path.exists(filepath):
|
|
204
|
-
with file_util.streamlit_read(filepath) as
|
|
205
|
-
stable_id =
|
|
204
|
+
with file_util.streamlit_read(filepath) as file:
|
|
205
|
+
stable_id = file.read()
|
|
206
206
|
|
|
207
207
|
if not stable_id:
|
|
208
208
|
stable_id = str(uuid.uuid4())
|
|
@@ -228,7 +228,7 @@ class Installation:
|
|
|
228
228
|
cls._instance = Installation()
|
|
229
229
|
return cls._instance
|
|
230
230
|
|
|
231
|
-
def __init__(self):
|
|
231
|
+
def __init__(self) -> None:
|
|
232
232
|
self.installation_id_v3 = str(
|
|
233
233
|
uuid.uuid5(uuid.NAMESPACE_DNS, _get_machine_id_v3())
|
|
234
234
|
)
|
|
@@ -239,7 +239,7 @@ class Installation:
|
|
|
239
239
|
return util.repr_(self)
|
|
240
240
|
|
|
241
241
|
@property
|
|
242
|
-
def installation_id(self):
|
|
242
|
+
def installation_id(self) -> str:
|
|
243
243
|
return self.installation_id_v3
|
|
244
244
|
|
|
245
245
|
|
|
@@ -284,7 +284,7 @@ def _get_arg_metadata(arg: object) -> str | None:
|
|
|
284
284
|
|
|
285
285
|
|
|
286
286
|
def _get_command_telemetry(
|
|
287
|
-
_command_func: Callable[..., Any], _command_name: str, *args, **kwargs
|
|
287
|
+
_command_func: Callable[..., Any], _command_name: str, *args: Any, **kwargs: Any
|
|
288
288
|
) -> Command:
|
|
289
289
|
"""Get telemetry information for the given callable and its arguments."""
|
|
290
290
|
arg_keywords = inspect.getfullargspec(_command_func).args
|
|
@@ -391,12 +391,11 @@ def gather_metrics(name: str, func: F | None = None) -> Callable[[F], F] | F:
|
|
|
391
391
|
)
|
|
392
392
|
|
|
393
393
|
return wrapper
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
non_optional_func = func
|
|
394
|
+
# To make mypy type narrow F | None -> F
|
|
395
|
+
non_optional_func = func
|
|
397
396
|
|
|
398
397
|
@wraps(non_optional_func)
|
|
399
|
-
def wrapped_func(*args, **kwargs):
|
|
398
|
+
def wrapped_func(*args: Any, **kwargs: Any) -> Any:
|
|
400
399
|
from timeit import default_timer as timer
|
|
401
400
|
|
|
402
401
|
exec_start = timer()
|
|
@@ -442,12 +441,12 @@ def gather_metrics(name: str, func: F | None = None) -> Callable[[F], F] | F:
|
|
|
442
441
|
_LOGGER.debug("Failed to collect command telemetry", exc_info=ex)
|
|
443
442
|
try:
|
|
444
443
|
result = non_optional_func(*args, **kwargs)
|
|
445
|
-
except RerunException
|
|
444
|
+
except RerunException:
|
|
446
445
|
# Duplicated from below, because static analysis tools get confused
|
|
447
446
|
# by deferring the rethrow.
|
|
448
447
|
if tracking_activated and command_telemetry:
|
|
449
448
|
command_telemetry.time = to_microseconds(timer() - exec_start)
|
|
450
|
-
raise
|
|
449
|
+
raise
|
|
451
450
|
finally:
|
|
452
451
|
# Activate tracking again if command executes without any exceptions
|
|
453
452
|
# we only want to do that if this command has set the
|
|
@@ -488,7 +487,7 @@ def create_page_profile_message(
|
|
|
488
487
|
# Collect all config options that have been manually set
|
|
489
488
|
config_options: set[str] = set()
|
|
490
489
|
if config._config_options:
|
|
491
|
-
for option_name in config._config_options
|
|
490
|
+
for option_name in config._config_options:
|
|
492
491
|
if not config.is_manually_set(option_name):
|
|
493
492
|
# We only care about manually defined options
|
|
494
493
|
continue
|
|
@@ -38,8 +38,8 @@ class PagesManager:
|
|
|
38
38
|
self,
|
|
39
39
|
main_script_path: ScriptPath,
|
|
40
40
|
script_cache: ScriptCache | None = None,
|
|
41
|
-
**kwargs,
|
|
42
|
-
):
|
|
41
|
+
**kwargs: Any,
|
|
42
|
+
) -> None:
|
|
43
43
|
self._main_script_path = main_script_path
|
|
44
44
|
self._main_script_hash: PageHash = calc_md5(main_script_path)
|
|
45
45
|
self._script_cache = script_cache
|
|
@@ -99,9 +99,7 @@ class PagesManager:
|
|
|
99
99
|
self._intended_page_script_hash = page_script_hash
|
|
100
100
|
self._intended_page_name = page_name
|
|
101
101
|
|
|
102
|
-
def get_initial_active_script(
|
|
103
|
-
self, page_script_hash: PageHash, page_name: PageName
|
|
104
|
-
) -> PageInfo | None:
|
|
102
|
+
def get_initial_active_script(self, page_script_hash: PageHash) -> PageInfo | None:
|
|
105
103
|
return {
|
|
106
104
|
# We always run the main script in V2 as it's the common code
|
|
107
105
|
"script_path": self.main_script_path,
|
|
@@ -137,7 +135,7 @@ class PagesManager:
|
|
|
137
135
|
self.intended_page_script_hash,
|
|
138
136
|
self._pages.get(fallback_page_hash, None),
|
|
139
137
|
)
|
|
140
|
-
|
|
138
|
+
if self.intended_page_name:
|
|
141
139
|
# If a user navigates directly to a non-main page of an app, the
|
|
142
140
|
# the page name can identify the page script to run
|
|
143
141
|
return next(
|
streamlit/runtime/runtime.py
CHANGED
|
@@ -167,7 +167,7 @@ class Runtime:
|
|
|
167
167
|
"""
|
|
168
168
|
return cls._instance is not None
|
|
169
169
|
|
|
170
|
-
def __init__(self, config: RuntimeConfig):
|
|
170
|
+
def __init__(self, config: RuntimeConfig) -> None:
|
|
171
171
|
"""Create a Runtime instance. It won't be started yet.
|
|
172
172
|
|
|
173
173
|
Runtime is *not* thread-safe. Its public methods are generally
|
|
@@ -313,7 +313,7 @@ class Runtime:
|
|
|
313
313
|
|
|
314
314
|
async_objs = self._get_async_objs()
|
|
315
315
|
|
|
316
|
-
def stop_on_eventloop():
|
|
316
|
+
def stop_on_eventloop() -> None:
|
|
317
317
|
if self._state in (RuntimeState.STOPPING, RuntimeState.STOPPED):
|
|
318
318
|
return
|
|
319
319
|
|
|
@@ -374,9 +374,11 @@ class Runtime:
|
|
|
374
374
|
-----
|
|
375
375
|
Threading: UNSAFE. Must be called on the eventloop thread.
|
|
376
376
|
"""
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
377
|
+
if existing_session_id and session_id_override:
|
|
378
|
+
raise RuntimeError(
|
|
379
|
+
"Only one of existing_session_id and session_id_override should be set. "
|
|
380
|
+
"This should never happen."
|
|
381
|
+
)
|
|
380
382
|
|
|
381
383
|
if self._state in (RuntimeState.STOPPING, RuntimeState.STOPPED):
|
|
382
384
|
raise RuntimeStoppedError(f"Can't connect_session (state={self._state})")
|
|
@@ -596,7 +598,7 @@ class Runtime:
|
|
|
596
598
|
elif self._state == RuntimeState.ONE_OR_MORE_SESSIONS_CONNECTED:
|
|
597
599
|
pass
|
|
598
600
|
else:
|
|
599
|
-
raise RuntimeError(f"Bad Runtime state at start: {self._state}")
|
|
601
|
+
raise RuntimeError(f"Bad Runtime state at start: {self._state}") # noqa: TRY301
|
|
600
602
|
|
|
601
603
|
# Signal that we're started and ready to accept sessions
|
|
602
604
|
async_objs.started.set_result(None)
|
|
@@ -31,7 +31,7 @@ _LOGGER: Final = getLogger(__name__)
|
|
|
31
31
|
class MessageSizeError(MarkdownFormattedException):
|
|
32
32
|
"""Exception raised when a websocket message is larger than the configured limit."""
|
|
33
33
|
|
|
34
|
-
def __init__(self, failed_msg_str: Any):
|
|
34
|
+
def __init__(self, failed_msg_str: Any) -> None:
|
|
35
35
|
msg = self._get_message(failed_msg_str)
|
|
36
36
|
super().__init__(msg)
|
|
37
37
|
|
|
@@ -39,7 +39,8 @@ class MessageSizeError(MarkdownFormattedException):
|
|
|
39
39
|
# This needs to have zero indentation otherwise the markdown will render incorrectly.
|
|
40
40
|
return (
|
|
41
41
|
f"""
|
|
42
|
-
**Data of size {len(failed_msg_str) / 1e6:.1f} MB exceeds the message size limit of
|
|
42
|
+
**Data of size {len(failed_msg_str) / 1e6:.1f} MB exceeds the message size limit of
|
|
43
|
+
{get_max_message_size_bytes() / 1e6} MB.**
|
|
43
44
|
|
|
44
45
|
This is often caused by a large chart or dataframe. Please decrease the amount of data sent
|
|
45
46
|
to the browser, or increase the limit by setting the config option `server.maxMessageSize`.
|
|
@@ -54,7 +55,7 @@ of the client's browser and the Streamlit server._
|
|
|
54
55
|
class BadDurationStringError(StreamlitAPIException):
|
|
55
56
|
"""Raised when a bad duration argument string is passed."""
|
|
56
57
|
|
|
57
|
-
def __init__(self, duration: str):
|
|
58
|
+
def __init__(self, duration: str) -> None:
|
|
58
59
|
MarkdownFormattedException.__init__(
|
|
59
60
|
self,
|
|
60
61
|
"TTL string doesn't look right. It should be formatted as"
|
|
@@ -74,12 +75,12 @@ def serialize_forward_msg(msg: ForwardMsg) -> bytes:
|
|
|
74
75
|
if len(msg_str) > get_max_message_size_bytes():
|
|
75
76
|
# Overwrite the offending ForwardMsg.delta with an error to display.
|
|
76
77
|
# This assumes that the size limit wasn't exceeded due to metadata.
|
|
77
|
-
|
|
78
|
+
from streamlit.elements import exception
|
|
78
79
|
|
|
79
80
|
msg_size_error = MessageSizeError(msg_str)
|
|
80
81
|
_LOGGER.warning(
|
|
81
|
-
"Websocket message size limit exceeded. "
|
|
82
|
-
|
|
82
|
+
"Websocket message size limit exceeded. Showing error to the user: %s",
|
|
83
|
+
msg_size_error,
|
|
83
84
|
)
|
|
84
85
|
exception.marshall(msg.delta.new_element.exception, msg_size_error)
|
|
85
86
|
# Deactivate caching for this error message:
|
|
@@ -27,12 +27,12 @@ from streamlit.runtime.scriptrunner_utils.script_run_context import (
|
|
|
27
27
|
|
|
28
28
|
__all__ = [
|
|
29
29
|
"RerunData",
|
|
30
|
-
"ScriptRunContext",
|
|
31
|
-
"add_script_run_ctx",
|
|
32
|
-
"get_script_run_ctx",
|
|
33
|
-
"enqueue_message",
|
|
34
30
|
"RerunException",
|
|
31
|
+
"ScriptRunContext",
|
|
35
32
|
"ScriptRunner",
|
|
36
33
|
"ScriptRunnerEvent",
|
|
37
34
|
"StopException",
|
|
35
|
+
"add_script_run_ctx",
|
|
36
|
+
"enqueue_message",
|
|
37
|
+
"get_script_run_ctx",
|
|
38
38
|
]
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import sys
|
|
18
|
-
from typing import TYPE_CHECKING, Any, Callable
|
|
18
|
+
from typing import TYPE_CHECKING, Any, Callable, Literal
|
|
19
19
|
|
|
20
20
|
from streamlit import util
|
|
21
21
|
from streamlit.delta_generator_singletons import (
|
|
@@ -30,30 +30,37 @@ from streamlit.runtime.scriptrunner_utils.exceptions import (
|
|
|
30
30
|
)
|
|
31
31
|
|
|
32
32
|
if TYPE_CHECKING:
|
|
33
|
+
from types import TracebackType
|
|
34
|
+
|
|
33
35
|
from streamlit.runtime.scriptrunner_utils.script_requests import RerunData
|
|
34
36
|
from streamlit.runtime.scriptrunner_utils.script_run_context import ScriptRunContext
|
|
35
37
|
|
|
36
38
|
|
|
37
|
-
class modified_sys_path:
|
|
39
|
+
class modified_sys_path: # noqa: N801
|
|
38
40
|
"""A context for prepending a directory to sys.path for a second.
|
|
39
41
|
|
|
40
42
|
Code inspired by IPython:
|
|
41
43
|
Source: https://github.com/ipython/ipython/blob/master/IPython/utils/syspathcontext.py#L42
|
|
42
44
|
"""
|
|
43
45
|
|
|
44
|
-
def __init__(self, main_script_path: str):
|
|
46
|
+
def __init__(self, main_script_path: str) -> None:
|
|
45
47
|
self._main_script_path = main_script_path
|
|
46
48
|
self._added_path = False
|
|
47
49
|
|
|
48
50
|
def __repr__(self) -> str:
|
|
49
51
|
return util.repr_(self)
|
|
50
52
|
|
|
51
|
-
def __enter__(self):
|
|
53
|
+
def __enter__(self) -> None:
|
|
52
54
|
if self._main_script_path not in sys.path:
|
|
53
55
|
sys.path.insert(0, self._main_script_path)
|
|
54
56
|
self._added_path = True
|
|
55
57
|
|
|
56
|
-
def __exit__(
|
|
58
|
+
def __exit__(
|
|
59
|
+
self,
|
|
60
|
+
typ: type[BaseException] | None,
|
|
61
|
+
exc: BaseException | None,
|
|
62
|
+
tb: TracebackType | None,
|
|
63
|
+
) -> Literal[False]:
|
|
57
64
|
if self._added_path:
|
|
58
65
|
try:
|
|
59
66
|
sys.path.remove(self._main_script_path)
|
|
@@ -21,8 +21,7 @@ from typing import Any, Final
|
|
|
21
21
|
from streamlit import config
|
|
22
22
|
|
|
23
23
|
# When a Streamlit app is magicified, we insert a `magic_funcs` import near the top of
|
|
24
|
-
# its module's AST:
|
|
25
|
-
# import streamlit.runtime.scriptrunner.magic_funcs as __streamlitmagic__
|
|
24
|
+
# its module's AST: import streamlit.runtime.scriptrunner.magic_funcs as __streamlitmagic__
|
|
26
25
|
MAGIC_MODULE_NAME: Final = "__streamlitmagic__"
|
|
27
26
|
|
|
28
27
|
|
|
@@ -59,7 +58,7 @@ def _modify_ast_subtree(
|
|
|
59
58
|
body_attr: str = "body",
|
|
60
59
|
is_root: bool = False,
|
|
61
60
|
file_ends_in_semicolon: bool = False,
|
|
62
|
-
):
|
|
61
|
+
) -> None:
|
|
63
62
|
"""Parses magic commands and modifies the given AST (sub)tree."""
|
|
64
63
|
|
|
65
64
|
body = getattr(tree, body_attr)
|
|
@@ -162,7 +161,7 @@ def _insert_import_statement(tree: Any) -> None:
|
|
|
162
161
|
tree.body.insert(0, st_import)
|
|
163
162
|
|
|
164
163
|
|
|
165
|
-
def _build_st_import_statement():
|
|
164
|
+
def _build_st_import_statement() -> ast.Import:
|
|
166
165
|
"""Build AST node for `import magic_funcs as __streamlitmagic__`."""
|
|
167
166
|
return ast.Import(
|
|
168
167
|
names=[
|
|
@@ -174,7 +173,7 @@ def _build_st_import_statement():
|
|
|
174
173
|
)
|
|
175
174
|
|
|
176
175
|
|
|
177
|
-
def _build_st_write_call(nodes):
|
|
176
|
+
def _build_st_write_call(nodes: list[Any]) -> ast.Call:
|
|
178
177
|
"""Build AST node for `__streamlitmagic__.transparent_write(*nodes)`."""
|
|
179
178
|
return ast.Call(
|
|
180
179
|
func=ast.Attribute(
|
|
@@ -188,8 +187,13 @@ def _build_st_write_call(nodes):
|
|
|
188
187
|
|
|
189
188
|
|
|
190
189
|
def _get_st_write_from_expr(
|
|
191
|
-
node
|
|
192
|
-
|
|
190
|
+
node: Any,
|
|
191
|
+
i: int,
|
|
192
|
+
parent_type: Any,
|
|
193
|
+
is_root: bool,
|
|
194
|
+
is_last_expr: bool,
|
|
195
|
+
file_ends_in_semicolon: bool,
|
|
196
|
+
) -> ast.Call | None:
|
|
193
197
|
# Don't wrap function calls
|
|
194
198
|
# (Unless the function call happened at the end of the root node, AND
|
|
195
199
|
# magic.displayLastExprIfNoSemicolon is True. This allows us to support notebook-like
|
|
@@ -217,17 +221,17 @@ def _get_st_write_from_expr(
|
|
|
217
221
|
return None
|
|
218
222
|
|
|
219
223
|
# If tuple, call st.write(*the_tuple). This allows us to add a comma at the end of a
|
|
220
|
-
# statement to turn it into an expression that should be
|
|
221
|
-
# "np.random.randn(1000, 2),"
|
|
224
|
+
# statement to turn it into an expression that should be
|
|
225
|
+
# st-written. Ex: "np.random.randn(1000, 2),"
|
|
222
226
|
args = node.value.elts if type(node.value) is ast.Tuple else [node.value]
|
|
223
227
|
return _build_st_write_call(args)
|
|
224
228
|
|
|
225
229
|
|
|
226
|
-
def _is_string_constant_node(node) -> bool:
|
|
230
|
+
def _is_string_constant_node(node: Any) -> bool:
|
|
227
231
|
return isinstance(node, ast.Constant) and isinstance(node.value, str)
|
|
228
232
|
|
|
229
233
|
|
|
230
|
-
def _is_docstring_node(node, node_index, parent_type) -> bool:
|
|
234
|
+
def _is_docstring_node(node: Any, node_index: int, parent_type: Any) -> bool:
|
|
231
235
|
return (
|
|
232
236
|
node_index == 0
|
|
233
237
|
and _is_string_constant_node(node)
|
|
@@ -235,7 +239,7 @@ def _is_docstring_node(node, node_index, parent_type) -> bool:
|
|
|
235
239
|
)
|
|
236
240
|
|
|
237
241
|
|
|
238
|
-
def _does_file_end_in_semicolon(tree, code: str) -> bool:
|
|
242
|
+
def _does_file_end_in_semicolon(tree: Any, code: str) -> bool:
|
|
239
243
|
file_ends_in_semicolon = False
|
|
240
244
|
|
|
241
245
|
# Avoid spending time with this operation if magic.displayLastExprIfNoSemicolon is
|
|
@@ -26,7 +26,7 @@ from streamlit.source_util import open_python_file
|
|
|
26
26
|
class ScriptCache:
|
|
27
27
|
"""Thread-safe cache of Python script bytecode."""
|
|
28
28
|
|
|
29
|
-
def __init__(self):
|
|
29
|
+
def __init__(self) -> None:
|
|
30
30
|
# Mapping of script_path: bytecode
|
|
31
31
|
self._cache: dict[str, Any] = {}
|
|
32
32
|
self._lock = threading.Lock()
|
|
@@ -62,6 +62,8 @@ from streamlit.runtime.state import (
|
|
|
62
62
|
from streamlit.source_util import page_sort_key
|
|
63
63
|
|
|
64
64
|
if TYPE_CHECKING:
|
|
65
|
+
from collections.abc import Generator
|
|
66
|
+
|
|
65
67
|
from streamlit.runtime.fragment import FragmentStorage
|
|
66
68
|
from streamlit.runtime.scriptrunner.script_cache import ScriptCache
|
|
67
69
|
from streamlit.runtime.uploaded_file_manager import UploadedFileManager
|
|
@@ -121,36 +123,35 @@ it in the future.
|
|
|
121
123
|
# is designed to leverage our original v1 version of multi-page apps. This
|
|
122
124
|
# function will be called to run the script in lieu of the main script. This
|
|
123
125
|
# function simulates the v1 setup using the modern v2 commands (st.navigation)
|
|
124
|
-
def _mpa_v1(main_script_path: str):
|
|
126
|
+
def _mpa_v1(main_script_path: str) -> None:
|
|
125
127
|
from pathlib import Path
|
|
126
128
|
|
|
127
129
|
from streamlit.commands.navigation import PageType, _navigation
|
|
128
130
|
from streamlit.navigation.page import StreamlitPage
|
|
129
131
|
|
|
130
132
|
# Select the folder that should be used for the pages:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
+
resolved_main_script_path: Final = Path(main_script_path).resolve()
|
|
134
|
+
pages_folder: Final = resolved_main_script_path.parent / "pages"
|
|
133
135
|
|
|
134
136
|
# Read out the my_pages folder and create a page for every script:
|
|
135
|
-
pages = PAGES_FOLDER.glob("*.py")
|
|
136
137
|
pages = sorted(
|
|
137
138
|
[
|
|
138
139
|
page
|
|
139
|
-
for page in
|
|
140
|
+
for page in pages_folder.glob("*.py")
|
|
140
141
|
if page.name.endswith(".py")
|
|
141
142
|
and not page.name.startswith(".")
|
|
142
|
-
and
|
|
143
|
+
and page.name != "__init__.py"
|
|
143
144
|
],
|
|
144
145
|
key=page_sort_key,
|
|
145
146
|
)
|
|
146
147
|
|
|
147
148
|
# Use this script as the main page and
|
|
148
|
-
main_page = StreamlitPage(
|
|
149
|
+
main_page = StreamlitPage(resolved_main_script_path, default=True)
|
|
149
150
|
all_pages = [main_page] + [
|
|
150
|
-
StreamlitPage(
|
|
151
|
+
StreamlitPage(pages_folder / page.name) for page in pages
|
|
151
152
|
]
|
|
152
153
|
# Initialize the navigation with all the pages:
|
|
153
|
-
position: Literal["sidebar", "hidden"] = (
|
|
154
|
+
position: Literal["sidebar", "hidden", "top"] = (
|
|
154
155
|
"hidden"
|
|
155
156
|
if config.get_option("client.showSidebarNavigation") is False
|
|
156
157
|
else "sidebar"
|
|
@@ -176,7 +177,7 @@ class ScriptRunner:
|
|
|
176
177
|
user_info: dict[str, str | bool | None],
|
|
177
178
|
fragment_storage: FragmentStorage,
|
|
178
179
|
pages_manager: PagesManager,
|
|
179
|
-
):
|
|
180
|
+
) -> None:
|
|
180
181
|
"""Initialize the ScriptRunner.
|
|
181
182
|
|
|
182
183
|
(The ScriptRunner won't start executing until start() is called.)
|
|
@@ -261,7 +262,7 @@ class ScriptRunner:
|
|
|
261
262
|
# _maybe_handle_execution_control_request.
|
|
262
263
|
self._execing = False
|
|
263
264
|
|
|
264
|
-
# This is initialized in start()
|
|
265
|
+
# This is initialized in the start() method
|
|
265
266
|
self._script_thread: threading.Thread | None = None
|
|
266
267
|
|
|
267
268
|
def __repr__(self) -> str:
|
|
@@ -297,7 +298,7 @@ class ScriptRunner:
|
|
|
297
298
|
|
|
298
299
|
"""
|
|
299
300
|
if self._script_thread is not None:
|
|
300
|
-
raise
|
|
301
|
+
raise RuntimeError("ScriptRunner was already started")
|
|
301
302
|
|
|
302
303
|
self._script_thread = threading.Thread(
|
|
303
304
|
target=self._run_script_thread,
|
|
@@ -321,7 +322,10 @@ class ScriptRunner:
|
|
|
321
322
|
If there is no ScriptRunContext for the current thread.
|
|
322
323
|
|
|
323
324
|
"""
|
|
324
|
-
|
|
325
|
+
if not self._is_in_script_thread():
|
|
326
|
+
raise RuntimeError(
|
|
327
|
+
"ScriptRunner._get_script_run_ctx must be called from the script thread."
|
|
328
|
+
)
|
|
325
329
|
|
|
326
330
|
ctx = get_script_run_ctx()
|
|
327
331
|
if ctx is None:
|
|
@@ -341,7 +345,10 @@ class ScriptRunner:
|
|
|
341
345
|
When the ScriptRequestQueue is empty, or when a SHUTDOWN request is
|
|
342
346
|
dequeued, this function will exit and its thread will terminate.
|
|
343
347
|
"""
|
|
344
|
-
|
|
348
|
+
if not self._is_in_script_thread():
|
|
349
|
+
raise RuntimeError(
|
|
350
|
+
"ScriptRunner._run_script_thread must be called from the script thread."
|
|
351
|
+
)
|
|
345
352
|
|
|
346
353
|
_LOGGER.debug("Beginning script thread")
|
|
347
354
|
|
|
@@ -371,13 +378,18 @@ class ScriptRunner:
|
|
|
371
378
|
self._run_script(request.rerun_data)
|
|
372
379
|
request = self._requests.on_scriptrunner_ready()
|
|
373
380
|
|
|
374
|
-
|
|
381
|
+
if request.type != ScriptRequestType.STOP:
|
|
382
|
+
raise RuntimeError(
|
|
383
|
+
f"Unrecognized ScriptRequestType: {request.type}. This should never happen."
|
|
384
|
+
)
|
|
375
385
|
|
|
376
386
|
# Send a SHUTDOWN event before exiting, so some state can be saved
|
|
377
387
|
# for use in a future script run when not triggered by the client.
|
|
378
388
|
client_state = ClientState()
|
|
379
389
|
client_state.query_string = ctx.query_string
|
|
380
390
|
client_state.page_script_hash = ctx.page_script_hash
|
|
391
|
+
if ctx.context_info:
|
|
392
|
+
client_state.context_info.CopyFrom(ctx.context_info)
|
|
381
393
|
self.on_event.send(
|
|
382
394
|
self, event=ScriptRunnerEvent.SHUTDOWN, client_state=client_state
|
|
383
395
|
)
|
|
@@ -433,11 +445,14 @@ class ScriptRunner:
|
|
|
433
445
|
if request.type == ScriptRequestType.RERUN:
|
|
434
446
|
raise RerunException(request.rerun_data)
|
|
435
447
|
|
|
436
|
-
|
|
448
|
+
if request.type != ScriptRequestType.STOP:
|
|
449
|
+
raise RuntimeError(
|
|
450
|
+
f"Unrecognized ScriptRequestType: {request.type}. This should never happen."
|
|
451
|
+
)
|
|
437
452
|
raise StopException()
|
|
438
453
|
|
|
439
454
|
@contextmanager
|
|
440
|
-
def _set_execing_flag(self):
|
|
455
|
+
def _set_execing_flag(self) -> Generator[None, None, None]:
|
|
441
456
|
"""A context for setting the ScriptRunner._execing flag.
|
|
442
457
|
|
|
443
458
|
Used by _maybe_handle_execution_control_request to ensure that
|
|
@@ -461,7 +476,10 @@ class ScriptRunner:
|
|
|
461
476
|
|
|
462
477
|
"""
|
|
463
478
|
|
|
464
|
-
|
|
479
|
+
if not self._is_in_script_thread():
|
|
480
|
+
raise RuntimeError(
|
|
481
|
+
"ScriptRunner._run_script must be called from the script thread."
|
|
482
|
+
)
|
|
465
483
|
|
|
466
484
|
# An explicit loop instead of recursion to avoid stack overflows
|
|
467
485
|
while True:
|
|
@@ -480,7 +498,7 @@ class ScriptRunner:
|
|
|
480
498
|
rerun_data.page_script_hash, rerun_data.page_name
|
|
481
499
|
)
|
|
482
500
|
active_script = self._pages_manager.get_initial_active_script(
|
|
483
|
-
rerun_data.page_script_hash
|
|
501
|
+
rerun_data.page_script_hash
|
|
484
502
|
)
|
|
485
503
|
main_page_info = self._pages_manager.get_main_page()
|
|
486
504
|
|
|
@@ -585,7 +603,12 @@ class ScriptRunner:
|
|
|
585
603
|
# assume is the main script directory.
|
|
586
604
|
module.__dict__["__file__"] = script_path
|
|
587
605
|
|
|
588
|
-
def code_to_exec(
|
|
606
|
+
def code_to_exec(
|
|
607
|
+
code: str = code,
|
|
608
|
+
module: types.ModuleType = module,
|
|
609
|
+
ctx: ScriptRunContext = ctx,
|
|
610
|
+
rerun_data: RerunData = rerun_data,
|
|
611
|
+
) -> None:
|
|
589
612
|
with (
|
|
590
613
|
modified_sys_path(self._main_script_path),
|
|
591
614
|
self._set_execing_flag(),
|
|
@@ -606,7 +629,7 @@ class ScriptRunner:
|
|
|
606
629
|
)
|
|
607
630
|
wrapped_fragment()
|
|
608
631
|
|
|
609
|
-
except FragmentStorageKeyError:
|
|
632
|
+
except FragmentStorageKeyError: # noqa: PERF203
|
|
610
633
|
# This can happen if the fragment_id is removed from the
|
|
611
634
|
# storage before the script runner gets to it. In this
|
|
612
635
|
# case, the fragment is simply skipped.
|
|
@@ -618,20 +641,21 @@ class ScriptRunner:
|
|
|
618
641
|
# (see https://github.com/streamlit/streamlit/issues/9080).
|
|
619
642
|
if not rerun_data.is_auto_rerun:
|
|
620
643
|
_LOGGER.warning(
|
|
621
|
-
|
|
644
|
+
"Couldn't find fragment with id %s."
|
|
622
645
|
" This can happen if the fragment does not"
|
|
623
646
|
" exist anymore when this request is processed,"
|
|
624
647
|
" for example because a full app rerun happened"
|
|
625
648
|
" that did not register the fragment."
|
|
626
649
|
" Usually this doesn't happen or no action is"
|
|
627
|
-
" required, so its mainly for debugging."
|
|
650
|
+
" required, so its mainly for debugging.",
|
|
651
|
+
fragment_id,
|
|
628
652
|
)
|
|
629
|
-
except (RerunException, StopException)
|
|
653
|
+
except (RerunException, StopException):
|
|
630
654
|
# The wrapped_fragment function is executed
|
|
631
655
|
# inside of a exec_func_with_error_handling call, so
|
|
632
656
|
# there is a correct handler for these exceptions.
|
|
633
|
-
raise
|
|
634
|
-
except Exception:
|
|
657
|
+
raise
|
|
658
|
+
except Exception: # noqa: S110
|
|
635
659
|
# Ignore exceptions raised by fragments here as we don't
|
|
636
660
|
# want to stop the execution of other fragments. The
|
|
637
661
|
# error itself is already rendered within the wrapped
|
|
@@ -642,7 +666,7 @@ class ScriptRunner:
|
|
|
642
666
|
if PagesManager.uses_pages_directory:
|
|
643
667
|
_mpa_v1(self._main_script_path)
|
|
644
668
|
else:
|
|
645
|
-
exec(code, module.__dict__)
|
|
669
|
+
exec(code, module.__dict__) # noqa: S102
|
|
646
670
|
self._fragment_storage.clear(
|
|
647
671
|
new_fragment_ids=ctx.new_fragment_ids
|
|
648
672
|
)
|
|
@@ -739,7 +763,7 @@ def _clean_problem_modules() -> None:
|
|
|
739
763
|
try:
|
|
740
764
|
keras = sys.modules["keras"]
|
|
741
765
|
keras.backend.clear_session()
|
|
742
|
-
except Exception:
|
|
766
|
+
except Exception: # noqa: S110
|
|
743
767
|
# We don't want to crash the app if we can't clear the Keras session.
|
|
744
768
|
pass
|
|
745
769
|
|
|
@@ -747,7 +771,7 @@ def _clean_problem_modules() -> None:
|
|
|
747
771
|
try:
|
|
748
772
|
plt = sys.modules["matplotlib.pyplot"]
|
|
749
773
|
plt.close("all")
|
|
750
|
-
except Exception:
|
|
774
|
+
except Exception: # noqa: S110
|
|
751
775
|
# We don't want to crash the app if we can't close matplotlib
|
|
752
776
|
pass
|
|
753
777
|
|
|
@@ -34,7 +34,7 @@ class StopException(ScriptControlException):
|
|
|
34
34
|
class RerunException(ScriptControlException):
|
|
35
35
|
"""Silently stop and rerun the user's script."""
|
|
36
36
|
|
|
37
|
-
def __init__(self, rerun_data: RerunData):
|
|
37
|
+
def __init__(self, rerun_data: RerunData) -> None:
|
|
38
38
|
"""Construct a RerunException.
|
|
39
39
|
|
|
40
40
|
Parameters
|