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,213 @@
|
|
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
|
+
# NOTE: We won't always be able to import from snowflake.snowpark.session so need the
|
16
|
+
# `type: ignore` comment below, but that comment will explode if `warn-unused-ignores` is
|
17
|
+
# turned on when the package is available. Unfortunately, mypy doesn't provide a good
|
18
|
+
# way to configure this at a per-line level :(
|
19
|
+
# mypy: no-warn-unused-ignores
|
20
|
+
|
21
|
+
from __future__ import annotations
|
22
|
+
|
23
|
+
import threading
|
24
|
+
from collections import ChainMap
|
25
|
+
from contextlib import contextmanager
|
26
|
+
from typing import TYPE_CHECKING, cast
|
27
|
+
|
28
|
+
from streamlit.connections import BaseConnection
|
29
|
+
from streamlit.connections.util import (
|
30
|
+
SNOWSQL_CONNECTION_FILE,
|
31
|
+
load_from_snowsql_config_file,
|
32
|
+
running_in_sis,
|
33
|
+
)
|
34
|
+
from streamlit.errors import StreamlitAPIException
|
35
|
+
from streamlit.runtime.caching import cache_data
|
36
|
+
|
37
|
+
if TYPE_CHECKING:
|
38
|
+
from collections.abc import Iterator
|
39
|
+
from datetime import timedelta
|
40
|
+
|
41
|
+
from pandas import DataFrame
|
42
|
+
from snowflake.snowpark.session import Session # type:ignore[import]
|
43
|
+
|
44
|
+
|
45
|
+
_REQUIRED_CONNECTION_PARAMS = {"account"}
|
46
|
+
|
47
|
+
|
48
|
+
class SnowparkConnection(BaseConnection["Session"]):
|
49
|
+
"""A connection to Snowpark using snowflake.snowpark.session.Session. Initialize using
|
50
|
+
``st.connection("<name>", type="snowpark")``.
|
51
|
+
|
52
|
+
In addition to providing access to the Snowpark Session, SnowparkConnection supports
|
53
|
+
direct SQL querying using ``query("...")`` and thread safe access using
|
54
|
+
``with conn.safe_session():``. See methods below for more information.
|
55
|
+
SnowparkConnections should always be created using ``st.connection()``, **not**
|
56
|
+
initialized directly.
|
57
|
+
|
58
|
+
.. note::
|
59
|
+
We don't expect this iteration of SnowparkConnection to be able to scale
|
60
|
+
well in apps with many concurrent users due to the lock contention that will occur
|
61
|
+
over the single underlying Session object under high load.
|
62
|
+
"""
|
63
|
+
|
64
|
+
def __init__(self, connection_name: str, **kwargs) -> None:
|
65
|
+
self._lock = threading.RLock()
|
66
|
+
super().__init__(connection_name, **kwargs)
|
67
|
+
|
68
|
+
def _connect(self, **kwargs) -> Session:
|
69
|
+
from snowflake.snowpark.context import get_active_session # type:ignore[import]
|
70
|
+
from snowflake.snowpark.session import Session
|
71
|
+
|
72
|
+
# If we're running in SiS, just call get_active_session(). Otherwise, attempt to
|
73
|
+
# create a new session from whatever credentials we have available.
|
74
|
+
if running_in_sis():
|
75
|
+
return get_active_session()
|
76
|
+
|
77
|
+
conn_params = ChainMap(
|
78
|
+
kwargs,
|
79
|
+
self._secrets.to_dict(),
|
80
|
+
load_from_snowsql_config_file(self._connection_name),
|
81
|
+
)
|
82
|
+
|
83
|
+
if not len(conn_params):
|
84
|
+
raise StreamlitAPIException(
|
85
|
+
"Missing Snowpark connection configuration. "
|
86
|
+
f"Did you forget to set this in `secrets.toml`, `{SNOWSQL_CONNECTION_FILE}`, "
|
87
|
+
"or as kwargs to `st.connection`?"
|
88
|
+
)
|
89
|
+
|
90
|
+
for p in _REQUIRED_CONNECTION_PARAMS:
|
91
|
+
if p not in conn_params:
|
92
|
+
raise StreamlitAPIException(f"Missing Snowpark connection param: {p}")
|
93
|
+
|
94
|
+
return cast(Session, Session.builder.configs(conn_params).create())
|
95
|
+
|
96
|
+
def query(
|
97
|
+
self,
|
98
|
+
sql: str,
|
99
|
+
ttl: float | int | timedelta | None = None,
|
100
|
+
) -> DataFrame:
|
101
|
+
"""Run a read-only SQL query.
|
102
|
+
|
103
|
+
This method implements both query result caching (with caching behavior
|
104
|
+
identical to that of using ``@st.cache_data``) as well as simple error handling/retries.
|
105
|
+
|
106
|
+
.. note::
|
107
|
+
Queries that are run without a specified ttl are cached indefinitely.
|
108
|
+
|
109
|
+
Parameters
|
110
|
+
----------
|
111
|
+
sql : str
|
112
|
+
The read-only SQL query to execute.
|
113
|
+
ttl : float, int, timedelta or None
|
114
|
+
The maximum number of seconds to keep results in the cache, or
|
115
|
+
None if cached results should not expire. The default is None.
|
116
|
+
|
117
|
+
Returns
|
118
|
+
-------
|
119
|
+
pandas.DataFrame
|
120
|
+
The result of running the query, formatted as a pandas DataFrame.
|
121
|
+
|
122
|
+
Example
|
123
|
+
-------
|
124
|
+
>>> import streamlit as st
|
125
|
+
>>>
|
126
|
+
>>> conn = st.connection("snowpark")
|
127
|
+
>>> df = conn.query("SELECT * FROM pet_owners")
|
128
|
+
>>> st.dataframe(df)
|
129
|
+
"""
|
130
|
+
from snowflake.snowpark.exceptions import ( # type:ignore[import]
|
131
|
+
SnowparkServerException,
|
132
|
+
)
|
133
|
+
from tenacity import (
|
134
|
+
retry,
|
135
|
+
retry_if_exception_type,
|
136
|
+
stop_after_attempt,
|
137
|
+
wait_fixed,
|
138
|
+
)
|
139
|
+
|
140
|
+
@retry(
|
141
|
+
after=lambda _: self.reset(),
|
142
|
+
stop=stop_after_attempt(3),
|
143
|
+
reraise=True,
|
144
|
+
retry=retry_if_exception_type(SnowparkServerException),
|
145
|
+
wait=wait_fixed(1),
|
146
|
+
)
|
147
|
+
def _query(sql: str) -> DataFrame:
|
148
|
+
with self._lock:
|
149
|
+
return self._instance.sql(sql).to_pandas()
|
150
|
+
|
151
|
+
# We modify our helper function's `__qualname__` here to work around default
|
152
|
+
# `@st.cache_data` behavior. Otherwise, `.query()` being called with different
|
153
|
+
# `ttl` values will reset the cache with each call, and the query caches won't
|
154
|
+
# be scoped by connection.
|
155
|
+
ttl_str = str( # Avoid adding extra `.` characters to `__qualname__`
|
156
|
+
ttl
|
157
|
+
).replace(".", "_")
|
158
|
+
_query.__qualname__ = f"{_query.__qualname__}_{self._connection_name}_{ttl_str}"
|
159
|
+
_query = cache_data(
|
160
|
+
show_spinner="Running `snowpark.query(...)`.",
|
161
|
+
ttl=ttl,
|
162
|
+
)(_query)
|
163
|
+
|
164
|
+
return _query(sql)
|
165
|
+
|
166
|
+
@property
|
167
|
+
def session(self) -> Session:
|
168
|
+
"""Access the underlying Snowpark session.
|
169
|
+
|
170
|
+
.. note::
|
171
|
+
Snowpark sessions are **not** thread safe. Users of this method are
|
172
|
+
responsible for ensuring that access to the session returned by this method is
|
173
|
+
done in a thread-safe manner. For most users, we recommend using the thread-safe
|
174
|
+
safe_session() method and a ``with`` block.
|
175
|
+
|
176
|
+
Information on how to use Snowpark sessions can be found in the `Snowpark documentation
|
177
|
+
<https://docs.snowflake.com/en/developer-guide/snowpark/python/working-with-dataframes>`_.
|
178
|
+
|
179
|
+
Example
|
180
|
+
-------
|
181
|
+
>>> import streamlit as st
|
182
|
+
>>>
|
183
|
+
>>> session = st.connection("snowpark").session
|
184
|
+
>>> df = session.table("mytable").limit(10).to_pandas()
|
185
|
+
>>> st.dataframe(df)
|
186
|
+
"""
|
187
|
+
return self._instance
|
188
|
+
|
189
|
+
@contextmanager
|
190
|
+
def safe_session(self) -> Iterator[Session]:
|
191
|
+
"""Grab the underlying Snowpark session in a thread-safe manner.
|
192
|
+
|
193
|
+
As operations on a Snowpark session are not thread safe, we need to take care
|
194
|
+
when using a session in the context of a Streamlit app where each script run
|
195
|
+
occurs in its own thread. Using the contextmanager pattern to do this ensures
|
196
|
+
that access on this connection's underlying Session is done in a thread-safe
|
197
|
+
manner.
|
198
|
+
|
199
|
+
Information on how to use Snowpark sessions can be found in the `Snowpark documentation
|
200
|
+
<https://docs.snowflake.com/en/developer-guide/snowpark/python/working-with-dataframes>`_.
|
201
|
+
|
202
|
+
Example
|
203
|
+
-------
|
204
|
+
>>> import streamlit as st
|
205
|
+
>>>
|
206
|
+
>>> conn = st.connection("snowpark")
|
207
|
+
>>> with conn.safe_session() as session:
|
208
|
+
... df = session.table("mytable").limit(10).to_pandas()
|
209
|
+
>>>
|
210
|
+
>>> st.dataframe(df)
|
211
|
+
"""
|
212
|
+
with self._lock:
|
213
|
+
yield self.session
|
@@ -0,0 +1,425 @@
|
|
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
|
+
# NOTE: We ignore all mypy import-not-found errors as top-level since
|
16
|
+
# this module is optional and the SQLAlchemy dependency is not installed
|
17
|
+
# by default.
|
18
|
+
# mypy: disable-error-code="import-not-found, redundant-cast"
|
19
|
+
|
20
|
+
from __future__ import annotations
|
21
|
+
|
22
|
+
from collections import ChainMap
|
23
|
+
from copy import deepcopy
|
24
|
+
from typing import TYPE_CHECKING, cast
|
25
|
+
|
26
|
+
from streamlit.connections import BaseConnection
|
27
|
+
from streamlit.connections.util import extract_from_dict
|
28
|
+
from streamlit.errors import StreamlitAPIException
|
29
|
+
from streamlit.runtime.caching import cache_data
|
30
|
+
|
31
|
+
if TYPE_CHECKING:
|
32
|
+
from datetime import timedelta
|
33
|
+
|
34
|
+
from pandas import DataFrame
|
35
|
+
from sqlalchemy.engine import Connection as SQLAlchemyConnection
|
36
|
+
from sqlalchemy.engine.base import Engine
|
37
|
+
from sqlalchemy.orm import Session
|
38
|
+
|
39
|
+
|
40
|
+
_ALL_CONNECTION_PARAMS = {
|
41
|
+
"url",
|
42
|
+
"driver",
|
43
|
+
"dialect",
|
44
|
+
"username",
|
45
|
+
"password",
|
46
|
+
"host",
|
47
|
+
"port",
|
48
|
+
"database",
|
49
|
+
"query",
|
50
|
+
}
|
51
|
+
_REQUIRED_CONNECTION_PARAMS = {"dialect", "username", "host"}
|
52
|
+
|
53
|
+
|
54
|
+
class SQLConnection(BaseConnection["Engine"]):
|
55
|
+
"""A connection to a SQL database using a SQLAlchemy Engine.
|
56
|
+
|
57
|
+
Initialize this connection object using ``st.connection("sql")`` or
|
58
|
+
``st.connection("<name>", type="sql")``. Connection parameters for a
|
59
|
+
SQLConnection can be specified using ``secrets.toml`` and/or ``**kwargs``.
|
60
|
+
Possible connection parameters include:
|
61
|
+
|
62
|
+
- ``url`` or keyword arguments for |sqlalchemy.engine.URL.create()|_, except
|
63
|
+
``drivername``. Use ``dialect`` and ``driver`` instead of ``drivername``.
|
64
|
+
- Keyword arguments for |sqlalchemy.create_engine()|_, including custom
|
65
|
+
``connect()`` arguments used by your specific ``dialect`` or ``driver``.
|
66
|
+
- ``autocommit``. If this is ``False`` (default), the connection operates
|
67
|
+
in manual commit (transactional) mode. If this is ``True``, the
|
68
|
+
connection operates in autocommit (non-transactional) mode.
|
69
|
+
|
70
|
+
If ``url`` exists as a connection parameter, Streamlit will pass it to
|
71
|
+
``sqlalchemy.engine.make_url()``. Otherwise, Streamlit requires (at a
|
72
|
+
minimum) ``dialect``, ``username``, and ``host``. Streamlit will use
|
73
|
+
``dialect`` and ``driver`` (if defined) to derive ``drivername``, then pass
|
74
|
+
the relevant connection parameters to ``sqlalchemy.engine.URL.create()``.
|
75
|
+
|
76
|
+
In addition to the default keyword arguments for ``sqlalchemy.create_engine()``,
|
77
|
+
your dialect may accept additional keyword arguments. For example, if you
|
78
|
+
use ``dialect="snowflake"`` with `Snowflake SQLAlchemy
|
79
|
+
<https://github.com/snowflakedb/snowflake-sqlalchemy#key-pair-authentication-support>`_,
|
80
|
+
you can pass a value for ``private_key`` to use key-pair authentication. If
|
81
|
+
you use ``dialect="bigquery"`` with `Google BigQuery
|
82
|
+
<https://github.com/googleapis/python-bigquery-sqlalchemy#authentication>`_,
|
83
|
+
you can pass a value for ``location``.
|
84
|
+
|
85
|
+
SQLConnection provides the ``.query()`` convenience method, which can be
|
86
|
+
used to run simple, read-only queries with both caching and simple error
|
87
|
+
handling/retries. More complex database interactions can be performed by
|
88
|
+
using the ``.session`` property to receive a regular SQLAlchemy Session.
|
89
|
+
|
90
|
+
.. Important::
|
91
|
+
`SQLAlchemy <https://pypi.org/project/SQLAlchemy/>`_ must be installed
|
92
|
+
in your environment to use this connection. You must also install your
|
93
|
+
driver, such as ``pyodbc`` or ``psycopg2``.
|
94
|
+
|
95
|
+
.. |sqlalchemy.engine.URL.create()| replace:: ``sqlalchemy.engine.URL.create()``
|
96
|
+
.. _sqlalchemy.engine.URL.create(): https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.engine.URL.create
|
97
|
+
.. |sqlalchemy.engine.make_url()| replace:: ``sqlalchemy.engine.make_url()``
|
98
|
+
.. _sqlalchemy.engine.make_url(): https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.engine.make_url
|
99
|
+
.. |sqlalchemy.create_engine()| replace:: ``sqlalchemy.create_engine()``
|
100
|
+
.. _sqlalchemy.create_engine(): https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.create_engine
|
101
|
+
|
102
|
+
Examples
|
103
|
+
--------
|
104
|
+
|
105
|
+
**Example 1: Configuration with URL**
|
106
|
+
|
107
|
+
You can configure your SQL connection using Streamlit's
|
108
|
+
`Secrets management <https://docs.streamlit.io/develop/concepts/connections/secrets-management>`_.
|
109
|
+
The following example specifies a SQL connection URL.
|
110
|
+
|
111
|
+
``.streamlit/secrets.toml``:
|
112
|
+
|
113
|
+
>>> [connections.sql]
|
114
|
+
>>> url = "xxx+xxx://xxx:xxx@xxx:xxx/xxx"
|
115
|
+
|
116
|
+
Your app code:
|
117
|
+
|
118
|
+
>>> import streamlit as st
|
119
|
+
>>>
|
120
|
+
>>> conn = st.connection("sql")
|
121
|
+
>>> df = conn.query("SELECT * FROM pet_owners")
|
122
|
+
>>> st.dataframe(df)
|
123
|
+
|
124
|
+
**Example 2: Configuration with dialect, host, and username**
|
125
|
+
|
126
|
+
If you do not specify ``url``, you must at least specify ``dialect``,
|
127
|
+
``host``, and ``username`` instead. The following example also includes
|
128
|
+
``password``.
|
129
|
+
|
130
|
+
``.streamlit/secrets.toml``:
|
131
|
+
|
132
|
+
>>> [connections.sql]
|
133
|
+
>>> dialect = "xxx"
|
134
|
+
>>> host = "xxx"
|
135
|
+
>>> username = "xxx"
|
136
|
+
>>> password = "xxx"
|
137
|
+
|
138
|
+
Your app code:
|
139
|
+
|
140
|
+
>>> import streamlit as st
|
141
|
+
>>>
|
142
|
+
>>> conn = st.connection("sql")
|
143
|
+
>>> df = conn.query("SELECT * FROM pet_owners")
|
144
|
+
>>> st.dataframe(df)
|
145
|
+
|
146
|
+
**Example 3: Configuration with keyword arguments**
|
147
|
+
|
148
|
+
You can configure your SQL connection with keyword arguments (with or
|
149
|
+
without ``secrets.toml``). For example, if you use Microsoft Entra ID with
|
150
|
+
a Microsoft Azure SQL server, you can quickly set up a local connection for
|
151
|
+
development using `interactive authentication
|
152
|
+
<https://learn.microsoft.com/en-us/sql/connect/odbc/using-azure-active-directory?view=sql-server-ver16#new-andor-modified-dsn-and-connection-string-keywords>`_.
|
153
|
+
|
154
|
+
This example requires the `Microsoft ODBC Driver for SQL Server
|
155
|
+
<https://learn.microsoft.com/en-us/sql/connect/odbc/microsoft-odbc-driver-for-sql-server?view=sql-server-ver16>`_
|
156
|
+
for *Windows* in addition to the ``sqlalchemy`` and ``pyodbc`` packages for
|
157
|
+
Python.
|
158
|
+
|
159
|
+
>>> import streamlit as st
|
160
|
+
>>>
|
161
|
+
>>> conn = st.connection(
|
162
|
+
... "sql",
|
163
|
+
... dialect="mssql",
|
164
|
+
... driver="pyodbc",
|
165
|
+
... host="xxx.database.windows.net",
|
166
|
+
... database="xxx",
|
167
|
+
... username="xxx",
|
168
|
+
... query={
|
169
|
+
... "driver": "ODBC Driver 18 for SQL Server",
|
170
|
+
... "authentication": "ActiveDirectoryInteractive",
|
171
|
+
... "encrypt": "yes",
|
172
|
+
... },
|
173
|
+
... )
|
174
|
+
>>>
|
175
|
+
>>> df = conn.query("SELECT * FROM pet_owners")
|
176
|
+
>>> st.dataframe(df)
|
177
|
+
|
178
|
+
"""
|
179
|
+
|
180
|
+
def _connect(self, autocommit: bool = False, **kwargs) -> Engine:
|
181
|
+
import sqlalchemy
|
182
|
+
|
183
|
+
kwargs = deepcopy(kwargs)
|
184
|
+
conn_param_kwargs = extract_from_dict(_ALL_CONNECTION_PARAMS, kwargs)
|
185
|
+
conn_params = ChainMap(conn_param_kwargs, self._secrets.to_dict())
|
186
|
+
|
187
|
+
if not len(conn_params):
|
188
|
+
raise StreamlitAPIException(
|
189
|
+
"Missing SQL DB connection configuration. "
|
190
|
+
"Did you forget to set this in `secrets.toml` or as kwargs to `st.connection`?"
|
191
|
+
)
|
192
|
+
|
193
|
+
if "url" in conn_params:
|
194
|
+
url = sqlalchemy.engine.make_url(conn_params["url"])
|
195
|
+
else:
|
196
|
+
for p in _REQUIRED_CONNECTION_PARAMS:
|
197
|
+
if p not in conn_params:
|
198
|
+
raise StreamlitAPIException(f"Missing SQL DB connection param: {p}")
|
199
|
+
|
200
|
+
drivername = conn_params["dialect"] + (
|
201
|
+
f"+{conn_params['driver']}" if "driver" in conn_params else ""
|
202
|
+
)
|
203
|
+
|
204
|
+
url = sqlalchemy.engine.URL.create(
|
205
|
+
drivername=drivername,
|
206
|
+
username=conn_params["username"],
|
207
|
+
password=conn_params.get("password"),
|
208
|
+
host=conn_params["host"],
|
209
|
+
port=int(conn_params["port"]) if "port" in conn_params else None,
|
210
|
+
database=conn_params.get("database"),
|
211
|
+
query=conn_params["query"] if "query" in conn_params else None,
|
212
|
+
)
|
213
|
+
|
214
|
+
create_engine_kwargs = ChainMap(
|
215
|
+
kwargs, self._secrets.get("create_engine_kwargs", {})
|
216
|
+
)
|
217
|
+
eng = sqlalchemy.create_engine(url, **create_engine_kwargs)
|
218
|
+
|
219
|
+
if autocommit:
|
220
|
+
return cast("Engine", eng.execution_options(isolation_level="AUTOCOMMIT"))
|
221
|
+
else:
|
222
|
+
return cast("Engine", eng)
|
223
|
+
|
224
|
+
def query(
|
225
|
+
self,
|
226
|
+
sql: str,
|
227
|
+
*, # keyword-only arguments:
|
228
|
+
show_spinner: bool | str = "Running `sql.query(...)`.",
|
229
|
+
ttl: float | int | timedelta | None = None,
|
230
|
+
index_col: str | list[str] | None = None,
|
231
|
+
chunksize: int | None = None,
|
232
|
+
params=None,
|
233
|
+
**kwargs,
|
234
|
+
) -> DataFrame:
|
235
|
+
"""Run a read-only query.
|
236
|
+
|
237
|
+
This method implements query result caching and simple error
|
238
|
+
handling/retries. The caching behavior is identical to that of using
|
239
|
+
``@st.cache_data``.
|
240
|
+
|
241
|
+
.. note::
|
242
|
+
Queries that are run without a specified ttl are cached indefinitely.
|
243
|
+
|
244
|
+
All keyword arguments passed to this function are passed down to
|
245
|
+
|pandas.read_sql|_, except ``ttl``.
|
246
|
+
|
247
|
+
.. |pandas.read_sql| replace:: ``pandas.read_sql``
|
248
|
+
.. _pandas.read_sql: https://pandas.pydata.org/docs/reference/api/pandas.read_sql.html
|
249
|
+
|
250
|
+
Parameters
|
251
|
+
----------
|
252
|
+
sql : str
|
253
|
+
The read-only SQL query to execute.
|
254
|
+
show_spinner : boolean or string
|
255
|
+
Enable the spinner. The default is to show a spinner when there is a
|
256
|
+
"cache miss" and the cached resource is being created. If a string, the value
|
257
|
+
of the show_spinner param will be used for the spinner text.
|
258
|
+
ttl : float, int, timedelta or None
|
259
|
+
The maximum number of seconds to keep results in the cache, or
|
260
|
+
None if cached results should not expire. The default is None.
|
261
|
+
index_col : str, list of str, or None
|
262
|
+
Column(s) to set as index(MultiIndex). Default is None.
|
263
|
+
chunksize : int or None
|
264
|
+
If specified, return an iterator where chunksize is the number of
|
265
|
+
rows to include in each chunk. Default is None.
|
266
|
+
params : list, tuple, dict or None
|
267
|
+
List of parameters to pass to the execute method. The syntax used to pass
|
268
|
+
parameters is database driver dependent. Check your database driver
|
269
|
+
documentation for which of the five syntax styles, described in `PEP 249
|
270
|
+
paramstyle <https://peps.python.org/pep-0249/#paramstyle>`_, is supported.
|
271
|
+
Default is None.
|
272
|
+
**kwargs: dict
|
273
|
+
Additional keyword arguments are passed to |pandas.read_sql|_.
|
274
|
+
|
275
|
+
.. |pandas.read_sql| replace:: ``pandas.read_sql``
|
276
|
+
.. _pandas.read_sql: https://pandas.pydata.org/docs/reference/api/pandas.read_sql.html
|
277
|
+
|
278
|
+
Returns
|
279
|
+
-------
|
280
|
+
pandas.DataFrame
|
281
|
+
The result of running the query, formatted as a pandas DataFrame.
|
282
|
+
|
283
|
+
Example
|
284
|
+
-------
|
285
|
+
>>> import streamlit as st
|
286
|
+
>>>
|
287
|
+
>>> conn = st.connection("sql")
|
288
|
+
>>> df = conn.query(
|
289
|
+
... "SELECT * FROM pet_owners WHERE owner = :owner",
|
290
|
+
... ttl=3600,
|
291
|
+
... params={"owner": "barbara"},
|
292
|
+
... )
|
293
|
+
>>> st.dataframe(df)
|
294
|
+
"""
|
295
|
+
|
296
|
+
from sqlalchemy import text
|
297
|
+
from sqlalchemy.exc import DatabaseError, InternalError, OperationalError
|
298
|
+
from tenacity import (
|
299
|
+
retry,
|
300
|
+
retry_if_exception_type,
|
301
|
+
stop_after_attempt,
|
302
|
+
wait_fixed,
|
303
|
+
)
|
304
|
+
|
305
|
+
@retry(
|
306
|
+
after=lambda _: self.reset(),
|
307
|
+
stop=stop_after_attempt(3),
|
308
|
+
reraise=True,
|
309
|
+
retry=retry_if_exception_type(
|
310
|
+
(DatabaseError, InternalError, OperationalError)
|
311
|
+
),
|
312
|
+
wait=wait_fixed(1),
|
313
|
+
)
|
314
|
+
def _query(
|
315
|
+
sql: str,
|
316
|
+
index_col=None,
|
317
|
+
chunksize=None,
|
318
|
+
params=None,
|
319
|
+
**kwargs,
|
320
|
+
) -> DataFrame:
|
321
|
+
import pandas as pd
|
322
|
+
|
323
|
+
instance = self._instance.connect()
|
324
|
+
return pd.read_sql(
|
325
|
+
text(sql),
|
326
|
+
instance,
|
327
|
+
index_col=index_col,
|
328
|
+
chunksize=chunksize,
|
329
|
+
params=params,
|
330
|
+
**kwargs,
|
331
|
+
)
|
332
|
+
|
333
|
+
# We modify our helper function's `__qualname__` here to work around default
|
334
|
+
# `@st.cache_data` behavior. Otherwise, `.query()` being called with different
|
335
|
+
# `ttl` values will reset the cache with each call, and the query caches won't
|
336
|
+
# be scoped by connection.
|
337
|
+
ttl_str = str( # Avoid adding extra `.` characters to `__qualname__`
|
338
|
+
ttl
|
339
|
+
).replace(".", "_")
|
340
|
+
_query.__qualname__ = f"{_query.__qualname__}_{self._connection_name}_{ttl_str}"
|
341
|
+
_query = cache_data(
|
342
|
+
show_spinner=show_spinner,
|
343
|
+
ttl=ttl,
|
344
|
+
)(_query)
|
345
|
+
|
346
|
+
return _query(
|
347
|
+
sql,
|
348
|
+
index_col=index_col,
|
349
|
+
chunksize=chunksize,
|
350
|
+
params=params,
|
351
|
+
**kwargs,
|
352
|
+
)
|
353
|
+
|
354
|
+
def connect(self) -> SQLAlchemyConnection:
|
355
|
+
"""Call ``.connect()`` on the underlying SQLAlchemy Engine, returning a new\
|
356
|
+
connection object.
|
357
|
+
|
358
|
+
Calling this method is equivalent to calling ``self._instance.connect()``.
|
359
|
+
|
360
|
+
NOTE: This method should not be confused with the internal ``_connect`` method used
|
361
|
+
to implement a Streamlit Connection.
|
362
|
+
|
363
|
+
Returns
|
364
|
+
-------
|
365
|
+
sqlalchemy.engine.Connection
|
366
|
+
A new SQLAlchemy connection object.
|
367
|
+
"""
|
368
|
+
return self._instance.connect()
|
369
|
+
|
370
|
+
@property
|
371
|
+
def engine(self) -> Engine:
|
372
|
+
"""The underlying SQLAlchemy Engine.
|
373
|
+
|
374
|
+
This is equivalent to accessing ``self._instance``.
|
375
|
+
|
376
|
+
Returns
|
377
|
+
-------
|
378
|
+
sqlalchemy.engine.base.Engine
|
379
|
+
The underlying SQLAlchemy Engine.
|
380
|
+
"""
|
381
|
+
return self._instance
|
382
|
+
|
383
|
+
@property
|
384
|
+
def driver(self) -> str:
|
385
|
+
"""The name of the driver used by the underlying SQLAlchemy Engine.
|
386
|
+
|
387
|
+
This is equivalent to accessing ``self._instance.driver``.
|
388
|
+
|
389
|
+
Returns
|
390
|
+
-------
|
391
|
+
str
|
392
|
+
The name of the driver. For example, ``"pyodbc"`` or ``"psycopg2"``.
|
393
|
+
"""
|
394
|
+
return cast(str, self._instance.driver)
|
395
|
+
|
396
|
+
@property
|
397
|
+
def session(self) -> Session:
|
398
|
+
"""Return a SQLAlchemy Session.
|
399
|
+
|
400
|
+
Users of this connection should use the contextmanager pattern for writes,
|
401
|
+
transactions, and anything more complex than simple read queries.
|
402
|
+
|
403
|
+
See the usage example below, which assumes we have a table ``numbers`` with a
|
404
|
+
single integer column ``val``. The `SQLAlchemy
|
405
|
+
<https://docs.sqlalchemy.org/en/20/orm/session_basics.html>`_ docs also contain
|
406
|
+
much more information on the usage of sessions.
|
407
|
+
|
408
|
+
Returns
|
409
|
+
-------
|
410
|
+
sqlalchemy.orm.Session
|
411
|
+
A SQLAlchemy Session.
|
412
|
+
|
413
|
+
Example
|
414
|
+
-------
|
415
|
+
>>> import streamlit as st
|
416
|
+
>>> conn = st.connection("sql")
|
417
|
+
>>> n = st.slider("Pick a number")
|
418
|
+
>>> if st.button("Add the number!"):
|
419
|
+
... with conn.session as session:
|
420
|
+
... session.execute("INSERT INTO numbers (val) VALUES (:n);", {"n": n})
|
421
|
+
... session.commit()
|
422
|
+
"""
|
423
|
+
from sqlalchemy.orm import Session
|
424
|
+
|
425
|
+
return Session(self._instance)
|