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
streamlit/web/bootstrap.py
CHANGED
|
@@ -21,7 +21,6 @@ import sys
|
|
|
21
21
|
from typing import Any, Final
|
|
22
22
|
|
|
23
23
|
from streamlit import cli_util, config, env_util, file_util, net_util, secrets
|
|
24
|
-
from streamlit.config import CONFIG_FILENAMES
|
|
25
24
|
from streamlit.git_util import MIN_GIT_VERSION, GitRepo
|
|
26
25
|
from streamlit.logger import get_logger
|
|
27
26
|
from streamlit.watcher import report_watchdog_availability, watch_file
|
|
@@ -39,7 +38,7 @@ MAX_APP_STATIC_FOLDER_SIZE = 1 * 1024 * 1024 * 1024 # 1 GB
|
|
|
39
38
|
def _set_up_signal_handler(server: Server) -> None:
|
|
40
39
|
_LOGGER.debug("Setting up signal handler")
|
|
41
40
|
|
|
42
|
-
def signal_handler(signal_number, stack_frame):
|
|
41
|
+
def signal_handler(signal_number: int, stack_frame: Any) -> None: # noqa: ARG001
|
|
43
42
|
# The server will shut down its threads and exit its loop.
|
|
44
43
|
server.stop()
|
|
45
44
|
|
|
@@ -98,7 +97,7 @@ def _fix_sys_argv(main_script_path: str, args: list[str]) -> None:
|
|
|
98
97
|
"""
|
|
99
98
|
import sys
|
|
100
99
|
|
|
101
|
-
sys.argv = [main_script_path
|
|
100
|
+
sys.argv = [main_script_path, *list(args)]
|
|
102
101
|
|
|
103
102
|
|
|
104
103
|
def _on_server_start(server: Server) -> None:
|
|
@@ -112,10 +111,10 @@ def _on_server_start(server: Server) -> None:
|
|
|
112
111
|
# errors and display them here.
|
|
113
112
|
try:
|
|
114
113
|
secrets.load_if_toml_exists()
|
|
115
|
-
except Exception
|
|
116
|
-
_LOGGER.
|
|
114
|
+
except Exception:
|
|
115
|
+
_LOGGER.exception("Failed to load secrets.toml file")
|
|
117
116
|
|
|
118
|
-
def maybe_open_browser():
|
|
117
|
+
def maybe_open_browser() -> None:
|
|
119
118
|
if config.get_option("server.headless"):
|
|
120
119
|
# Don't open browser when in headless mode.
|
|
121
120
|
return
|
|
@@ -141,7 +140,8 @@ def _fix_pydeck_mapbox_api_warning() -> None:
|
|
|
141
140
|
will throw an exception.
|
|
142
141
|
"""
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
if "MAPBOX_API_KEY" not in os.environ:
|
|
144
|
+
os.environ["MAPBOX_API_KEY"] = config.get_option("mapbox.token")
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
def _maybe_print_static_folder_warning(main_script_path: str) -> None:
|
|
@@ -209,7 +209,7 @@ def _print_url(is_running_hello: bool) -> None:
|
|
|
209
209
|
named_urls.append(("External URL", server_util.get_url(external_ip)))
|
|
210
210
|
|
|
211
211
|
cli_util.print_to_cli("")
|
|
212
|
-
cli_util.print_to_cli("
|
|
212
|
+
cli_util.print_to_cli(f" {title_message}", fg="blue", bold=True)
|
|
213
213
|
cli_util.print_to_cli("")
|
|
214
214
|
|
|
215
215
|
for url_name, url in named_urls:
|
|
@@ -287,10 +287,10 @@ def load_config_options(flag_options: dict[str, Any]) -> None:
|
|
|
287
287
|
|
|
288
288
|
|
|
289
289
|
def _install_config_watchers(flag_options: dict[str, Any]) -> None:
|
|
290
|
-
def on_config_changed(_path):
|
|
290
|
+
def on_config_changed(_path: str) -> None:
|
|
291
291
|
load_config_options(flag_options)
|
|
292
292
|
|
|
293
|
-
for filename in
|
|
293
|
+
for filename in config.get_config_files("config.toml"):
|
|
294
294
|
if os.path.exists(filename):
|
|
295
295
|
watch_file(filename, on_config_changed)
|
|
296
296
|
|
|
@@ -307,6 +307,7 @@ def run(
|
|
|
307
307
|
|
|
308
308
|
This starts a blocking asyncio eventloop.
|
|
309
309
|
"""
|
|
310
|
+
|
|
310
311
|
_fix_sys_path(main_script_path)
|
|
311
312
|
_fix_tornado_crash()
|
|
312
313
|
_fix_sys_argv(main_script_path, args)
|
|
@@ -335,18 +336,19 @@ def run(
|
|
|
335
336
|
await server.stopped
|
|
336
337
|
|
|
337
338
|
# Run the server. This function will not return until the server is shut down.
|
|
338
|
-
# FIX RuntimeError: asyncio.run() cannot be called from a running event loop
|
|
339
|
-
# asyncio.run(run_server())
|
|
339
|
+
# FIX RuntimeError: asyncio.run() cannot be called from a running event loop
|
|
340
|
+
# asyncio.run(run_server()) # noqa: ERA001
|
|
340
341
|
|
|
341
342
|
# Define a main function to handle the event loop logic
|
|
342
|
-
async def main():
|
|
343
|
+
async def main() -> None:
|
|
343
344
|
await run_server()
|
|
344
345
|
|
|
345
346
|
try:
|
|
346
347
|
# Check if we're already in an event loop
|
|
347
348
|
if asyncio.get_running_loop().is_running():
|
|
348
349
|
# Use `asyncio.create_task` if we're in an async context
|
|
349
|
-
|
|
350
|
+
# TODO(lukasmasuch): Do we have to store a reference for the task here?
|
|
351
|
+
asyncio.create_task(main()) # noqa: RUF006
|
|
350
352
|
else:
|
|
351
353
|
# Otherwise, use `asyncio.run`
|
|
352
354
|
asyncio.run(main())
|
streamlit/web/cli.py
CHANGED
|
@@ -18,15 +18,15 @@ from __future__ import annotations
|
|
|
18
18
|
|
|
19
19
|
import os
|
|
20
20
|
import sys
|
|
21
|
-
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
|
21
|
+
from typing import TYPE_CHECKING, Any, Callable, Final, TypeVar
|
|
22
22
|
|
|
23
23
|
# We cannot lazy-load click here because its used via decorators.
|
|
24
24
|
import click
|
|
25
25
|
|
|
26
|
-
import streamlit.runtime.caching as caching
|
|
27
|
-
import streamlit.web.bootstrap as bootstrap
|
|
28
26
|
from streamlit import config as _config
|
|
27
|
+
from streamlit.runtime import caching
|
|
29
28
|
from streamlit.runtime.credentials import Credentials, check_credentials
|
|
29
|
+
from streamlit.web import bootstrap
|
|
30
30
|
from streamlit.web.cache_storage_manager_config import (
|
|
31
31
|
create_default_cache_storage_manager,
|
|
32
32
|
)
|
|
@@ -34,9 +34,9 @@ from streamlit.web.cache_storage_manager_config import (
|
|
|
34
34
|
if TYPE_CHECKING:
|
|
35
35
|
from streamlit.config_option import ConfigOption
|
|
36
36
|
|
|
37
|
-
ACCEPTED_FILE_EXTENSIONS = ("py", "py3")
|
|
37
|
+
ACCEPTED_FILE_EXTENSIONS: Final = ("py", "py3")
|
|
38
38
|
|
|
39
|
-
LOG_LEVELS = ("error", "warning", "info", "debug")
|
|
39
|
+
LOG_LEVELS: Final = ("error", "warning", "info", "debug")
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def _convert_config_option_to_click_option(
|
|
@@ -63,10 +63,12 @@ def _convert_config_option_to_click_option(
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
def _make_sensitive_option_callback(
|
|
67
|
-
|
|
66
|
+
def _make_sensitive_option_callback(
|
|
67
|
+
config_option: ConfigOption,
|
|
68
|
+
) -> Callable[[click.Context, click.Parameter, Any], None]:
|
|
69
|
+
def callback(_ctx: click.Context, _param: click.Parameter, cli_value: Any) -> None:
|
|
68
70
|
if cli_value is None:
|
|
69
|
-
return
|
|
71
|
+
return
|
|
70
72
|
raise SystemExit(
|
|
71
73
|
f"Setting {config_option.key!r} option using the CLI flag is not allowed. "
|
|
72
74
|
f"Set this option in the configuration file or environment "
|
|
@@ -103,7 +105,7 @@ def configurator_options(func: F) -> F:
|
|
|
103
105
|
help=parsed_parameter["description"],
|
|
104
106
|
type=parsed_parameter["type"],
|
|
105
107
|
multiple=parsed_parameter["multiple"],
|
|
106
|
-
**click_option_kwargs,
|
|
108
|
+
**click_option_kwargs, # type: ignore
|
|
107
109
|
)
|
|
108
110
|
func = config_option(func)
|
|
109
111
|
return func
|
|
@@ -115,7 +117,7 @@ def _download_remote(main_script_path: str, url_path: str) -> None:
|
|
|
115
117
|
|
|
116
118
|
with open(main_script_path, "wb") as fp:
|
|
117
119
|
try:
|
|
118
|
-
resp = requests.get(url_path)
|
|
120
|
+
resp = requests.get(url_path, timeout=30)
|
|
119
121
|
resp.raise_for_status()
|
|
120
122
|
fp.write(resp.content)
|
|
121
123
|
except requests.exceptions.RequestException as e:
|
|
@@ -125,7 +127,7 @@ def _download_remote(main_script_path: str, url_path: str) -> None:
|
|
|
125
127
|
@click.group(context_settings={"auto_envvar_prefix": "STREAMLIT"})
|
|
126
128
|
@click.option("--log_level", show_default=True, type=click.Choice(LOG_LEVELS))
|
|
127
129
|
@click.version_option(prog_name="Streamlit")
|
|
128
|
-
def main(log_level="info"):
|
|
130
|
+
def main(log_level: str = "info") -> None:
|
|
129
131
|
"""Try out a demo with:
|
|
130
132
|
|
|
131
133
|
$ streamlit hello
|
|
@@ -138,29 +140,27 @@ def main(log_level="info"):
|
|
|
138
140
|
if log_level:
|
|
139
141
|
from streamlit.logger import get_logger
|
|
140
142
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
logger: Final = get_logger(__name__)
|
|
144
|
+
logger.warning(
|
|
143
145
|
"Setting the log level using the --log_level flag is unsupported."
|
|
144
146
|
"\nUse the --logger.level flag (after your streamlit command) instead."
|
|
145
147
|
)
|
|
146
148
|
|
|
147
149
|
|
|
148
150
|
@main.command("help")
|
|
149
|
-
def help():
|
|
151
|
+
def help() -> None: # noqa: A001
|
|
150
152
|
"""Print this help message."""
|
|
151
153
|
# We use _get_command_line_as_string to run some error checks but don't do
|
|
152
154
|
# anything with its return value.
|
|
153
155
|
_get_command_line_as_string()
|
|
154
156
|
|
|
155
|
-
assert len(sys.argv) == 2 # This is always true, but let's assert anyway.
|
|
156
|
-
|
|
157
157
|
# Pretend user typed 'streamlit --help' instead of 'streamlit help'.
|
|
158
158
|
sys.argv[1] = "--help"
|
|
159
159
|
main(prog_name="streamlit")
|
|
160
160
|
|
|
161
161
|
|
|
162
162
|
@main.command("version")
|
|
163
|
-
def main_version():
|
|
163
|
+
def main_version() -> None:
|
|
164
164
|
"""Print Streamlit's version number."""
|
|
165
165
|
# Pretend user typed 'streamlit --version' instead of 'streamlit version'
|
|
166
166
|
import sys
|
|
@@ -169,13 +169,12 @@ def main_version():
|
|
|
169
169
|
# anything with its return value.
|
|
170
170
|
_get_command_line_as_string()
|
|
171
171
|
|
|
172
|
-
assert len(sys.argv) == 2 # This is always true, but let's assert anyway.
|
|
173
172
|
sys.argv[1] = "--version"
|
|
174
173
|
main()
|
|
175
174
|
|
|
176
175
|
|
|
177
176
|
@main.command("docs")
|
|
178
|
-
def main_docs():
|
|
177
|
+
def main_docs() -> None:
|
|
179
178
|
"""Show help in browser."""
|
|
180
179
|
click.echo("Showing help page in browser...")
|
|
181
180
|
from streamlit import cli_util
|
|
@@ -185,11 +184,10 @@ def main_docs():
|
|
|
185
184
|
|
|
186
185
|
@main.command("hello")
|
|
187
186
|
@configurator_options
|
|
188
|
-
def main_hello(**kwargs):
|
|
187
|
+
def main_hello(**kwargs: Any) -> None:
|
|
189
188
|
"""Runs the Hello World script."""
|
|
190
189
|
from streamlit.hello import streamlit_app
|
|
191
190
|
|
|
192
|
-
bootstrap.load_config_options(flag_options=kwargs)
|
|
193
191
|
filename = streamlit_app.__file__
|
|
194
192
|
_main_run(filename, flag_options=kwargs)
|
|
195
193
|
|
|
@@ -198,7 +196,7 @@ def main_hello(**kwargs):
|
|
|
198
196
|
@configurator_options
|
|
199
197
|
@click.argument("target", required=True, envvar="STREAMLIT_RUN_TARGET")
|
|
200
198
|
@click.argument("args", nargs=-1)
|
|
201
|
-
def main_run(target: str, args=None, **kwargs):
|
|
199
|
+
def main_run(target: str, args: list[str] | None = None, **kwargs: Any) -> None:
|
|
202
200
|
"""Run a Python script, piping stderr to Streamlit.
|
|
203
201
|
|
|
204
202
|
The script can be local or it can be an url. In the latter case, Streamlit
|
|
@@ -207,18 +205,16 @@ def main_run(target: str, args=None, **kwargs):
|
|
|
207
205
|
"""
|
|
208
206
|
from streamlit import url_util
|
|
209
207
|
|
|
210
|
-
bootstrap.load_config_options(flag_options=kwargs)
|
|
211
|
-
|
|
212
208
|
_, extension = os.path.splitext(target)
|
|
213
209
|
if extension[1:] not in ACCEPTED_FILE_EXTENSIONS:
|
|
214
210
|
if extension[1:] == "":
|
|
215
211
|
raise click.BadArgumentUsage(
|
|
216
|
-
"Streamlit requires raw Python (.py) files, but the provided file has no extension.\
|
|
217
|
-
|
|
218
|
-
else:
|
|
219
|
-
raise click.BadArgumentUsage(
|
|
220
|
-
f"Streamlit requires raw Python (.py) files, not {extension}.\nFor more information, please see https://docs.streamlit.io"
|
|
212
|
+
"Streamlit requires raw Python (.py) files, but the provided file has no extension.\n"
|
|
213
|
+
"For more information, please see https://docs.streamlit.io"
|
|
221
214
|
)
|
|
215
|
+
raise click.BadArgumentUsage(
|
|
216
|
+
f"Streamlit requires raw Python (.py) files, not {extension}.\nFor more information, please see https://docs.streamlit.io"
|
|
217
|
+
)
|
|
222
218
|
|
|
223
219
|
if url_util.is_url(target):
|
|
224
220
|
from streamlit.temporary_directory import TemporaryDirectory
|
|
@@ -259,10 +255,16 @@ def _get_command_line_as_string() -> str | None:
|
|
|
259
255
|
|
|
260
256
|
|
|
261
257
|
def _main_run(
|
|
262
|
-
file,
|
|
258
|
+
file: str,
|
|
263
259
|
args: list[str] | None = None,
|
|
264
260
|
flag_options: dict[str, Any] | None = None,
|
|
265
261
|
) -> None:
|
|
262
|
+
# Set the main script path to use it for config & secret files
|
|
263
|
+
# While its a bit suboptimal, we need to store this into a module-level
|
|
264
|
+
# variable before we load the config options via `load_config_options`
|
|
265
|
+
_config._main_script_path = os.path.abspath(file)
|
|
266
|
+
|
|
267
|
+
bootstrap.load_config_options(flag_options=flag_options or {})
|
|
266
268
|
if args is None:
|
|
267
269
|
args = []
|
|
268
270
|
|
|
@@ -276,17 +278,17 @@ def _main_run(
|
|
|
276
278
|
bootstrap.run(file, is_hello, args, flag_options)
|
|
277
279
|
|
|
278
280
|
|
|
279
|
-
# SUBCOMMAND
|
|
281
|
+
# SUBCOMMAND cache
|
|
280
282
|
|
|
281
283
|
|
|
282
284
|
@main.group("cache")
|
|
283
|
-
def cache():
|
|
285
|
+
def cache() -> None:
|
|
284
286
|
"""Manage the Streamlit cache."""
|
|
285
287
|
pass
|
|
286
288
|
|
|
287
289
|
|
|
288
290
|
@cache.command("clear")
|
|
289
|
-
def cache_clear():
|
|
291
|
+
def cache_clear() -> None:
|
|
290
292
|
"""Clear st.cache_data and st.cache_resource caches."""
|
|
291
293
|
|
|
292
294
|
# in this `streamlit cache clear` cli command we cannot use the
|
|
@@ -299,18 +301,18 @@ def cache_clear():
|
|
|
299
301
|
caching.cache_resource.clear()
|
|
300
302
|
|
|
301
303
|
|
|
302
|
-
# SUBCOMMAND
|
|
304
|
+
# SUBCOMMAND config
|
|
303
305
|
|
|
304
306
|
|
|
305
307
|
@main.group("config")
|
|
306
|
-
def config():
|
|
308
|
+
def config() -> None:
|
|
307
309
|
"""Manage Streamlit's config settings."""
|
|
308
310
|
pass
|
|
309
311
|
|
|
310
312
|
|
|
311
313
|
@config.command("show")
|
|
312
314
|
@configurator_options
|
|
313
|
-
def config_show(**kwargs):
|
|
315
|
+
def config_show(**kwargs: Any) -> None:
|
|
314
316
|
"""Show all of Streamlit's config settings."""
|
|
315
317
|
|
|
316
318
|
bootstrap.load_config_options(flag_options=kwargs)
|
|
@@ -318,28 +320,28 @@ def config_show(**kwargs):
|
|
|
318
320
|
_config.show_config()
|
|
319
321
|
|
|
320
322
|
|
|
321
|
-
# SUBCOMMAND
|
|
323
|
+
# SUBCOMMAND activate
|
|
322
324
|
|
|
323
325
|
|
|
324
326
|
@main.group("activate", invoke_without_command=True)
|
|
325
327
|
@click.pass_context
|
|
326
|
-
def activate(ctx):
|
|
328
|
+
def activate(ctx: click.Context) -> None:
|
|
327
329
|
"""Activate Streamlit by entering your email."""
|
|
328
330
|
if not ctx.invoked_subcommand:
|
|
329
331
|
Credentials.get_current().activate()
|
|
330
332
|
|
|
331
333
|
|
|
332
334
|
@activate.command("reset")
|
|
333
|
-
def activate_reset():
|
|
335
|
+
def activate_reset() -> None:
|
|
334
336
|
"""Reset Activation Credentials."""
|
|
335
337
|
Credentials.get_current().reset()
|
|
336
338
|
|
|
337
339
|
|
|
338
|
-
# SUBCOMMAND
|
|
340
|
+
# SUBCOMMAND test
|
|
339
341
|
|
|
340
342
|
|
|
341
343
|
@main.group("test", hidden=True)
|
|
342
|
-
def test():
|
|
344
|
+
def test() -> None:
|
|
343
345
|
"""Internal-only commands used for testing.
|
|
344
346
|
|
|
345
347
|
These commands are not included in the output of `streamlit help`.
|
|
@@ -348,7 +350,7 @@ def test():
|
|
|
348
350
|
|
|
349
351
|
|
|
350
352
|
@test.command("prog_name")
|
|
351
|
-
def test_prog_name():
|
|
353
|
+
def test_prog_name() -> None:
|
|
352
354
|
"""Assert that the program name is set to `streamlit test`.
|
|
353
355
|
|
|
354
356
|
This is used by our cli-smoke-tests to verify that the program name is set
|
|
@@ -361,13 +363,18 @@ def test_prog_name():
|
|
|
361
363
|
|
|
362
364
|
parent = click.get_current_context().parent
|
|
363
365
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
+
if parent is None:
|
|
367
|
+
raise AssertionError("parent is None")
|
|
368
|
+
|
|
369
|
+
if parent.command_path != "streamlit test":
|
|
370
|
+
raise AssertionError(
|
|
371
|
+
f"Parent command path is {parent.command_path} not streamlit test."
|
|
372
|
+
)
|
|
366
373
|
|
|
367
374
|
|
|
368
375
|
@main.command("init")
|
|
369
376
|
@click.argument("directory", required=False)
|
|
370
|
-
def main_init(directory: str | None = None):
|
|
377
|
+
def main_init(directory: str | None = None) -> None:
|
|
371
378
|
"""Initialize a new Streamlit project.
|
|
372
379
|
|
|
373
380
|
If DIRECTORY is specified, create it and initialize the project there.
|
streamlit/web/server/__init__.py
CHANGED
|
@@ -13,14 +13,18 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from streamlit.web.server.component_request_handler import ComponentRequestHandler
|
|
16
|
-
from streamlit.web.server.routes import
|
|
16
|
+
from streamlit.web.server.routes import (
|
|
17
|
+
allow_all_cross_origin_requests,
|
|
18
|
+
is_allowed_origin,
|
|
19
|
+
)
|
|
17
20
|
from streamlit.web.server.server import Server, server_address_is_unix_socket
|
|
18
21
|
from streamlit.web.server.stats_request_handler import StatsRequestHandler
|
|
19
22
|
|
|
20
23
|
__all__ = [
|
|
21
24
|
"ComponentRequestHandler",
|
|
22
|
-
"allow_cross_origin_requests",
|
|
23
25
|
"Server",
|
|
24
|
-
"server_address_is_unix_socket",
|
|
25
26
|
"StatsRequestHandler",
|
|
27
|
+
"allow_all_cross_origin_requests",
|
|
28
|
+
"is_allowed_origin",
|
|
29
|
+
"server_address_is_unix_socket",
|
|
26
30
|
]
|
|
@@ -82,7 +82,7 @@ class AppStaticFileHandler(tornado.web.StaticFileHandler):
|
|
|
82
82
|
|
|
83
83
|
return ret_val
|
|
84
84
|
|
|
85
|
-
def set_default_headers(self):
|
|
85
|
+
def set_default_headers(self) -> None:
|
|
86
86
|
# CORS protection is disabled because we need access to this endpoint
|
|
87
87
|
# from the inner iframe.
|
|
88
88
|
self.set_header("Access-Control-Allow-Origin", "*")
|
|
@@ -16,7 +16,7 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
from typing import TYPE_CHECKING, Any
|
|
18
18
|
|
|
19
|
-
from authlib.integrations.base_client import (
|
|
19
|
+
from authlib.integrations.base_client import (
|
|
20
20
|
FrameworkIntegration,
|
|
21
21
|
)
|
|
22
22
|
|
|
@@ -28,15 +28,20 @@ if TYPE_CHECKING:
|
|
|
28
28
|
from streamlit.web.server.oidc_mixin import TornadoOAuth
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class TornadoIntegration(FrameworkIntegration):
|
|
32
|
-
def update_token(
|
|
31
|
+
class TornadoIntegration(FrameworkIntegration):
|
|
32
|
+
def update_token(
|
|
33
|
+
self,
|
|
34
|
+
token: dict[str, Any],
|
|
35
|
+
refresh_token: dict[str, Any] | None = None,
|
|
36
|
+
access_token: dict[str, Any] | None = None,
|
|
37
|
+
) -> None:
|
|
33
38
|
"""We do not support access token refresh, since we obtain and operate only on
|
|
34
39
|
identity tokens. We override this method explicitly to implement all abstract
|
|
35
40
|
methods of base class.
|
|
36
41
|
"""
|
|
37
42
|
|
|
38
43
|
@staticmethod
|
|
39
|
-
def load_config(
|
|
44
|
+
def load_config( # type: ignore[override]
|
|
40
45
|
oauth: TornadoOAuth, name: str, params: Sequence[str]
|
|
41
46
|
) -> dict[str, Any]:
|
|
42
47
|
"""Configure Authlib integration with provider parameters
|
|
@@ -113,6 +113,12 @@ class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
|
|
|
113
113
|
del cookie_value["is_logged_in"]
|
|
114
114
|
user_info.update(cookie_value)
|
|
115
115
|
|
|
116
|
+
else:
|
|
117
|
+
_LOGGER.error(
|
|
118
|
+
"Origin mismatch, the origin of websocket request is not the "
|
|
119
|
+
"same origin of redirect_uri in secrets.toml",
|
|
120
|
+
)
|
|
121
|
+
|
|
116
122
|
return user_info
|
|
117
123
|
|
|
118
124
|
def write_forward_msg(self, msg: ForwardMsg) -> None:
|
|
@@ -148,7 +154,7 @@ class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
|
|
|
148
154
|
|
|
149
155
|
return None
|
|
150
156
|
|
|
151
|
-
def open(self, *args, **kwargs) -> Awaitable[None] | None:
|
|
157
|
+
def open(self, *args: Any, **kwargs: Any) -> Awaitable[None] | None:
|
|
152
158
|
user_info: dict[str, str | bool | None] = {}
|
|
153
159
|
|
|
154
160
|
existing_session_id = None
|
|
@@ -207,7 +213,7 @@ class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
|
|
|
207
213
|
if isinstance(payload, str):
|
|
208
214
|
# Sanity check. (The frontend should only be sending us bytes;
|
|
209
215
|
# Protobuf.ParseFromString does not accept str input.)
|
|
210
|
-
raise
|
|
216
|
+
raise TypeError( # noqa: TRY301
|
|
211
217
|
"WebSocket received an unexpected `str` message. "
|
|
212
218
|
"(We expect `bytes` only.)"
|
|
213
219
|
)
|
|
@@ -16,7 +16,7 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
import mimetypes
|
|
18
18
|
import os
|
|
19
|
-
from typing import TYPE_CHECKING, Final
|
|
19
|
+
from typing import TYPE_CHECKING, Final, cast
|
|
20
20
|
|
|
21
21
|
import tornado.web
|
|
22
22
|
|
|
@@ -30,7 +30,7 @@ _LOGGER: Final = get_logger(__name__)
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class ComponentRequestHandler(tornado.web.RequestHandler):
|
|
33
|
-
def initialize(self, registry: BaseComponentRegistry):
|
|
33
|
+
def initialize(self, registry: BaseComponentRegistry) -> None:
|
|
34
34
|
self._registry = registry
|
|
35
35
|
|
|
36
36
|
def get(self, path: str) -> None:
|
|
@@ -55,9 +55,10 @@ class ComponentRequestHandler(tornado.web.RequestHandler):
|
|
|
55
55
|
try:
|
|
56
56
|
with open(abspath, "rb") as file:
|
|
57
57
|
contents = file.read()
|
|
58
|
-
except OSError
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
except OSError:
|
|
59
|
+
sanitized_abspath = abspath.replace("\n", "").replace("\r", "")
|
|
60
|
+
_LOGGER.exception(
|
|
61
|
+
"ComponentRequestHandler: GET %s read error", sanitized_abspath
|
|
61
62
|
)
|
|
62
63
|
self.write("read error")
|
|
63
64
|
self.set_status(404)
|
|
@@ -82,8 +83,12 @@ class ComponentRequestHandler(tornado.web.RequestHandler):
|
|
|
82
83
|
self.set_header("Cache-Control", "public")
|
|
83
84
|
|
|
84
85
|
def set_default_headers(self) -> None:
|
|
85
|
-
if streamlit.web.server.routes.
|
|
86
|
+
if streamlit.web.server.routes.allow_all_cross_origin_requests():
|
|
86
87
|
self.set_header("Access-Control-Allow-Origin", "*")
|
|
88
|
+
elif streamlit.web.server.routes.is_allowed_origin(
|
|
89
|
+
origin := self.request.headers.get("Origin")
|
|
90
|
+
):
|
|
91
|
+
self.set_header("Access-Control-Allow-Origin", cast("str", origin))
|
|
87
92
|
|
|
88
93
|
def options(self) -> None:
|
|
89
94
|
"""/OPTIONS handler for preflight CORS checks."""
|
|
@@ -102,13 +107,12 @@ class ComponentRequestHandler(tornado.web.RequestHandler):
|
|
|
102
107
|
# As of 2015-07-21 there is no bzip2 encoding defined at
|
|
103
108
|
# http://www.iana.org/assignments/media-types/media-types.xhtml
|
|
104
109
|
# So for that (and any other encoding), use octet-stream.
|
|
105
|
-
|
|
110
|
+
if encoding is not None:
|
|
106
111
|
return "application/octet-stream"
|
|
107
|
-
|
|
112
|
+
if mime_type is not None:
|
|
108
113
|
return mime_type
|
|
109
114
|
# if mime_type not detected, use application/octet-stream
|
|
110
|
-
|
|
111
|
-
return "application/octet-stream"
|
|
115
|
+
return "application/octet-stream"
|
|
112
116
|
|
|
113
117
|
@staticmethod
|
|
114
118
|
def get_url(file_id: str) -> str:
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
+
from typing import Any, cast
|
|
17
18
|
from urllib.parse import quote
|
|
18
19
|
|
|
19
20
|
import tornado.web
|
|
@@ -24,7 +25,7 @@ from streamlit.runtime.memory_media_file_storage import (
|
|
|
24
25
|
MemoryMediaFileStorage,
|
|
25
26
|
get_extension_for_mimetype,
|
|
26
27
|
)
|
|
27
|
-
from streamlit.web.server import
|
|
28
|
+
from streamlit.web.server import allow_all_cross_origin_requests, is_allowed_origin
|
|
28
29
|
|
|
29
30
|
_LOGGER = get_logger(__name__)
|
|
30
31
|
|
|
@@ -43,8 +44,10 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
|
|
|
43
44
|
cls._storage = storage
|
|
44
45
|
|
|
45
46
|
def set_default_headers(self) -> None:
|
|
46
|
-
if
|
|
47
|
+
if allow_all_cross_origin_requests():
|
|
47
48
|
self.set_header("Access-Control-Allow-Origin", "*")
|
|
49
|
+
elif is_allowed_origin(origin := self.request.headers.get("Origin")):
|
|
50
|
+
self.set_header("Access-Control-Allow-Origin", cast("str", origin))
|
|
48
51
|
|
|
49
52
|
def set_extra_headers(self, path: str) -> None:
|
|
50
53
|
"""Add Content-Disposition header for downloadable files.
|
|
@@ -83,11 +86,15 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
|
|
|
83
86
|
# static content from a database), override `get_content`,
|
|
84
87
|
# `get_content_size`, `get_modified_time`, `get_absolute_path`, and
|
|
85
88
|
# `validate_absolute_path`.
|
|
86
|
-
def validate_absolute_path(
|
|
89
|
+
def validate_absolute_path(
|
|
90
|
+
self,
|
|
91
|
+
root: str, # noqa: ARG002
|
|
92
|
+
absolute_path: str,
|
|
93
|
+
) -> str:
|
|
87
94
|
try:
|
|
88
95
|
self._storage.get_file(absolute_path)
|
|
89
96
|
except MediaFileStorageError:
|
|
90
|
-
_LOGGER.
|
|
97
|
+
_LOGGER.exception("MediaFileHandler: Missing file %s", absolute_path)
|
|
91
98
|
raise tornado.web.HTTPError(404, "not found")
|
|
92
99
|
|
|
93
100
|
return absolute_path
|
|
@@ -106,7 +113,7 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
|
|
|
106
113
|
return None
|
|
107
114
|
|
|
108
115
|
@classmethod
|
|
109
|
-
def get_absolute_path(cls, root: str, path: str) -> str:
|
|
116
|
+
def get_absolute_path(cls, root: str, path: str) -> str: # noqa: ARG003
|
|
110
117
|
# All files are stored in memory, so the absolute path is just the
|
|
111
118
|
# path itself. In the MediaFileHandler, it's just the filename
|
|
112
119
|
return path
|
|
@@ -114,14 +121,14 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
|
|
|
114
121
|
@classmethod
|
|
115
122
|
def get_content(
|
|
116
123
|
cls, abspath: str, start: int | None = None, end: int | None = None
|
|
117
|
-
):
|
|
124
|
+
) -> Any:
|
|
118
125
|
_LOGGER.debug("MediaFileHandler: GET %s", abspath)
|
|
119
126
|
|
|
120
127
|
try:
|
|
121
128
|
# abspath is the hash as used `get_absolute_path`
|
|
122
129
|
media_file = cls._storage.get_file(abspath)
|
|
123
130
|
except Exception:
|
|
124
|
-
_LOGGER.
|
|
131
|
+
_LOGGER.exception("MediaFileHandler: Missing file %s", abspath)
|
|
125
132
|
return None
|
|
126
133
|
|
|
127
134
|
_LOGGER.debug(
|