streamlit-nightly 1.43.2.dev20250307__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 +306 -0
- streamlit/__main__.py +20 -0
- streamlit/auth_util.py +218 -0
- streamlit/cli_util.py +105 -0
- streamlit/column_config.py +56 -0
- streamlit/commands/__init__.py +13 -0
- streamlit/commands/echo.py +126 -0
- streamlit/commands/execution_control.py +238 -0
- streamlit/commands/experimental_query_params.py +169 -0
- streamlit/commands/logo.py +189 -0
- streamlit/commands/navigation.py +385 -0
- streamlit/commands/page_config.py +311 -0
- streamlit/components/__init__.py +13 -0
- streamlit/components/lib/__init__.py +13 -0
- streamlit/components/lib/local_component_registry.py +84 -0
- streamlit/components/types/__init__.py +13 -0
- streamlit/components/types/base_component_registry.py +99 -0
- streamlit/components/types/base_custom_component.py +150 -0
- streamlit/components/v1/__init__.py +31 -0
- streamlit/components/v1/component_arrow.py +141 -0
- streamlit/components/v1/component_registry.py +130 -0
- streamlit/components/v1/components.py +38 -0
- streamlit/components/v1/custom_component.py +243 -0
- streamlit/config.py +1513 -0
- streamlit/config_option.py +311 -0
- streamlit/config_util.py +177 -0
- streamlit/connections/__init__.py +28 -0
- streamlit/connections/base_connection.py +174 -0
- streamlit/connections/snowflake_connection.py +562 -0
- streamlit/connections/snowpark_connection.py +213 -0
- streamlit/connections/sql_connection.py +425 -0
- streamlit/connections/util.py +97 -0
- streamlit/cursor.py +210 -0
- streamlit/dataframe_util.py +1416 -0
- streamlit/delta_generator.py +602 -0
- streamlit/delta_generator_singletons.py +204 -0
- streamlit/deprecation_util.py +209 -0
- streamlit/development.py +21 -0
- streamlit/elements/__init__.py +13 -0
- streamlit/elements/alert.py +234 -0
- streamlit/elements/arrow.py +962 -0
- streamlit/elements/balloons.py +47 -0
- streamlit/elements/bokeh_chart.py +133 -0
- streamlit/elements/code.py +114 -0
- streamlit/elements/deck_gl_json_chart.py +546 -0
- streamlit/elements/dialog_decorator.py +267 -0
- streamlit/elements/doc_string.py +558 -0
- streamlit/elements/empty.py +130 -0
- streamlit/elements/exception.py +331 -0
- streamlit/elements/form.py +354 -0
- streamlit/elements/graphviz_chart.py +150 -0
- streamlit/elements/heading.py +302 -0
- streamlit/elements/html.py +105 -0
- streamlit/elements/iframe.py +191 -0
- streamlit/elements/image.py +196 -0
- streamlit/elements/json.py +139 -0
- streamlit/elements/layouts.py +879 -0
- streamlit/elements/lib/__init__.py +13 -0
- streamlit/elements/lib/built_in_chart_utils.py +1157 -0
- streamlit/elements/lib/color_util.py +263 -0
- streamlit/elements/lib/column_config_utils.py +542 -0
- streamlit/elements/lib/column_types.py +2188 -0
- streamlit/elements/lib/dialog.py +147 -0
- streamlit/elements/lib/dicttools.py +154 -0
- streamlit/elements/lib/event_utils.py +37 -0
- streamlit/elements/lib/file_uploader_utils.py +66 -0
- streamlit/elements/lib/form_utils.py +77 -0
- streamlit/elements/lib/image_utils.py +441 -0
- streamlit/elements/lib/js_number.py +105 -0
- streamlit/elements/lib/mutable_status_container.py +183 -0
- streamlit/elements/lib/options_selector_utils.py +250 -0
- streamlit/elements/lib/pandas_styler_utils.py +274 -0
- streamlit/elements/lib/policies.py +194 -0
- streamlit/elements/lib/streamlit_plotly_theme.py +207 -0
- streamlit/elements/lib/subtitle_utils.py +176 -0
- streamlit/elements/lib/utils.py +250 -0
- streamlit/elements/map.py +508 -0
- streamlit/elements/markdown.py +277 -0
- streamlit/elements/media.py +793 -0
- streamlit/elements/metric.py +301 -0
- streamlit/elements/plotly_chart.py +546 -0
- streamlit/elements/progress.py +156 -0
- streamlit/elements/pyplot.py +194 -0
- streamlit/elements/snow.py +47 -0
- streamlit/elements/spinner.py +113 -0
- streamlit/elements/text.py +76 -0
- streamlit/elements/toast.py +98 -0
- streamlit/elements/vega_charts.py +1984 -0
- streamlit/elements/widgets/__init__.py +13 -0
- streamlit/elements/widgets/audio_input.py +310 -0
- streamlit/elements/widgets/button.py +1123 -0
- streamlit/elements/widgets/button_group.py +1008 -0
- streamlit/elements/widgets/camera_input.py +263 -0
- streamlit/elements/widgets/chat.py +647 -0
- streamlit/elements/widgets/checkbox.py +352 -0
- streamlit/elements/widgets/color_picker.py +265 -0
- streamlit/elements/widgets/data_editor.py +983 -0
- streamlit/elements/widgets/file_uploader.py +486 -0
- streamlit/elements/widgets/multiselect.py +338 -0
- streamlit/elements/widgets/number_input.py +545 -0
- streamlit/elements/widgets/radio.py +407 -0
- streamlit/elements/widgets/select_slider.py +437 -0
- streamlit/elements/widgets/selectbox.py +366 -0
- streamlit/elements/widgets/slider.py +880 -0
- streamlit/elements/widgets/text_widgets.py +628 -0
- streamlit/elements/widgets/time_widgets.py +970 -0
- streamlit/elements/write.py +574 -0
- streamlit/emojis.py +34 -0
- streamlit/env_util.py +61 -0
- streamlit/error_util.py +105 -0
- streamlit/errors.py +452 -0
- streamlit/external/__init__.py +13 -0
- streamlit/external/langchain/__init__.py +23 -0
- streamlit/external/langchain/streamlit_callback_handler.py +406 -0
- streamlit/file_util.py +247 -0
- streamlit/git_util.py +173 -0
- streamlit/hello/__init__.py +13 -0
- streamlit/hello/animation_demo.py +82 -0
- streamlit/hello/dataframe_demo.py +71 -0
- streamlit/hello/hello.py +37 -0
- streamlit/hello/mapping_demo.py +114 -0
- streamlit/hello/plotting_demo.py +55 -0
- streamlit/hello/streamlit_app.py +55 -0
- streamlit/hello/utils.py +28 -0
- streamlit/logger.py +130 -0
- streamlit/material_icon_names.py +25 -0
- streamlit/navigation/__init__.py +13 -0
- streamlit/navigation/page.py +302 -0
- streamlit/net_util.py +125 -0
- streamlit/platform.py +33 -0
- streamlit/proto/Alert_pb2.py +29 -0
- streamlit/proto/Alert_pb2.pyi +90 -0
- streamlit/proto/AppPage_pb2.py +27 -0
- streamlit/proto/AppPage_pb2.pyi +64 -0
- streamlit/proto/ArrowNamedDataSet_pb2.py +28 -0
- streamlit/proto/ArrowNamedDataSet_pb2.pyi +57 -0
- streamlit/proto/ArrowVegaLiteChart_pb2.py +29 -0
- streamlit/proto/ArrowVegaLiteChart_pb2.pyi +84 -0
- streamlit/proto/Arrow_pb2.py +33 -0
- streamlit/proto/Arrow_pb2.pyi +188 -0
- streamlit/proto/AudioInput_pb2.py +28 -0
- streamlit/proto/AudioInput_pb2.pyi +58 -0
- streamlit/proto/Audio_pb2.py +27 -0
- streamlit/proto/Audio_pb2.pyi +58 -0
- streamlit/proto/AuthRedirect_pb2.py +27 -0
- streamlit/proto/AuthRedirect_pb2.pyi +41 -0
- streamlit/proto/AutoRerun_pb2.py +27 -0
- streamlit/proto/AutoRerun_pb2.pyi +45 -0
- streamlit/proto/BackMsg_pb2.py +29 -0
- streamlit/proto/BackMsg_pb2.pyi +105 -0
- streamlit/proto/Balloons_pb2.py +27 -0
- streamlit/proto/Balloons_pb2.pyi +43 -0
- streamlit/proto/Block_pb2.py +53 -0
- streamlit/proto/Block_pb2.pyi +322 -0
- streamlit/proto/BokehChart_pb2.py +27 -0
- streamlit/proto/BokehChart_pb2.pyi +49 -0
- streamlit/proto/ButtonGroup_pb2.py +36 -0
- streamlit/proto/ButtonGroup_pb2.pyi +169 -0
- streamlit/proto/Button_pb2.py +27 -0
- streamlit/proto/Button_pb2.pyi +71 -0
- streamlit/proto/CameraInput_pb2.py +28 -0
- streamlit/proto/CameraInput_pb2.pyi +58 -0
- streamlit/proto/ChatInput_pb2.py +31 -0
- streamlit/proto/ChatInput_pb2.pyi +111 -0
- streamlit/proto/Checkbox_pb2.py +30 -0
- streamlit/proto/Checkbox_pb2.pyi +90 -0
- streamlit/proto/ClientState_pb2.py +30 -0
- streamlit/proto/ClientState_pb2.pyi +90 -0
- streamlit/proto/Code_pb2.py +27 -0
- streamlit/proto/Code_pb2.pyi +55 -0
- streamlit/proto/ColorPicker_pb2.py +28 -0
- streamlit/proto/ColorPicker_pb2.pyi +67 -0
- streamlit/proto/Common_pb2.py +51 -0
- streamlit/proto/Common_pb2.pyi +293 -0
- streamlit/proto/Components_pb2.py +35 -0
- streamlit/proto/Components_pb2.pyi +172 -0
- streamlit/proto/DataFrame_pb2.py +56 -0
- streamlit/proto/DataFrame_pb2.pyi +397 -0
- streamlit/proto/DateInput_pb2.py +28 -0
- streamlit/proto/DateInput_pb2.pyi +83 -0
- streamlit/proto/DeckGlJsonChart_pb2.py +29 -0
- streamlit/proto/DeckGlJsonChart_pb2.pyi +102 -0
- streamlit/proto/Delta_pb2.py +31 -0
- streamlit/proto/Delta_pb2.pyi +74 -0
- streamlit/proto/DocString_pb2.py +29 -0
- streamlit/proto/DocString_pb2.pyi +93 -0
- streamlit/proto/DownloadButton_pb2.py +27 -0
- streamlit/proto/DownloadButton_pb2.pyi +70 -0
- streamlit/proto/Element_pb2.py +78 -0
- streamlit/proto/Element_pb2.pyi +312 -0
- streamlit/proto/Empty_pb2.py +27 -0
- streamlit/proto/Empty_pb2.pyi +36 -0
- streamlit/proto/Exception_pb2.py +27 -0
- streamlit/proto/Exception_pb2.pyi +72 -0
- streamlit/proto/Favicon_pb2.py +27 -0
- streamlit/proto/Favicon_pb2.pyi +40 -0
- streamlit/proto/FileUploader_pb2.py +28 -0
- streamlit/proto/FileUploader_pb2.pyi +78 -0
- streamlit/proto/ForwardMsg_pb2.py +53 -0
- streamlit/proto/ForwardMsg_pb2.pyi +293 -0
- streamlit/proto/GitInfo_pb2.py +29 -0
- streamlit/proto/GitInfo_pb2.pyi +83 -0
- streamlit/proto/GraphVizChart_pb2.py +27 -0
- streamlit/proto/GraphVizChart_pb2.pyi +53 -0
- streamlit/proto/Heading_pb2.py +27 -0
- streamlit/proto/Heading_pb2.pyi +56 -0
- streamlit/proto/Html_pb2.py +27 -0
- streamlit/proto/Html_pb2.pyi +42 -0
- streamlit/proto/IFrame_pb2.py +27 -0
- streamlit/proto/IFrame_pb2.pyi +59 -0
- streamlit/proto/Image_pb2.py +29 -0
- streamlit/proto/Image_pb2.pyi +84 -0
- streamlit/proto/Json_pb2.py +27 -0
- streamlit/proto/Json_pb2.pyi +53 -0
- streamlit/proto/LabelVisibilityMessage_pb2.py +29 -0
- streamlit/proto/LabelVisibilityMessage_pb2.pyi +68 -0
- streamlit/proto/LinkButton_pb2.py +27 -0
- streamlit/proto/LinkButton_pb2.pyi +58 -0
- streamlit/proto/Logo_pb2.py +27 -0
- streamlit/proto/Logo_pb2.pyi +51 -0
- streamlit/proto/Markdown_pb2.py +29 -0
- streamlit/proto/Markdown_pb2.pyi +86 -0
- streamlit/proto/Metric_pb2.py +32 -0
- streamlit/proto/Metric_pb2.pyi +101 -0
- streamlit/proto/MetricsEvent_pb2.py +30 -0
- streamlit/proto/MetricsEvent_pb2.pyi +200 -0
- streamlit/proto/MultiSelect_pb2.py +28 -0
- streamlit/proto/MultiSelect_pb2.pyi +81 -0
- streamlit/proto/NamedDataSet_pb2.py +28 -0
- streamlit/proto/NamedDataSet_pb2.pyi +59 -0
- streamlit/proto/Navigation_pb2.py +30 -0
- streamlit/proto/Navigation_pb2.pyi +84 -0
- streamlit/proto/NewSession_pb2.py +51 -0
- streamlit/proto/NewSession_pb2.pyi +481 -0
- streamlit/proto/NumberInput_pb2.py +30 -0
- streamlit/proto/NumberInput_pb2.pyi +121 -0
- streamlit/proto/PageConfig_pb2.py +33 -0
- streamlit/proto/PageConfig_pb2.pyi +126 -0
- streamlit/proto/PageInfo_pb2.py +27 -0
- streamlit/proto/PageInfo_pb2.pyi +43 -0
- streamlit/proto/PageLink_pb2.py +27 -0
- streamlit/proto/PageLink_pb2.pyi +63 -0
- streamlit/proto/PageNotFound_pb2.py +27 -0
- streamlit/proto/PageNotFound_pb2.pyi +42 -0
- streamlit/proto/PageProfile_pb2.py +31 -0
- streamlit/proto/PageProfile_pb2.pyi +127 -0
- streamlit/proto/PagesChanged_pb2.py +28 -0
- streamlit/proto/PagesChanged_pb2.pyi +48 -0
- streamlit/proto/ParentMessage_pb2.py +27 -0
- streamlit/proto/ParentMessage_pb2.pyi +46 -0
- streamlit/proto/PlotlyChart_pb2.py +31 -0
- streamlit/proto/PlotlyChart_pb2.pyi +131 -0
- streamlit/proto/Progress_pb2.py +27 -0
- streamlit/proto/Progress_pb2.pyi +43 -0
- streamlit/proto/Radio_pb2.py +28 -0
- streamlit/proto/Radio_pb2.pyi +84 -0
- streamlit/proto/RootContainer_pb2.py +27 -0
- streamlit/proto/RootContainer_pb2.pyi +56 -0
- streamlit/proto/Selectbox_pb2.py +28 -0
- streamlit/proto/Selectbox_pb2.pyi +80 -0
- streamlit/proto/SessionEvent_pb2.py +28 -0
- streamlit/proto/SessionEvent_pb2.pyi +62 -0
- streamlit/proto/SessionStatus_pb2.py +27 -0
- streamlit/proto/SessionStatus_pb2.pyi +57 -0
- streamlit/proto/Skeleton_pb2.py +29 -0
- streamlit/proto/Skeleton_pb2.pyi +71 -0
- streamlit/proto/Slider_pb2.py +32 -0
- streamlit/proto/Slider_pb2.pyi +142 -0
- streamlit/proto/Snow_pb2.py +27 -0
- streamlit/proto/Snow_pb2.pyi +43 -0
- streamlit/proto/Spinner_pb2.py +27 -0
- streamlit/proto/Spinner_pb2.pyi +49 -0
- streamlit/proto/TextArea_pb2.py +28 -0
- streamlit/proto/TextArea_pb2.pyi +80 -0
- streamlit/proto/TextInput_pb2.py +30 -0
- streamlit/proto/TextInput_pb2.pyi +107 -0
- streamlit/proto/Text_pb2.py +27 -0
- streamlit/proto/Text_pb2.pyi +46 -0
- streamlit/proto/TimeInput_pb2.py +28 -0
- streamlit/proto/TimeInput_pb2.pyi +74 -0
- streamlit/proto/Toast_pb2.py +27 -0
- streamlit/proto/Toast_pb2.pyi +45 -0
- streamlit/proto/VegaLiteChart_pb2.py +29 -0
- streamlit/proto/VegaLiteChart_pb2.pyi +71 -0
- streamlit/proto/Video_pb2.py +31 -0
- streamlit/proto/Video_pb2.pyi +117 -0
- streamlit/proto/WidgetStates_pb2.py +31 -0
- streamlit/proto/WidgetStates_pb2.pyi +126 -0
- streamlit/proto/__init__.py +15 -0
- streamlit/proto/openmetrics_data_model_pb2.py +60 -0
- streamlit/proto/openmetrics_data_model_pb2.pyi +522 -0
- streamlit/py.typed +0 -0
- streamlit/runtime/__init__.py +50 -0
- streamlit/runtime/app_session.py +982 -0
- streamlit/runtime/caching/__init__.py +98 -0
- streamlit/runtime/caching/cache_data_api.py +665 -0
- streamlit/runtime/caching/cache_errors.py +142 -0
- streamlit/runtime/caching/cache_resource_api.py +527 -0
- streamlit/runtime/caching/cache_type.py +33 -0
- streamlit/runtime/caching/cache_utils.py +523 -0
- streamlit/runtime/caching/cached_message_replay.py +290 -0
- streamlit/runtime/caching/hashing.py +637 -0
- streamlit/runtime/caching/legacy_cache_api.py +169 -0
- streamlit/runtime/caching/storage/__init__.py +29 -0
- streamlit/runtime/caching/storage/cache_storage_protocol.py +239 -0
- streamlit/runtime/caching/storage/dummy_cache_storage.py +60 -0
- streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +145 -0
- streamlit/runtime/caching/storage/local_disk_cache_storage.py +223 -0
- streamlit/runtime/connection_factory.py +436 -0
- streamlit/runtime/context.py +280 -0
- streamlit/runtime/credentials.py +364 -0
- streamlit/runtime/forward_msg_cache.py +296 -0
- streamlit/runtime/forward_msg_queue.py +240 -0
- streamlit/runtime/fragment.py +477 -0
- streamlit/runtime/media_file_manager.py +234 -0
- streamlit/runtime/media_file_storage.py +143 -0
- streamlit/runtime/memory_media_file_storage.py +181 -0
- streamlit/runtime/memory_session_storage.py +77 -0
- streamlit/runtime/memory_uploaded_file_manager.py +138 -0
- streamlit/runtime/metrics_util.py +486 -0
- streamlit/runtime/pages_manager.py +165 -0
- streamlit/runtime/runtime.py +792 -0
- streamlit/runtime/runtime_util.py +106 -0
- streamlit/runtime/script_data.py +46 -0
- streamlit/runtime/scriptrunner/__init__.py +38 -0
- streamlit/runtime/scriptrunner/exec_code.py +159 -0
- streamlit/runtime/scriptrunner/magic.py +273 -0
- streamlit/runtime/scriptrunner/magic_funcs.py +32 -0
- streamlit/runtime/scriptrunner/script_cache.py +89 -0
- streamlit/runtime/scriptrunner/script_runner.py +756 -0
- streamlit/runtime/scriptrunner_utils/__init__.py +19 -0
- streamlit/runtime/scriptrunner_utils/exceptions.py +48 -0
- streamlit/runtime/scriptrunner_utils/script_requests.py +307 -0
- streamlit/runtime/scriptrunner_utils/script_run_context.py +287 -0
- streamlit/runtime/secrets.py +534 -0
- streamlit/runtime/session_manager.py +394 -0
- streamlit/runtime/state/__init__.py +41 -0
- streamlit/runtime/state/common.py +191 -0
- streamlit/runtime/state/query_params.py +205 -0
- streamlit/runtime/state/query_params_proxy.py +218 -0
- streamlit/runtime/state/safe_session_state.py +138 -0
- streamlit/runtime/state/session_state.py +772 -0
- streamlit/runtime/state/session_state_proxy.py +153 -0
- streamlit/runtime/state/widgets.py +135 -0
- streamlit/runtime/stats.py +109 -0
- streamlit/runtime/uploaded_file_manager.py +148 -0
- streamlit/runtime/websocket_session_manager.py +167 -0
- streamlit/source_util.py +98 -0
- streamlit/static/favicon.png +0 -0
- streamlit/static/index.html +61 -0
- streamlit/static/static/css/index.Bmkmz40k.css +1 -0
- streamlit/static/static/css/index.DpJG_94W.css +1 -0
- streamlit/static/static/css/index.DzuxGC_t.css +1 -0
- streamlit/static/static/js/FileDownload.esm.Bp9m5jrx.js +1 -0
- streamlit/static/static/js/FileHelper.D_3pbilj.js +5 -0
- streamlit/static/static/js/FormClearHelper.Ct2rwLXo.js +1 -0
- streamlit/static/static/js/Hooks.BKdzj5MJ.js +1 -0
- streamlit/static/static/js/InputInstructions.DB3QGNJP.js +1 -0
- streamlit/static/static/js/ProgressBar.D40A5xc2.js +2 -0
- streamlit/static/static/js/RenderInPortalIfExists.DLUCooTN.js +1 -0
- streamlit/static/static/js/Toolbar.BiGGIQun.js +1 -0
- streamlit/static/static/js/UploadFileInfo.C-jY39rj.js +1 -0
- streamlit/static/static/js/base-input.CQBQT24M.js +4 -0
- streamlit/static/static/js/checkbox.Buj8gd_M.js +9 -0
- streamlit/static/static/js/createDownloadLinkElement.DZMwyjvU.js +1 -0
- streamlit/static/static/js/createSuper.CesK3I23.js +1 -0
- streamlit/static/static/js/data-grid-overlay-editor.B69OOFM4.js +1 -0
- streamlit/static/static/js/downloader.BZQhlBNT.js +1 -0
- streamlit/static/static/js/es6.D9Zhqujy.js +2 -0
- streamlit/static/static/js/iframeResizer.contentWindow.CAzcBpCC.js +1 -0
- streamlit/static/static/js/index.08vcOOvb.js +1 -0
- streamlit/static/static/js/index.0uqKfJUS.js +1 -0
- streamlit/static/static/js/index.B02M5u69.js +203 -0
- streamlit/static/static/js/index.B7mcZKMx.js +1 -0
- streamlit/static/static/js/index.BAQDHFA_.js +1 -0
- streamlit/static/static/js/index.BI60cMVr.js +2 -0
- streamlit/static/static/js/index.BLug2inK.js +1 -0
- streamlit/static/static/js/index.BM6TMY8g.js +2 -0
- streamlit/static/static/js/index.BZ9p1t7G.js +1 -0
- streamlit/static/static/js/index.BZqa87a1.js +2 -0
- streamlit/static/static/js/index.BcsRUzZZ.js +1 -0
- streamlit/static/static/js/index.BgVMiY_P.js +197 -0
- streamlit/static/static/js/index.BtuGy7By.js +6 -0
- streamlit/static/static/js/index.BuDuBmrs.js +1 -0
- streamlit/static/static/js/index.BvXU2oKV.js +1 -0
- streamlit/static/static/js/index.BxcwPacT.js +73 -0
- streamlit/static/static/js/index.CWX8KB81.js +1 -0
- streamlit/static/static/js/index.CXzZTo_q.js +1 -0
- streamlit/static/static/js/index.CcRWp_KL.js +1 -0
- streamlit/static/static/js/index.Cd-_xe55.js +3 -0
- streamlit/static/static/js/index.CdG2PXln.js +4537 -0
- streamlit/static/static/js/index.CjXvXmcP.js +1 -0
- streamlit/static/static/js/index.D1HZENZx.js +776 -0
- streamlit/static/static/js/index.D21Efo64.js +1617 -0
- streamlit/static/static/js/index.D9WgGVBx.js +7 -0
- streamlit/static/static/js/index.DEcsHtvb.js +12 -0
- streamlit/static/static/js/index.DFeMfr_K.js +1 -0
- streamlit/static/static/js/index.DHFBoItz.js +1 -0
- streamlit/static/static/js/index.D_PrBKnJ.js +3 -0
- streamlit/static/static/js/index.DmuRkekN.js +3855 -0
- streamlit/static/static/js/index.Do6eY8sf.js +1 -0
- streamlit/static/static/js/index.Dz3lP2P-.js +1 -0
- streamlit/static/static/js/index.Dz_UqF-s.js +1 -0
- streamlit/static/static/js/index.GkSUsPhJ.js +1 -0
- streamlit/static/static/js/index.H1U1IC_d.js +3 -0
- streamlit/static/static/js/index.g6p_4DPr.js +1 -0
- streamlit/static/static/js/index.g9x_GKss.js +1 -0
- streamlit/static/static/js/index.zo9jm08y.js +1 -0
- streamlit/static/static/js/input.DnaFglHq.js +2 -0
- streamlit/static/static/js/inputUtils.CQWz5UKz.js +1 -0
- streamlit/static/static/js/memory.Crb9x4-F.js +1 -0
- streamlit/static/static/js/mergeWith.ouAz0sK3.js +1 -0
- streamlit/static/static/js/number-overlay-editor._UaN-O48.js +9 -0
- streamlit/static/static/js/possibleConstructorReturn.CtGjGFHz.js +1 -0
- streamlit/static/static/js/sandbox.CBybYOhV.js +1 -0
- streamlit/static/static/js/sprintf.D7DtBTRn.js +1 -0
- streamlit/static/static/js/textarea.Cb_uJt5U.js +2 -0
- streamlit/static/static/js/threshold.DjX0wlsa.js +1 -0
- streamlit/static/static/js/timepicker.DKT7pfoF.js +4 -0
- streamlit/static/static/js/timer.CAwTRJ_g.js +1 -0
- streamlit/static/static/js/toConsumableArray.05Ikp13-.js +3 -0
- streamlit/static/static/js/uniqueId.D2FMWUEI.js +1 -0
- streamlit/static/static/js/useBasicWidgetState.urnZLANY.js +1 -0
- streamlit/static/static/js/useOnInputChange.BOKIIdJ1.js +1 -0
- streamlit/static/static/js/value.CgPGBV_l.js +1 -0
- streamlit/static/static/js/withFullScreenWrapper.C_N8J0Xx.js +1 -0
- streamlit/static/static/media/KaTeX_AMS-Regular.BQhdFMY1.woff2 +0 -0
- streamlit/static/static/media/KaTeX_AMS-Regular.DMm9YOAa.woff +0 -0
- streamlit/static/static/media/KaTeX_AMS-Regular.DRggAlZN.ttf +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Bold.ATXxdsX0.ttf +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Bold.BEiXGLvX.woff +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Bold.Dq_IR9rO.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Regular.CTRA-rTL.woff +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Regular.Di6jR-x-.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Caligraphic-Regular.wX97UBjC.ttf +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Bold.BdnERNNW.ttf +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Bold.BsDP51OF.woff +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Bold.CL6g_b3V.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Regular.CB_wures.ttf +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Regular.CTYiF6lA.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Fraktur-Regular.Dxdc4cR9.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Bold.Cx986IdX.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Main-Bold.Jm3AIy58.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Bold.waoOVXN0.ttf +0 -0
- streamlit/static/static/media/KaTeX_Main-BoldItalic.DxDJ3AOS.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Main-BoldItalic.DzxPMmG6.ttf +0 -0
- streamlit/static/static/media/KaTeX_Main-BoldItalic.SpSLRI95.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Italic.3WenGoN9.ttf +0 -0
- streamlit/static/static/media/KaTeX_Main-Italic.BMLOBm91.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Italic.NWA7e6Wa.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Main-Regular.B22Nviop.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Main-Regular.Dr94JaBh.woff +0 -0
- streamlit/static/static/media/KaTeX_Main-Regular.ypZvNtVU.ttf +0 -0
- streamlit/static/static/media/KaTeX_Math-BoldItalic.B3XSjfu4.ttf +0 -0
- streamlit/static/static/media/KaTeX_Math-BoldItalic.CZnvNsCZ.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Math-BoldItalic.iY-2wyZ7.woff +0 -0
- streamlit/static/static/media/KaTeX_Math-Italic.DA0__PXp.woff +0 -0
- streamlit/static/static/media/KaTeX_Math-Italic.flOr_0UB.ttf +0 -0
- streamlit/static/static/media/KaTeX_Math-Italic.t53AETM-.woff2 +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Bold.CFMepnvq.ttf +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Bold.D1sUS0GD.woff2 +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Bold.DbIhKOiC.woff +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Italic.C3H0VqGB.woff2 +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Italic.DN2j7dab.woff +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Italic.YYjJ1zSn.ttf +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Regular.BNo7hRIc.ttf +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Regular.CS6fqUqJ.woff +0 -0
- streamlit/static/static/media/KaTeX_SansSerif-Regular.DDBCnlJ7.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Script-Regular.C5JkGWo-.ttf +0 -0
- streamlit/static/static/media/KaTeX_Script-Regular.D3wIWfF6.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Script-Regular.D5yQViql.woff +0 -0
- streamlit/static/static/media/KaTeX_Size1-Regular.C195tn64.woff +0 -0
- streamlit/static/static/media/KaTeX_Size1-Regular.Dbsnue_I.ttf +0 -0
- streamlit/static/static/media/KaTeX_Size1-Regular.mCD8mA8B.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Size2-Regular.B7gKUWhC.ttf +0 -0
- streamlit/static/static/media/KaTeX_Size2-Regular.Dy4dx90m.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Size2-Regular.oD1tc_U0.woff +0 -0
- streamlit/static/static/media/KaTeX_Size3-Regular.CTq5MqoE.woff +0 -0
- streamlit/static/static/media/KaTeX_Size3-Regular.DgpXs0kz.ttf +0 -0
- streamlit/static/static/media/KaTeX_Size4-Regular.BF-4gkZK.woff +0 -0
- streamlit/static/static/media/KaTeX_Size4-Regular.DWFBv043.ttf +0 -0
- streamlit/static/static/media/KaTeX_Size4-Regular.Dl5lxZxV.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Typewriter-Regular.C0xS9mPB.woff +0 -0
- streamlit/static/static/media/KaTeX_Typewriter-Regular.CO6r4hn1.woff2 +0 -0
- streamlit/static/static/media/KaTeX_Typewriter-Regular.D3Ib7_Hf.ttf +0 -0
- streamlit/static/static/media/MaterialSymbols-Rounded.DcZbplWk.woff2 +0 -0
- 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/static/static/media/balloon-0.Czj7AKwE.png +0 -0
- streamlit/static/static/media/balloon-1.CNvFFrND.png +0 -0
- streamlit/static/static/media/balloon-2.DTvC6B1t.png +0 -0
- streamlit/static/static/media/balloon-3.CgSk4tbL.png +0 -0
- streamlit/static/static/media/balloon-4.mbtFrzxf.png +0 -0
- streamlit/static/static/media/balloon-5.CSwkUfRA.png +0 -0
- streamlit/static/static/media/fireworks.B4d-_KUe.gif +0 -0
- streamlit/static/static/media/flake-0.DgWaVvm5.png +0 -0
- streamlit/static/static/media/flake-1.B2r5AHMK.png +0 -0
- streamlit/static/static/media/flake-2.BnWSExPC.png +0 -0
- streamlit/static/static/media/snowflake.JU2jBHL8.svg +11 -0
- streamlit/string_util.py +203 -0
- streamlit/temporary_directory.py +56 -0
- streamlit/testing/__init__.py +13 -0
- streamlit/testing/v1/__init__.py +17 -0
- streamlit/testing/v1/app_test.py +1050 -0
- streamlit/testing/v1/element_tree.py +2083 -0
- streamlit/testing/v1/local_script_runner.py +180 -0
- streamlit/testing/v1/util.py +53 -0
- streamlit/time_util.py +75 -0
- streamlit/type_util.py +460 -0
- streamlit/url_util.py +122 -0
- streamlit/user_info.py +519 -0
- streamlit/util.py +72 -0
- streamlit/vendor/__init__.py +0 -0
- streamlit/vendor/pympler/__init__.py +0 -0
- streamlit/vendor/pympler/asizeof.py +2869 -0
- streamlit/version.py +18 -0
- streamlit/watcher/__init__.py +28 -0
- streamlit/watcher/event_based_path_watcher.py +406 -0
- streamlit/watcher/folder_black_list.py +82 -0
- streamlit/watcher/local_sources_watcher.py +233 -0
- streamlit/watcher/path_watcher.py +185 -0
- streamlit/watcher/polling_path_watcher.py +124 -0
- streamlit/watcher/util.py +207 -0
- streamlit/web/__init__.py +13 -0
- streamlit/web/bootstrap.py +353 -0
- streamlit/web/cache_storage_manager_config.py +38 -0
- streamlit/web/cli.py +369 -0
- streamlit/web/server/__init__.py +26 -0
- streamlit/web/server/app_static_file_handler.py +93 -0
- streamlit/web/server/authlib_tornado_integration.py +60 -0
- streamlit/web/server/browser_websocket_handler.py +246 -0
- streamlit/web/server/component_request_handler.py +116 -0
- streamlit/web/server/media_file_handler.py +141 -0
- streamlit/web/server/oauth_authlib_routes.py +176 -0
- streamlit/web/server/oidc_mixin.py +108 -0
- streamlit/web/server/routes.py +295 -0
- streamlit/web/server/server.py +479 -0
- streamlit/web/server/server_util.py +161 -0
- streamlit/web/server/stats_request_handler.py +95 -0
- streamlit/web/server/upload_file_request_handler.py +137 -0
- streamlit/web/server/websocket_headers.py +56 -0
- streamlit_nightly-1.43.2.dev20250307.data/scripts/streamlit.cmd +16 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/METADATA +207 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/RECORD +563 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/WHEEL +5 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/entry_points.txt +2 -0
- streamlit_nightly-1.43.2.dev20250307.dist-info/top_level.txt +1 -0
@@ -0,0 +1,246 @@
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
import hmac
|
18
|
+
import json
|
19
|
+
from typing import TYPE_CHECKING, Any, Final
|
20
|
+
from urllib.parse import urlparse
|
21
|
+
|
22
|
+
import tornado.concurrent
|
23
|
+
import tornado.locks
|
24
|
+
import tornado.netutil
|
25
|
+
import tornado.web
|
26
|
+
import tornado.websocket
|
27
|
+
from tornado.escape import utf8
|
28
|
+
from tornado.websocket import WebSocketHandler
|
29
|
+
|
30
|
+
from streamlit import config
|
31
|
+
from streamlit.logger import get_logger
|
32
|
+
from streamlit.proto.BackMsg_pb2 import BackMsg
|
33
|
+
from streamlit.runtime import Runtime, SessionClient, SessionClientDisconnectedError
|
34
|
+
from streamlit.runtime.runtime_util import serialize_forward_msg
|
35
|
+
from streamlit.web.server.server_util import (
|
36
|
+
AUTH_COOKIE_NAME,
|
37
|
+
is_url_from_allowed_origins,
|
38
|
+
is_xsrf_enabled,
|
39
|
+
)
|
40
|
+
|
41
|
+
if TYPE_CHECKING:
|
42
|
+
from collections.abc import Awaitable
|
43
|
+
|
44
|
+
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
45
|
+
|
46
|
+
_LOGGER: Final = get_logger(__name__)
|
47
|
+
|
48
|
+
|
49
|
+
class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
|
50
|
+
"""Handles a WebSocket connection from the browser"""
|
51
|
+
|
52
|
+
def initialize(self, runtime: Runtime) -> None:
|
53
|
+
self._runtime = runtime
|
54
|
+
self._session_id: str | None = None
|
55
|
+
# The XSRF cookie is normally set when xsrf_form_html is used, but in a
|
56
|
+
# pure-Javascript application that does not use any regular forms we just
|
57
|
+
# need to read the self.xsrf_token manually to set the cookie as a side
|
58
|
+
# effect. See https://www.tornadoweb.org/en/stable/guide/security.html#cross-site-request-forgery-protection
|
59
|
+
# for more details.
|
60
|
+
if is_xsrf_enabled():
|
61
|
+
_ = self.xsrf_token
|
62
|
+
|
63
|
+
def get_signed_cookie(
|
64
|
+
self,
|
65
|
+
name: str,
|
66
|
+
value: str | None = None,
|
67
|
+
max_age_days: float = 31,
|
68
|
+
min_version: int | None = None,
|
69
|
+
) -> bytes | None:
|
70
|
+
"""Get a signed cookie from the request. Added for compatibility with
|
71
|
+
Tornado < 6.3.0.
|
72
|
+
See release notes: https://www.tornadoweb.org/en/stable/releases/v6.3.0.html#deprecation-notices
|
73
|
+
"""
|
74
|
+
try:
|
75
|
+
return super().get_signed_cookie(name, value, max_age_days, min_version)
|
76
|
+
except AttributeError:
|
77
|
+
return super().get_secure_cookie(name, value, max_age_days, min_version)
|
78
|
+
|
79
|
+
def check_origin(self, origin: str) -> bool:
|
80
|
+
"""Set up CORS."""
|
81
|
+
return super().check_origin(origin) or is_url_from_allowed_origins(origin)
|
82
|
+
|
83
|
+
def _validate_xsrf_token(self, supplied_token: str) -> bool:
|
84
|
+
"""Inspired by tornado.web.RequestHandler.check_xsrf_cookie method,
|
85
|
+
to check the XSRF token passed in Websocket connection header.
|
86
|
+
"""
|
87
|
+
_, token, _ = self._decode_xsrf_token(supplied_token)
|
88
|
+
_, expected_token, _ = self._get_raw_xsrf_token()
|
89
|
+
|
90
|
+
decoded_token = utf8(token)
|
91
|
+
decoded_expected_token = utf8(expected_token)
|
92
|
+
|
93
|
+
if not decoded_token or not decoded_expected_token:
|
94
|
+
return False
|
95
|
+
return hmac.compare_digest(decoded_token, decoded_expected_token)
|
96
|
+
|
97
|
+
def _parse_user_cookie(self, raw_cookie_value: bytes) -> dict[str, Any]:
|
98
|
+
"""Process the user cookie and extract the user info after
|
99
|
+
validating the origin. Origin is validated for security reasons.
|
100
|
+
"""
|
101
|
+
cookie_value = json.loads(raw_cookie_value)
|
102
|
+
user_info = {}
|
103
|
+
|
104
|
+
cookie_value_origin = cookie_value.get("origin", None)
|
105
|
+
parsed_origin_from_header = urlparse(self.request.headers["Origin"])
|
106
|
+
expected_origin_value = (
|
107
|
+
parsed_origin_from_header.scheme + "://" + parsed_origin_from_header.netloc
|
108
|
+
)
|
109
|
+
if cookie_value_origin == expected_origin_value:
|
110
|
+
user_info["is_logged_in"] = cookie_value.get("is_logged_in", False)
|
111
|
+
del cookie_value["origin"]
|
112
|
+
del cookie_value["is_logged_in"]
|
113
|
+
user_info.update(cookie_value)
|
114
|
+
|
115
|
+
return user_info
|
116
|
+
|
117
|
+
def write_forward_msg(self, msg: ForwardMsg) -> None:
|
118
|
+
"""Send a ForwardMsg to the browser."""
|
119
|
+
try:
|
120
|
+
self.write_message(serialize_forward_msg(msg), binary=True)
|
121
|
+
except tornado.websocket.WebSocketClosedError as e:
|
122
|
+
raise SessionClientDisconnectedError from e
|
123
|
+
|
124
|
+
def select_subprotocol(self, subprotocols: list[str]) -> str | None:
|
125
|
+
"""Return the first subprotocol in the given list.
|
126
|
+
|
127
|
+
This method is used by Tornado to select a protocol when the
|
128
|
+
Sec-WebSocket-Protocol header is set in an HTTP Upgrade request.
|
129
|
+
|
130
|
+
NOTE: We repurpose the Sec-WebSocket-Protocol header here in a slightly
|
131
|
+
unfortunate (but necessary) way. The browser WebSocket API doesn't allow us to
|
132
|
+
set arbitrary HTTP headers, and this header is the only one where we have the
|
133
|
+
ability to set it to arbitrary values, so we use it to pass tokens (in this
|
134
|
+
case, the previous session ID to allow us to reconnect to it) from client to
|
135
|
+
server as the *third* value in the list.
|
136
|
+
|
137
|
+
The reason why the auth token is set as the third value is that:
|
138
|
+
- when Sec-WebSocket-Protocol is set, many clients expect the server to
|
139
|
+
respond with a selected subprotocol to use. We don't want that reply to be
|
140
|
+
the session token, so we by convention have the client always set the first
|
141
|
+
protocol to "streamlit" and select that.
|
142
|
+
- the second protocol in the list is reserved in some deployment environments
|
143
|
+
for an auth token that we currently don't use
|
144
|
+
"""
|
145
|
+
if subprotocols:
|
146
|
+
return subprotocols[0]
|
147
|
+
|
148
|
+
return None
|
149
|
+
|
150
|
+
def open(self, *args, **kwargs) -> Awaitable[None] | None:
|
151
|
+
user_info: dict[str, str | bool | None] = {}
|
152
|
+
|
153
|
+
existing_session_id = None
|
154
|
+
try:
|
155
|
+
ws_protocols = [
|
156
|
+
p.strip()
|
157
|
+
for p in self.request.headers["Sec-Websocket-Protocol"].split(",")
|
158
|
+
]
|
159
|
+
|
160
|
+
raw_cookie_value = self.get_signed_cookie(AUTH_COOKIE_NAME)
|
161
|
+
if is_xsrf_enabled() and raw_cookie_value:
|
162
|
+
csrf_protocol_value = ws_protocols[1]
|
163
|
+
|
164
|
+
if self._validate_xsrf_token(csrf_protocol_value):
|
165
|
+
user_info.update(self._parse_user_cookie(raw_cookie_value))
|
166
|
+
|
167
|
+
if len(ws_protocols) >= 3:
|
168
|
+
# See the NOTE in the docstring of the `select_subprotocol` method above
|
169
|
+
# for a detailed explanation of why this is done.
|
170
|
+
existing_session_id = ws_protocols[2]
|
171
|
+
except KeyError:
|
172
|
+
# Just let existing_session_id=None if we run into any error while trying to
|
173
|
+
# extract it from the Sec-Websocket-Protocol header.
|
174
|
+
pass
|
175
|
+
|
176
|
+
self._session_id = self._runtime.connect_session(
|
177
|
+
client=self,
|
178
|
+
user_info=user_info,
|
179
|
+
existing_session_id=existing_session_id,
|
180
|
+
)
|
181
|
+
return None
|
182
|
+
|
183
|
+
def on_close(self) -> None:
|
184
|
+
if not self._session_id:
|
185
|
+
return
|
186
|
+
self._runtime.disconnect_session(self._session_id)
|
187
|
+
self._session_id = None
|
188
|
+
|
189
|
+
def get_compression_options(self) -> dict[Any, Any] | None:
|
190
|
+
"""Enable WebSocket compression.
|
191
|
+
|
192
|
+
Returning an empty dict enables websocket compression. Returning
|
193
|
+
None disables it.
|
194
|
+
|
195
|
+
(See the docstring in the parent class.)
|
196
|
+
"""
|
197
|
+
if config.get_option("server.enableWebsocketCompression"):
|
198
|
+
return {}
|
199
|
+
return None
|
200
|
+
|
201
|
+
def on_message(self, payload: str | bytes) -> None:
|
202
|
+
if not self._session_id:
|
203
|
+
return
|
204
|
+
|
205
|
+
try:
|
206
|
+
if isinstance(payload, str):
|
207
|
+
# Sanity check. (The frontend should only be sending us bytes;
|
208
|
+
# Protobuf.ParseFromString does not accept str input.)
|
209
|
+
raise RuntimeError(
|
210
|
+
"WebSocket received an unexpected `str` message. "
|
211
|
+
"(We expect `bytes` only.)"
|
212
|
+
)
|
213
|
+
|
214
|
+
msg = BackMsg()
|
215
|
+
msg.ParseFromString(payload)
|
216
|
+
_LOGGER.debug("Received the following back message:\n%s", msg)
|
217
|
+
|
218
|
+
except Exception as ex:
|
219
|
+
_LOGGER.exception("Error deserializing back message")
|
220
|
+
self._runtime.handle_backmsg_deserialization_exception(self._session_id, ex)
|
221
|
+
return
|
222
|
+
|
223
|
+
# "debug_disconnect_websocket" and "debug_shutdown_runtime" are special
|
224
|
+
# developmentMode-only messages used in e2e tests to test reconnect handling and
|
225
|
+
# disabling widgets.
|
226
|
+
if msg.WhichOneof("type") == "debug_disconnect_websocket":
|
227
|
+
if config.get_option("global.developmentMode") or config.get_option(
|
228
|
+
"global.e2eTest"
|
229
|
+
):
|
230
|
+
self.close()
|
231
|
+
else:
|
232
|
+
_LOGGER.warning(
|
233
|
+
"Client tried to disconnect websocket when not in development mode or e2e testing."
|
234
|
+
)
|
235
|
+
elif msg.WhichOneof("type") == "debug_shutdown_runtime":
|
236
|
+
if config.get_option("global.developmentMode") or config.get_option(
|
237
|
+
"global.e2eTest"
|
238
|
+
):
|
239
|
+
self._runtime.stop()
|
240
|
+
else:
|
241
|
+
_LOGGER.warning(
|
242
|
+
"Client tried to shut down runtime when not in development mode or e2e testing."
|
243
|
+
)
|
244
|
+
else:
|
245
|
+
# AppSession handles all other BackMsg types.
|
246
|
+
self._runtime.handle_backmsg(self._session_id, msg)
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
import mimetypes
|
18
|
+
import os
|
19
|
+
from typing import TYPE_CHECKING, Final
|
20
|
+
|
21
|
+
import tornado.web
|
22
|
+
|
23
|
+
import streamlit.web.server.routes
|
24
|
+
from streamlit.logger import get_logger
|
25
|
+
|
26
|
+
if TYPE_CHECKING:
|
27
|
+
from streamlit.components.types.base_component_registry import BaseComponentRegistry
|
28
|
+
|
29
|
+
_LOGGER: Final = get_logger(__name__)
|
30
|
+
|
31
|
+
|
32
|
+
class ComponentRequestHandler(tornado.web.RequestHandler):
|
33
|
+
def initialize(self, registry: BaseComponentRegistry):
|
34
|
+
self._registry = registry
|
35
|
+
|
36
|
+
def get(self, path: str) -> None:
|
37
|
+
parts = path.split("/")
|
38
|
+
component_name = parts[0]
|
39
|
+
component_root = self._registry.get_component_path(component_name)
|
40
|
+
if component_root is None:
|
41
|
+
self.write("not found")
|
42
|
+
self.set_status(404)
|
43
|
+
return
|
44
|
+
|
45
|
+
# follow symlinks to get an accurate normalized path
|
46
|
+
component_root = os.path.realpath(component_root)
|
47
|
+
filename = "/".join(parts[1:])
|
48
|
+
abspath = os.path.normpath(os.path.join(component_root, filename))
|
49
|
+
|
50
|
+
# Do NOT expose anything outside of the component root.
|
51
|
+
if os.path.commonpath([component_root, abspath]) != component_root:
|
52
|
+
self.write("forbidden")
|
53
|
+
self.set_status(403)
|
54
|
+
return
|
55
|
+
try:
|
56
|
+
with open(abspath, "rb") as file:
|
57
|
+
contents = file.read()
|
58
|
+
except OSError as e:
|
59
|
+
_LOGGER.error(
|
60
|
+
"ComponentRequestHandler: GET %s read error", abspath, exc_info=e
|
61
|
+
)
|
62
|
+
self.write("read error")
|
63
|
+
self.set_status(404)
|
64
|
+
return
|
65
|
+
|
66
|
+
self.write(contents)
|
67
|
+
self.set_header("Content-Type", self.get_content_type(abspath))
|
68
|
+
|
69
|
+
self.set_extra_headers(path)
|
70
|
+
|
71
|
+
def set_extra_headers(self, path: str) -> None:
|
72
|
+
"""Disable cache for HTML files.
|
73
|
+
|
74
|
+
Other assets like JS and CSS are suffixed with their hash, so they can
|
75
|
+
be cached indefinitely.
|
76
|
+
"""
|
77
|
+
is_index_url = len(path) == 0
|
78
|
+
|
79
|
+
if is_index_url or path.endswith(".html"):
|
80
|
+
self.set_header("Cache-Control", "no-cache")
|
81
|
+
else:
|
82
|
+
self.set_header("Cache-Control", "public")
|
83
|
+
|
84
|
+
def set_default_headers(self) -> None:
|
85
|
+
if streamlit.web.server.routes.allow_cross_origin_requests():
|
86
|
+
self.set_header("Access-Control-Allow-Origin", "*")
|
87
|
+
|
88
|
+
def options(self) -> None:
|
89
|
+
"""/OPTIONS handler for preflight CORS checks."""
|
90
|
+
self.set_status(204)
|
91
|
+
self.finish()
|
92
|
+
|
93
|
+
@staticmethod
|
94
|
+
def get_content_type(abspath: str) -> str:
|
95
|
+
"""Returns the ``Content-Type`` header to be used for this request.
|
96
|
+
From tornado.web.StaticFileHandler.
|
97
|
+
"""
|
98
|
+
mime_type, encoding = mimetypes.guess_type(abspath)
|
99
|
+
# per RFC 6713, use the appropriate type for a gzip compressed file
|
100
|
+
if encoding == "gzip":
|
101
|
+
return "application/gzip"
|
102
|
+
# As of 2015-07-21 there is no bzip2 encoding defined at
|
103
|
+
# http://www.iana.org/assignments/media-types/media-types.xhtml
|
104
|
+
# So for that (and any other encoding), use octet-stream.
|
105
|
+
elif encoding is not None:
|
106
|
+
return "application/octet-stream"
|
107
|
+
elif mime_type is not None:
|
108
|
+
return mime_type
|
109
|
+
# if mime_type not detected, use application/octet-stream
|
110
|
+
else:
|
111
|
+
return "application/octet-stream"
|
112
|
+
|
113
|
+
@staticmethod
|
114
|
+
def get_url(file_id: str) -> str:
|
115
|
+
"""Return the URL for a component file with the given ID."""
|
116
|
+
return f"components/{file_id}"
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
from urllib.parse import quote
|
18
|
+
|
19
|
+
import tornado.web
|
20
|
+
|
21
|
+
from streamlit.logger import get_logger
|
22
|
+
from streamlit.runtime.media_file_storage import MediaFileKind, MediaFileStorageError
|
23
|
+
from streamlit.runtime.memory_media_file_storage import (
|
24
|
+
MemoryMediaFileStorage,
|
25
|
+
get_extension_for_mimetype,
|
26
|
+
)
|
27
|
+
from streamlit.web.server import allow_cross_origin_requests
|
28
|
+
|
29
|
+
_LOGGER = get_logger(__name__)
|
30
|
+
|
31
|
+
|
32
|
+
class MediaFileHandler(tornado.web.StaticFileHandler):
|
33
|
+
_storage: MemoryMediaFileStorage
|
34
|
+
|
35
|
+
@classmethod
|
36
|
+
def initialize_storage(cls, storage: MemoryMediaFileStorage) -> None:
|
37
|
+
"""Set the MemoryMediaFileStorage object used by instances of this
|
38
|
+
handler. Must be called on server startup.
|
39
|
+
"""
|
40
|
+
# This is a class method, rather than an instance method, because
|
41
|
+
# `get_content()` is a class method and needs to access the storage
|
42
|
+
# instance.
|
43
|
+
cls._storage = storage
|
44
|
+
|
45
|
+
def set_default_headers(self) -> None:
|
46
|
+
if allow_cross_origin_requests():
|
47
|
+
self.set_header("Access-Control-Allow-Origin", "*")
|
48
|
+
|
49
|
+
def set_extra_headers(self, path: str) -> None:
|
50
|
+
"""Add Content-Disposition header for downloadable files.
|
51
|
+
|
52
|
+
Set header value to "attachment" indicating that file should be saved
|
53
|
+
locally instead of displaying inline in browser.
|
54
|
+
|
55
|
+
We also set filename to specify the filename for downloaded files.
|
56
|
+
Used for serving downloadable files, like files stored via the
|
57
|
+
`st.download_button` widget.
|
58
|
+
"""
|
59
|
+
media_file = self._storage.get_file(path)
|
60
|
+
|
61
|
+
if media_file and media_file.kind == MediaFileKind.DOWNLOADABLE:
|
62
|
+
filename = media_file.filename
|
63
|
+
|
64
|
+
if not filename:
|
65
|
+
filename = f"streamlit_download{get_extension_for_mimetype(media_file.mimetype)}"
|
66
|
+
|
67
|
+
try:
|
68
|
+
# Check that the value can be encoded in latin1. Latin1 is
|
69
|
+
# the default encoding for headers.
|
70
|
+
filename.encode("latin1")
|
71
|
+
file_expr = f'filename="{filename}"'
|
72
|
+
except UnicodeEncodeError:
|
73
|
+
# RFC5987 syntax.
|
74
|
+
# See: https://datatracker.ietf.org/doc/html/rfc5987
|
75
|
+
file_expr = f"filename*=utf-8''{quote(filename)}"
|
76
|
+
|
77
|
+
self.set_header("Content-Disposition", f"attachment; {file_expr}")
|
78
|
+
|
79
|
+
# Overriding StaticFileHandler to use the MediaFileManager
|
80
|
+
#
|
81
|
+
# From the Tornado docs:
|
82
|
+
# To replace all interaction with the filesystem (e.g. to serve
|
83
|
+
# static content from a database), override `get_content`,
|
84
|
+
# `get_content_size`, `get_modified_time`, `get_absolute_path`, and
|
85
|
+
# `validate_absolute_path`.
|
86
|
+
def validate_absolute_path(self, root: str, absolute_path: str) -> str:
|
87
|
+
try:
|
88
|
+
self._storage.get_file(absolute_path)
|
89
|
+
except MediaFileStorageError:
|
90
|
+
_LOGGER.error("MediaFileHandler: Missing file %s", absolute_path)
|
91
|
+
raise tornado.web.HTTPError(404, "not found")
|
92
|
+
|
93
|
+
return absolute_path
|
94
|
+
|
95
|
+
def get_content_size(self) -> int:
|
96
|
+
abspath = self.absolute_path
|
97
|
+
if abspath is None:
|
98
|
+
return 0
|
99
|
+
|
100
|
+
media_file = self._storage.get_file(abspath)
|
101
|
+
return media_file.content_size
|
102
|
+
|
103
|
+
def get_modified_time(self) -> None:
|
104
|
+
# We do not track last modified time, but this can be improved to
|
105
|
+
# allow caching among files in the MediaFileManager
|
106
|
+
return None
|
107
|
+
|
108
|
+
@classmethod
|
109
|
+
def get_absolute_path(cls, root: str, path: str) -> str:
|
110
|
+
# All files are stored in memory, so the absolute path is just the
|
111
|
+
# path itself. In the MediaFileHandler, it's just the filename
|
112
|
+
return path
|
113
|
+
|
114
|
+
@classmethod
|
115
|
+
def get_content(
|
116
|
+
cls, abspath: str, start: int | None = None, end: int | None = None
|
117
|
+
):
|
118
|
+
_LOGGER.debug("MediaFileHandler: GET %s", abspath)
|
119
|
+
|
120
|
+
try:
|
121
|
+
# abspath is the hash as used `get_absolute_path`
|
122
|
+
media_file = cls._storage.get_file(abspath)
|
123
|
+
except Exception:
|
124
|
+
_LOGGER.error("MediaFileHandler: Missing file %s", abspath)
|
125
|
+
return None
|
126
|
+
|
127
|
+
_LOGGER.debug(
|
128
|
+
"MediaFileHandler: Sending %s file %s", media_file.mimetype, abspath
|
129
|
+
)
|
130
|
+
|
131
|
+
# If there is no start and end, just return the full content
|
132
|
+
if start is None and end is None:
|
133
|
+
return media_file.content
|
134
|
+
|
135
|
+
if start is None:
|
136
|
+
start = 0
|
137
|
+
if end is None:
|
138
|
+
end = len(media_file.content)
|
139
|
+
|
140
|
+
# content is bytes that work just by slicing supplied by start and end
|
141
|
+
return media_file.content[start:end]
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
from __future__ import annotations
|
15
|
+
|
16
|
+
import json
|
17
|
+
from typing import Any
|
18
|
+
from urllib.parse import urlparse
|
19
|
+
|
20
|
+
import tornado.web
|
21
|
+
|
22
|
+
from streamlit.auth_util import (
|
23
|
+
AuthCache,
|
24
|
+
decode_provider_token,
|
25
|
+
generate_default_provider_section,
|
26
|
+
get_secrets_auth_section,
|
27
|
+
)
|
28
|
+
from streamlit.errors import StreamlitAuthError
|
29
|
+
from streamlit.url_util import make_url_path
|
30
|
+
from streamlit.web.server.oidc_mixin import TornadoOAuth, TornadoOAuth2App
|
31
|
+
from streamlit.web.server.server_util import AUTH_COOKIE_NAME
|
32
|
+
|
33
|
+
auth_cache = AuthCache()
|
34
|
+
|
35
|
+
|
36
|
+
def create_oauth_client(provider: str) -> tuple[TornadoOAuth2App, str]:
|
37
|
+
"""Create an OAuth client for the given provider based on secrets.toml configuration."""
|
38
|
+
auth_section = get_secrets_auth_section()
|
39
|
+
if auth_section:
|
40
|
+
redirect_uri = auth_section.get("redirect_uri", None)
|
41
|
+
config = auth_section.to_dict()
|
42
|
+
else:
|
43
|
+
config = {}
|
44
|
+
redirect_uri = "/"
|
45
|
+
|
46
|
+
provider_section = config.setdefault(provider, {})
|
47
|
+
|
48
|
+
if not provider_section and provider == "default":
|
49
|
+
provider_section = generate_default_provider_section(auth_section)
|
50
|
+
config["default"] = provider_section
|
51
|
+
|
52
|
+
provider_client_kwargs = provider_section.setdefault("client_kwargs", {})
|
53
|
+
if "scope" not in provider_client_kwargs:
|
54
|
+
provider_client_kwargs["scope"] = "openid email profile"
|
55
|
+
if "prompt" not in provider_client_kwargs:
|
56
|
+
provider_client_kwargs["prompt"] = "select_account"
|
57
|
+
|
58
|
+
oauth = TornadoOAuth(config, cache=auth_cache)
|
59
|
+
oauth.register(provider)
|
60
|
+
return oauth.create_client(provider), redirect_uri
|
61
|
+
|
62
|
+
|
63
|
+
class AuthHandlerMixin(tornado.web.RequestHandler):
|
64
|
+
"""Mixin for handling auth cookies. Added for compatibility with Tornado < 6.3.0."""
|
65
|
+
|
66
|
+
def initialize(self, base_url: str) -> None:
|
67
|
+
self.base_url = base_url
|
68
|
+
|
69
|
+
def redirect_to_base(self) -> None:
|
70
|
+
self.redirect(make_url_path(self.base_url, "/"))
|
71
|
+
|
72
|
+
def set_auth_cookie(self, user_info: dict[str, Any]) -> None:
|
73
|
+
serialized_cookie_value = json.dumps(user_info)
|
74
|
+
try:
|
75
|
+
# We don't specify Tornado secure flag here because it leads to missing cookie on Safari.
|
76
|
+
# The OIDC flow should work only on secure context anyway (localhost or HTTPS),
|
77
|
+
# so specifying the secure flag here will not add anything in terms of security.
|
78
|
+
self.set_signed_cookie(
|
79
|
+
AUTH_COOKIE_NAME,
|
80
|
+
serialized_cookie_value,
|
81
|
+
httpOnly=True,
|
82
|
+
)
|
83
|
+
except AttributeError:
|
84
|
+
self.set_secure_cookie(
|
85
|
+
AUTH_COOKIE_NAME,
|
86
|
+
serialized_cookie_value,
|
87
|
+
httponly=True,
|
88
|
+
)
|
89
|
+
|
90
|
+
def clear_auth_cookie(self) -> None:
|
91
|
+
self.clear_cookie(AUTH_COOKIE_NAME)
|
92
|
+
|
93
|
+
|
94
|
+
class AuthLoginHandler(AuthHandlerMixin, tornado.web.RequestHandler):
|
95
|
+
async def get(self):
|
96
|
+
"""Redirect to the OAuth provider login page."""
|
97
|
+
provider = self._parse_provider_token()
|
98
|
+
if provider is None:
|
99
|
+
self.redirect_to_base()
|
100
|
+
return
|
101
|
+
|
102
|
+
client, redirect_uri = create_oauth_client(provider)
|
103
|
+
try:
|
104
|
+
client.authorize_redirect(self, redirect_uri)
|
105
|
+
except Exception as e:
|
106
|
+
self.send_error(400, reason=str(e))
|
107
|
+
|
108
|
+
def _parse_provider_token(self) -> str | None:
|
109
|
+
provider_token = self.get_argument("provider", None)
|
110
|
+
try:
|
111
|
+
if provider_token is None:
|
112
|
+
raise StreamlitAuthError("Missing provider token")
|
113
|
+
payload = decode_provider_token(provider_token)
|
114
|
+
except StreamlitAuthError:
|
115
|
+
return None
|
116
|
+
|
117
|
+
return payload["provider"]
|
118
|
+
|
119
|
+
|
120
|
+
class AuthLogoutHandler(AuthHandlerMixin, tornado.web.RequestHandler):
|
121
|
+
def get(self):
|
122
|
+
self.clear_auth_cookie()
|
123
|
+
self.redirect_to_base()
|
124
|
+
|
125
|
+
|
126
|
+
class AuthCallbackHandler(AuthHandlerMixin, tornado.web.RequestHandler):
|
127
|
+
async def get(self):
|
128
|
+
provider = self._get_provider_by_state()
|
129
|
+
origin = self._get_origin_from_secrets()
|
130
|
+
if origin is None:
|
131
|
+
self.redirect_to_base()
|
132
|
+
return
|
133
|
+
|
134
|
+
error = self.get_argument("error", None)
|
135
|
+
if error:
|
136
|
+
self.redirect_to_base()
|
137
|
+
return
|
138
|
+
|
139
|
+
if provider is None:
|
140
|
+
self.redirect_to_base()
|
141
|
+
return
|
142
|
+
|
143
|
+
client, _ = create_oauth_client(provider)
|
144
|
+
token = client.authorize_access_token(self)
|
145
|
+
user = token.get("userinfo")
|
146
|
+
|
147
|
+
cookie_value = dict(user, origin=origin, is_logged_in=True)
|
148
|
+
if user:
|
149
|
+
self.set_auth_cookie(cookie_value)
|
150
|
+
self.redirect_to_base()
|
151
|
+
|
152
|
+
def _get_provider_by_state(self) -> str | None:
|
153
|
+
state_code_from_url = self.get_argument("state")
|
154
|
+
current_cache_keys = list(auth_cache.get_dict().keys())
|
155
|
+
state_provider_mapping = {}
|
156
|
+
for key in current_cache_keys:
|
157
|
+
_, _, recorded_provider, code = key.split("_")
|
158
|
+
state_provider_mapping[code] = recorded_provider
|
159
|
+
|
160
|
+
provider: str | None = state_provider_mapping.get(state_code_from_url, None)
|
161
|
+
return provider
|
162
|
+
|
163
|
+
def _get_origin_from_secrets(self) -> str | None:
|
164
|
+
redirect_uri = None
|
165
|
+
auth_section = get_secrets_auth_section()
|
166
|
+
if auth_section:
|
167
|
+
redirect_uri = auth_section.get("redirect_uri", None)
|
168
|
+
|
169
|
+
if not redirect_uri:
|
170
|
+
return None
|
171
|
+
|
172
|
+
redirect_uri_parsed = urlparse(redirect_uri)
|
173
|
+
origin_from_redirect_uri: str = (
|
174
|
+
redirect_uri_parsed.scheme + "://" + redirect_uri_parsed.netloc
|
175
|
+
)
|
176
|
+
return origin_from_redirect_uri
|