streamlit 1.45.1__py3-none-any.whl → 1.46.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- streamlit/__init__.py +5 -1
- streamlit/auth_util.py +12 -12
- streamlit/cli_util.py +4 -3
- streamlit/column_config.py +11 -9
- streamlit/commands/echo.py +6 -4
- streamlit/commands/execution_control.py +33 -32
- streamlit/commands/experimental_query_params.py +2 -2
- streamlit/commands/logo.py +9 -4
- streamlit/commands/navigation.py +61 -18
- streamlit/commands/page_config.py +57 -47
- streamlit/components/types/base_custom_component.py +7 -7
- streamlit/components/v1/component_registry.py +7 -3
- streamlit/components/v1/components.py +1 -1
- streamlit/components/v1/custom_component.py +8 -8
- streamlit/config.py +289 -144
- streamlit/config_option.py +19 -15
- streamlit/config_util.py +29 -23
- streamlit/connections/__init__.py +2 -2
- streamlit/connections/base_connection.py +5 -5
- streamlit/connections/snowflake_connection.py +13 -11
- streamlit/connections/snowpark_connection.py +3 -3
- streamlit/connections/sql_connection.py +20 -18
- streamlit/connections/util.py +2 -2
- streamlit/cursor.py +6 -6
- streamlit/dataframe_util.py +52 -52
- streamlit/delta_generator.py +46 -48
- streamlit/delta_generator_singletons.py +3 -3
- streamlit/deprecation_util.py +6 -6
- streamlit/elements/alert.py +37 -29
- streamlit/elements/arrow.py +40 -22
- streamlit/elements/code.py +46 -13
- streamlit/elements/deck_gl_json_chart.py +38 -27
- streamlit/elements/dialog_decorator.py +3 -4
- streamlit/elements/doc_string.py +64 -58
- streamlit/elements/exception.py +23 -27
- streamlit/elements/form.py +41 -0
- streamlit/elements/graphviz_chart.py +1 -1
- streamlit/elements/heading.py +60 -9
- streamlit/elements/html.py +3 -4
- streamlit/elements/image.py +8 -9
- streamlit/elements/json.py +21 -2
- streamlit/elements/layouts.py +120 -31
- streamlit/elements/lib/built_in_chart_utils.py +96 -73
- streamlit/elements/lib/color_util.py +3 -3
- streamlit/elements/lib/column_config_utils.py +2 -4
- streamlit/elements/lib/column_types.py +14 -8
- streamlit/elements/lib/dialog.py +9 -5
- streamlit/elements/lib/image_utils.py +39 -40
- streamlit/elements/lib/js_number.py +4 -4
- streamlit/elements/lib/layout_utils.py +65 -1
- streamlit/elements/lib/mutable_status_container.py +14 -3
- streamlit/elements/lib/options_selector_utils.py +22 -12
- streamlit/elements/lib/pandas_styler_utils.py +25 -21
- streamlit/elements/lib/policies.py +6 -5
- streamlit/elements/lib/streamlit_plotly_theme.py +54 -53
- streamlit/elements/lib/subtitle_utils.py +6 -9
- streamlit/elements/lib/utils.py +20 -5
- streamlit/elements/map.py +32 -56
- streamlit/elements/markdown.py +101 -12
- streamlit/elements/media.py +78 -21
- streamlit/elements/metric.py +32 -16
- streamlit/elements/plotly_chart.py +15 -15
- streamlit/elements/progress.py +33 -15
- streamlit/elements/spinner.py +31 -6
- streamlit/elements/text.py +21 -1
- streamlit/elements/toast.py +1 -2
- streamlit/elements/vega_charts.py +54 -23
- streamlit/elements/widgets/audio_input.py +24 -7
- streamlit/elements/widgets/button.py +26 -19
- streamlit/elements/widgets/button_group.py +10 -15
- streamlit/elements/widgets/camera_input.py +27 -7
- streamlit/elements/widgets/chat.py +91 -38
- streamlit/elements/widgets/checkbox.py +45 -4
- streamlit/elements/widgets/color_picker.py +40 -17
- streamlit/elements/widgets/data_editor.py +76 -37
- streamlit/elements/widgets/file_uploader.py +42 -13
- streamlit/elements/widgets/multiselect.py +7 -10
- streamlit/elements/widgets/number_input.py +123 -47
- streamlit/elements/widgets/radio.py +59 -13
- streamlit/elements/widgets/select_slider.py +35 -30
- streamlit/elements/widgets/selectbox.py +56 -9
- streamlit/elements/widgets/slider.py +190 -99
- streamlit/elements/widgets/text_widgets.py +54 -8
- streamlit/elements/widgets/time_widgets.py +53 -14
- streamlit/elements/write.py +5 -8
- streamlit/env_util.py +2 -7
- streamlit/error_util.py +16 -9
- streamlit/errors.py +69 -48
- streamlit/external/langchain/streamlit_callback_handler.py +10 -5
- streamlit/file_util.py +27 -10
- streamlit/git_util.py +29 -24
- streamlit/hello/animation_demo.py +9 -9
- streamlit/hello/dataframe_demo.py +5 -5
- streamlit/hello/hello.py +1 -0
- streamlit/hello/mapping_demo.py +7 -8
- streamlit/hello/plotting_demo.py +3 -3
- streamlit/hello/streamlit_app.py +28 -26
- streamlit/hello/utils.py +2 -1
- streamlit/logger.py +10 -11
- streamlit/navigation/page.py +11 -8
- streamlit/proto/Audio_pb2.py +4 -3
- streamlit/proto/Audio_pb2.pyi +8 -1
- streamlit/proto/Block_pb2.py +38 -29
- streamlit/proto/Block_pb2.pyi +72 -4
- streamlit/proto/ClientState_pb2.py +4 -4
- streamlit/proto/ClientState_pb2.pyi +7 -2
- streamlit/proto/Code_pb2.py +4 -2
- streamlit/proto/Code_pb2.pyi +1 -0
- streamlit/proto/DataFrame_pb2.pyi +1 -1
- streamlit/proto/DeckGlJsonChart_pb2.pyi +1 -1
- streamlit/proto/Element_pb2.py +5 -3
- streamlit/proto/Element_pb2.pyi +20 -3
- streamlit/proto/GapSize_pb2.py +29 -0
- streamlit/proto/GapSize_pb2.pyi +70 -0
- streamlit/proto/HeightConfig_pb2.py +27 -0
- streamlit/proto/HeightConfig_pb2.pyi +48 -0
- streamlit/proto/NamedDataSet_pb2.pyi +1 -1
- streamlit/proto/Navigation_pb2.py +3 -3
- streamlit/proto/Navigation_pb2.pyi +4 -0
- streamlit/proto/NewSession_pb2.py +18 -16
- streamlit/proto/NewSession_pb2.pyi +29 -3
- streamlit/proto/PageConfig_pb2.py +7 -7
- streamlit/proto/PageConfig_pb2.pyi +21 -1
- streamlit/proto/Video_pb2.py +8 -7
- streamlit/proto/Video_pb2.pyi +8 -1
- streamlit/proto/WidthConfig_pb2.py +2 -2
- streamlit/proto/WidthConfig_pb2.pyi +15 -1
- streamlit/runtime/__init__.py +1 -1
- streamlit/runtime/app_session.py +53 -40
- streamlit/runtime/caching/__init__.py +9 -9
- streamlit/runtime/caching/cache_data_api.py +36 -30
- streamlit/runtime/caching/cache_errors.py +4 -4
- streamlit/runtime/caching/cache_resource_api.py +8 -8
- streamlit/runtime/caching/cache_utils.py +15 -14
- streamlit/runtime/caching/cached_message_replay.py +14 -8
- streamlit/runtime/caching/hashing.py +91 -97
- streamlit/runtime/caching/legacy_cache_api.py +2 -2
- streamlit/runtime/caching/storage/cache_storage_protocol.py +1 -1
- streamlit/runtime/caching/storage/dummy_cache_storage.py +1 -1
- streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +12 -14
- streamlit/runtime/caching/storage/local_disk_cache_storage.py +6 -6
- streamlit/runtime/connection_factory.py +36 -36
- streamlit/runtime/context.py +58 -9
- streamlit/runtime/credentials.py +29 -40
- streamlit/runtime/forward_msg_queue.py +11 -11
- streamlit/runtime/fragment.py +7 -7
- streamlit/runtime/media_file_manager.py +3 -4
- streamlit/runtime/memory_media_file_storage.py +6 -5
- streamlit/runtime/memory_uploaded_file_manager.py +2 -2
- streamlit/runtime/metrics_util.py +11 -12
- streamlit/runtime/pages_manager.py +4 -6
- streamlit/runtime/runtime.py +8 -6
- streamlit/runtime/runtime_util.py +7 -6
- streamlit/runtime/scriptrunner/__init__.py +4 -4
- streamlit/runtime/scriptrunner/exec_code.py +12 -5
- streamlit/runtime/scriptrunner/magic.py +16 -12
- streamlit/runtime/scriptrunner/script_cache.py +1 -1
- streamlit/runtime/scriptrunner/script_runner.py +53 -29
- streamlit/runtime/scriptrunner_utils/exceptions.py +1 -1
- streamlit/runtime/scriptrunner_utils/script_requests.py +7 -4
- streamlit/runtime/scriptrunner_utils/script_run_context.py +10 -23
- streamlit/runtime/secrets.py +40 -35
- streamlit/runtime/session_manager.py +2 -1
- streamlit/runtime/state/__init__.py +5 -5
- streamlit/runtime/state/common.py +2 -2
- streamlit/runtime/state/query_params.py +13 -15
- streamlit/runtime/state/query_params_proxy.py +17 -13
- streamlit/runtime/state/safe_session_state.py +2 -2
- streamlit/runtime/state/session_state.py +52 -34
- streamlit/runtime/stats.py +2 -2
- streamlit/runtime/uploaded_file_manager.py +1 -1
- streamlit/runtime/websocket_session_manager.py +10 -6
- streamlit/source_util.py +8 -6
- streamlit/static/index.html +3 -17
- streamlit/static/manifest.json +1180 -0
- streamlit/static/static/css/{index.DqDwtg6_.css → index.CJVRHjQZ.css} +1 -1
- streamlit/static/static/js/{ErrorOutline.esm.DU9IrB3M.js → ErrorOutline.esm.DitPpe1Y.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.P9rKwKo8.js → FileDownload.esm.AI3watX9.js} +1 -1
- streamlit/static/static/js/{FileHelper.D7RMkx0e.js → FileHelper.kt7mhnu8.js} +5 -5
- streamlit/static/static/js/{FormClearHelper.B67tgll0.js → FormClearHelper.D1M9GM_c.js} +1 -1
- streamlit/static/static/js/{Hooks.ncTJktu9.js → Hooks.BGwHKeUc.js} +1 -1
- streamlit/static/static/js/{InputInstructions.D-Y8geDN.js → InputInstructions.DaZ89mzH.js} +1 -1
- streamlit/static/static/js/{ProgressBar.B-kexwwD.js → ProgressBar.C0zPMe-p.js} +2 -2
- streamlit/static/static/js/{RenderInPortalIfExists.BgaoZgep.js → RenderInPortalIfExists.Ox8gQvdz.js} +1 -1
- streamlit/static/static/js/Toolbar.KhlcEc0K.js +1 -0
- streamlit/static/static/js/UploadFileInfo.0DCkpDDf.js +6 -0
- streamlit/static/static/js/{base-input.BoAa1U94.js → base-input.BJ4qsfSq.js} +4 -4
- streamlit/static/static/js/{checkbox.Z6iSfe5F.js → checkbox.DSDh78Xz.js} +2 -2
- streamlit/static/static/js/{createSuper.B4oGDYRm.js → createSuper.wQ9SIXEJ.js} +1 -1
- streamlit/static/static/js/{data-grid-overlay-editor.msYws2Ou.js → data-grid-overlay-editor.DvbdPJ15.js} +1 -1
- streamlit/static/static/js/{downloader.kc14n2Hv.js → downloader.CD9rzih5.js} +1 -1
- streamlit/static/static/js/{es6.CxQz807-.js → es6.48Q9Qjgb.js} +2 -2
- streamlit/static/static/js/{iframeResizer.contentWindow.B19u0ONI.js → iframeResizer.contentWindow.CKdem3Bn.js} +1 -1
- streamlit/static/static/js/{index.LaIasviC.js → index.6md5Qhod.js} +1 -1
- streamlit/static/static/js/index.7hy6AeJ1.js +1 -0
- streamlit/static/static/js/index.B4CGJiBW.js +1 -0
- streamlit/static/static/js/index.B8oW0ZTD.js +1 -0
- streamlit/static/static/js/index.BU6RnlHI.js +73 -0
- streamlit/static/static/js/index.BUq9Wcf8.js +197 -0
- streamlit/static/static/js/{index.BFz9U2y0.js → index.BXXo-Yoj.js} +1 -1
- streamlit/static/static/js/index.Bae9H0OS.js +1 -0
- streamlit/static/static/js/{index.-5ruC9At.js → index.BhTl2Uyb.js} +1 -1
- streamlit/static/static/js/{index.BpILzHf_.js → index.BiSaCB1o.js} +20 -20
- streamlit/static/static/js/{index.xNQq3Ei5.js → index.BulSAJ9z.js} +1 -1
- streamlit/static/static/js/{index.9V1KdxfP.js → index.Bv-EuTKR.js} +1 -1
- streamlit/static/static/js/index.BvMLYCHi.js +1 -0
- streamlit/static/static/js/index.C1NIn1Y2.js +783 -0
- streamlit/static/static/js/index.CP-fthOJ.js +2 -0
- streamlit/static/static/js/{index.BoigZiu7.js → index.CS9guO3p.js} +1 -1
- streamlit/static/static/js/index.CYTBHth8.js +1 -0
- streamlit/static/static/js/{index.CmTAF0dM.js → index.CcJufcuD.js} +1 -1
- streamlit/static/static/js/index.CnENU1yn.js +1 -0
- streamlit/static/static/js/index.Cns13qBb.js +1 -0
- streamlit/static/static/js/index.Ct_xXq7w.js +1 -0
- streamlit/static/static/js/{index.BqfdT8-Q.js → index.CxGSemHL.js} +1 -1
- streamlit/static/static/js/index.D5S0ldVb.js +1 -0
- streamlit/static/static/js/index.D72B_ksb.js +2 -0
- streamlit/static/static/js/index.DI4yZ27M.js +1 -0
- streamlit/static/static/js/index.DN51vLxR.js +1 -0
- streamlit/static/static/js/index.DRtq5dka.js +1 -0
- streamlit/static/static/js/{index.BHXxWdde.js → index.DX-oiXlb.js} +1 -1
- streamlit/static/static/js/index.DlFE4_Aq.js +12 -0
- streamlit/static/static/js/{index.BHGGDa8K.js → index.J7BJwXOi.js} +2 -2
- streamlit/static/static/js/index.Jg38kJPP.js +1 -0
- streamlit/static/static/js/index.JhIO6abf.js +3 -0
- streamlit/static/static/js/{index.DeB9iKFW.js → index.NkRcWwc5.js} +255 -255
- streamlit/static/static/js/{index.BGga-hcS.js → index.prekPLrm.js} +25 -25
- streamlit/static/static/js/{index.BRXmLIsC.js → index.wyzngKUE.js} +1 -1
- streamlit/static/static/js/index.xW7mVdI8.js +1 -0
- streamlit/static/static/js/index.yk07dYGx.js +1 -0
- streamlit/static/static/js/{input.DsCfafm0.js → input.CxKZ5Wrc.js} +2 -2
- streamlit/static/static/js/{memory.nY_lMTtu.js → memory.DeZ9VUvl.js} +1 -1
- streamlit/static/static/js/{mergeWith.B_7zmsM4.js → mergeWith.CVkhrWUb.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.CSeVhHRU.js → number-overlay-editor.Bpkm3nTq.js} +1 -1
- streamlit/static/static/js/{possibleConstructorReturn.nNhsvgRd.js → possibleConstructorReturn.CIDCId52.js} +1 -1
- streamlit/static/static/js/{sandbox.Cgm3iuL6.js → sandbox.TrkMaokR.js} +1 -1
- streamlit/static/static/js/{textarea.BR8rlyih.js → textarea.QKjxR64N.js} +2 -2
- streamlit/static/static/js/{timepicker.w4XhAenH.js → timepicker.DJYmE1dK.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.CgkEPBwD.js → toConsumableArray.BZoworE-.js} +1 -1
- streamlit/static/static/js/{uniqueId.j-1rlNNH.js → uniqueId.O0UbJ2Bu.js} +1 -1
- streamlit/static/static/js/{useBasicWidgetState.zXY9CjFS.js → useBasicWidgetState.Ci89jaH5.js} +1 -1
- streamlit/static/static/js/useOnInputChange.Cxh6ExEn.js +1 -0
- streamlit/static/static/js/{withFullScreenWrapper.Ov13692o.js → withFullScreenWrapper.iW37lS8Z.js} +1 -1
- streamlit/static/static/media/SourceCodeVF-Italic.ttf.Ba1oaZG1.woff2 +0 -0
- streamlit/static/static/media/SourceCodeVF-Upright.ttf.BjWn63N-.woff2 +0 -0
- streamlit/static/static/media/SourceSansVF-Italic.ttf.Bt9VkdQ3.woff2 +0 -0
- streamlit/static/static/media/SourceSansVF-Upright.ttf.BsWL4Kly.woff2 +0 -0
- streamlit/static/static/media/SourceSerifVariable-Italic.ttf.CVdzAtxO.woff2 +0 -0
- streamlit/static/static/media/SourceSerifVariable-Roman.ttf.mdpVL9bi.woff2 +0 -0
- streamlit/string_util.py +14 -19
- streamlit/temporary_directory.py +13 -4
- streamlit/testing/v1/app_test.py +15 -10
- streamlit/testing/v1/element_tree.py +157 -178
- streamlit/testing/v1/local_script_runner.py +11 -15
- streamlit/testing/v1/util.py +11 -4
- streamlit/type_util.py +8 -12
- streamlit/url_util.py +1 -1
- streamlit/user_info.py +6 -5
- streamlit/util.py +25 -1
- streamlit/vendor/pympler/asizeof.py +3 -2
- streamlit/watcher/event_based_path_watcher.py +21 -2
- streamlit/watcher/folder_black_list.py +2 -2
- streamlit/watcher/local_sources_watcher.py +64 -18
- streamlit/watcher/path_watcher.py +6 -10
- streamlit/watcher/polling_path_watcher.py +8 -7
- streamlit/watcher/util.py +7 -6
- streamlit/web/bootstrap.py +16 -14
- streamlit/web/cli.py +52 -45
- streamlit/web/server/__init__.py +7 -3
- streamlit/web/server/app_static_file_handler.py +1 -1
- streamlit/web/server/authlib_tornado_integration.py +9 -4
- streamlit/web/server/browser_websocket_handler.py +8 -2
- streamlit/web/server/component_request_handler.py +14 -10
- streamlit/web/server/media_file_handler.py +14 -7
- streamlit/web/server/oauth_authlib_routes.py +41 -9
- streamlit/web/server/oidc_mixin.py +35 -17
- streamlit/web/server/routes.py +32 -22
- streamlit/web/server/server.py +13 -24
- streamlit/web/server/server_util.py +43 -9
- streamlit/web/server/stats_request_handler.py +7 -5
- streamlit/web/server/upload_file_request_handler.py +22 -19
- streamlit/web/server/websocket_headers.py +1 -1
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/METADATA +4 -4
- streamlit-1.46.1.dist-info/RECORD +559 -0
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/WHEEL +1 -1
- streamlit/elements/lib/event_utils.py +0 -39
- streamlit/static/static/js/Toolbar.D9RUZv9G.js +0 -1
- streamlit/static/static/js/UploadFileInfo.C-jY39rj.js +0 -1
- streamlit/static/static/js/index.8jhZBWF2.js +0 -3
- streamlit/static/static/js/index.BCx3C6e_.js +0 -1
- streamlit/static/static/js/index.BRuTz_S4.js +0 -1
- streamlit/static/static/js/index.Bcru_ti-.js +0 -1
- streamlit/static/static/js/index.Bl1FMJRd.js +0 -1
- streamlit/static/static/js/index.C1z8KpLA.js +0 -779
- streamlit/static/static/js/index.C32I2PUe.js +0 -2
- streamlit/static/static/js/index.C5GnDRB7.js +0 -1
- streamlit/static/static/js/index.CG4qPaaW.js +0 -2
- streamlit/static/static/js/index.C_msmT1u.js +0 -1
- streamlit/static/static/js/index.CbeNTdd6.js +0 -1
- streamlit/static/static/js/index.CnGQVJcw.js +0 -12
- streamlit/static/static/js/index.CopVVq4l.js +0 -1
- streamlit/static/static/js/index.CtXupx4d.js +0 -197
- streamlit/static/static/js/index.DGmCchO7.js +0 -1
- streamlit/static/static/js/index.DH6zBk0e.js +0 -1
- streamlit/static/static/js/index.DHVlVWsm.js +0 -1
- streamlit/static/static/js/index.DRKIVBoi.js +0 -1
- streamlit/static/static/js/index.DUd-lFXx.js +0 -73
- streamlit/static/static/js/index.D_uRBA4B.js +0 -1
- streamlit/static/static/js/index.QHNfgPJd.js +0 -1
- streamlit/static/static/js/index.a-RJocYL.js +0 -1
- streamlit/static/static/js/index.cvz4B1gy.js +0 -1
- streamlit/static/static/js/index.t--hEgTQ.js +0 -6
- streamlit/static/static/js/useOnInputChange.z04u96A8.js +0 -1
- streamlit/static/static/media/SourceCodePro-Bold.CFEfr7-q.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-BoldItalic.C-LkFXxa.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-Italic.CxFOx7N-.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-Regular.CBOlD63d.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-SemiBold.CFHwW3Wd.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-SemiBoldItalic.Cg2yRu82.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Bold.-6c9oR8J.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-BoldItalic.DmM_grLY.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Italic.I1ipWe7Q.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Regular.DZLUzqI4.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-SemiBold.sKQIyTMz.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-SemiBoldItalic.C0wP0icr.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Bold.8TUnKj4x.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-BoldItalic.CBVO7Ve7.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Italic.DkFgL2HZ.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Regular.CNJNET2S.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-SemiBold.CHyh9GC5.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-SemiBoldItalic.CBtz8sWN.woff2 +0 -0
- streamlit-1.45.1.dist-info/RECORD +0 -568
- {streamlit-1.45.1.data → streamlit-1.46.1.data}/scripts/streamlit.cmd +0 -0
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/entry_points.txt +0 -0
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/top_level.txt +0 -0
|
@@ -57,7 +57,9 @@ class InMemoryCacheStorageWrapper(CacheStorage):
|
|
|
57
57
|
it from multiple threads.
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
|
-
def __init__(
|
|
60
|
+
def __init__(
|
|
61
|
+
self, persist_storage: CacheStorage, context: CacheStorageContext
|
|
62
|
+
) -> None:
|
|
61
63
|
self.function_key = context.function_key
|
|
62
64
|
self.function_display_name = context.function_display_name
|
|
63
65
|
self._ttl_seconds = context.ttl_seconds
|
|
@@ -108,18 +110,15 @@ class InMemoryCacheStorageWrapper(CacheStorage):
|
|
|
108
110
|
|
|
109
111
|
def get_stats(self) -> list[CacheStat]:
|
|
110
112
|
"""Returns a list of stats in bytes for the cache memory storage per item."""
|
|
111
|
-
stats = []
|
|
112
|
-
|
|
113
113
|
with self._mem_cache_lock:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
byte_length=len(item),
|
|
120
|
-
)
|
|
114
|
+
return [
|
|
115
|
+
CacheStat(
|
|
116
|
+
category_name="st_cache_data",
|
|
117
|
+
cache_name=self.function_display_name,
|
|
118
|
+
byte_length=len(item),
|
|
121
119
|
)
|
|
122
|
-
|
|
120
|
+
for item in self._mem_cache.values()
|
|
121
|
+
]
|
|
123
122
|
|
|
124
123
|
def close(self) -> None:
|
|
125
124
|
"""Closes the cache storage."""
|
|
@@ -132,9 +131,8 @@ class InMemoryCacheStorageWrapper(CacheStorage):
|
|
|
132
131
|
_LOGGER.debug("Memory cache HIT: %s", key)
|
|
133
132
|
return entry
|
|
134
133
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
raise CacheStorageKeyNotFoundError("Key not found in mem cache")
|
|
134
|
+
_LOGGER.debug("Memory cache MISS: %s", key)
|
|
135
|
+
raise CacheStorageKeyNotFoundError("Key not found in mem cache")
|
|
138
136
|
|
|
139
137
|
def _write_to_mem_cache(self, key: str, entry_bytes: bytes) -> None:
|
|
140
138
|
with self._mem_cache_lock:
|
|
@@ -109,9 +109,9 @@ class LocalDiskCacheStorageManager(CacheStorageManager):
|
|
|
109
109
|
and not math.isinf(context.ttl_seconds)
|
|
110
110
|
):
|
|
111
111
|
_LOGGER.warning(
|
|
112
|
-
|
|
113
|
-
"
|
|
114
|
-
|
|
112
|
+
"The cached function '%s' has a TTL that will be ignored. "
|
|
113
|
+
"Persistent cached functions currently don't support TTL.",
|
|
114
|
+
context.function_display_name,
|
|
115
115
|
)
|
|
116
116
|
|
|
117
117
|
|
|
@@ -120,7 +120,7 @@ class LocalDiskCacheStorage(CacheStorage):
|
|
|
120
120
|
This is the default cache persistence layer for `@st.cache_data`.
|
|
121
121
|
"""
|
|
122
122
|
|
|
123
|
-
def __init__(self, context: CacheStorageContext):
|
|
123
|
+
def __init__(self, context: CacheStorageContext) -> None:
|
|
124
124
|
self.function_key = context.function_key
|
|
125
125
|
self.persist = context.persist
|
|
126
126
|
self._ttl_seconds = context.ttl_seconds
|
|
@@ -143,8 +143,8 @@ class LocalDiskCacheStorage(CacheStorage):
|
|
|
143
143
|
if self.persist == "disk":
|
|
144
144
|
path = self._get_cache_file_path(key)
|
|
145
145
|
try:
|
|
146
|
-
with streamlit_read(path, binary=True) as
|
|
147
|
-
value =
|
|
146
|
+
with streamlit_read(path, binary=True) as file:
|
|
147
|
+
value = file.read()
|
|
148
148
|
_LOGGER.debug("Disk cache HIT: %s", key)
|
|
149
149
|
return bytes(value)
|
|
150
150
|
except FileNotFoundError:
|
|
@@ -38,13 +38,13 @@ if TYPE_CHECKING:
|
|
|
38
38
|
# 2. Writing two new @overloads for connection_factory (one for the case where the
|
|
39
39
|
# only the connection name is specified and another when both name and type are).
|
|
40
40
|
# 3. Updating test_get_first_party_connection_helper in connection_factory_test.py.
|
|
41
|
-
|
|
41
|
+
_FIRST_PARTY_CONNECTIONS: Final[dict[str, type[BaseConnection[Any]]]] = {
|
|
42
42
|
"snowflake": SnowflakeConnection,
|
|
43
43
|
"snowpark": SnowparkConnection,
|
|
44
44
|
"sql": SQLConnection,
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
_MODULE_EXTRACTION_REGEX = re.compile(r"No module named \'(.+)\'")
|
|
47
|
+
_MODULES_TO_PYPI_PACKAGES: Final[dict[str, str]] = {
|
|
48
48
|
"MySQLdb": "mysqlclient",
|
|
49
49
|
"psycopg2": "psycopg2-binary",
|
|
50
50
|
"sqlalchemy": "sqlalchemy",
|
|
@@ -52,6 +52,7 @@ MODULES_TO_PYPI_PACKAGES: Final[dict[str, str]] = {
|
|
|
52
52
|
"snowflake.connector": "snowflake-connector-python",
|
|
53
53
|
"snowflake.snowpark": "snowflake-snowpark-python",
|
|
54
54
|
}
|
|
55
|
+
_USE_ENV_PREFIX: Final = "env:"
|
|
55
56
|
|
|
56
57
|
# The BaseConnection bound is parameterized to `Any` below as subclasses of
|
|
57
58
|
# BaseConnection are responsible for binding the type parameter of BaseConnection to a
|
|
@@ -65,7 +66,7 @@ def _create_connection(
|
|
|
65
66
|
connection_class: type[ConnectionClass],
|
|
66
67
|
max_entries: int | None = None,
|
|
67
68
|
ttl: float | timedelta | None = None,
|
|
68
|
-
**kwargs,
|
|
69
|
+
**kwargs: Any,
|
|
69
70
|
) -> ConnectionClass:
|
|
70
71
|
"""Create an instance of connection_class with the given name and kwargs.
|
|
71
72
|
|
|
@@ -76,7 +77,7 @@ def _create_connection(
|
|
|
76
77
|
"""
|
|
77
78
|
|
|
78
79
|
def __create_connection(
|
|
79
|
-
name: str, connection_class: type[ConnectionClass], **kwargs
|
|
80
|
+
name: str, connection_class: type[ConnectionClass], **kwargs: Any
|
|
80
81
|
) -> ConnectionClass:
|
|
81
82
|
return connection_class(connection_name=name, **kwargs)
|
|
82
83
|
|
|
@@ -103,13 +104,13 @@ def _create_connection(
|
|
|
103
104
|
return __create_connection(name, connection_class, **kwargs)
|
|
104
105
|
|
|
105
106
|
|
|
106
|
-
def _get_first_party_connection(connection_class: str):
|
|
107
|
-
if connection_class in
|
|
108
|
-
return
|
|
107
|
+
def _get_first_party_connection(connection_class: str) -> type[BaseConnection[Any]]:
|
|
108
|
+
if connection_class in _FIRST_PARTY_CONNECTIONS:
|
|
109
|
+
return _FIRST_PARTY_CONNECTIONS[connection_class]
|
|
109
110
|
|
|
110
111
|
raise StreamlitAPIException(
|
|
111
112
|
f"Invalid connection '{connection_class}'. "
|
|
112
|
-
f"Supported connection classes: {
|
|
113
|
+
f"Supported connection classes: {_FIRST_PARTY_CONNECTIONS}"
|
|
113
114
|
)
|
|
114
115
|
|
|
115
116
|
|
|
@@ -119,7 +120,7 @@ def connection_factory(
|
|
|
119
120
|
max_entries: int | None = None,
|
|
120
121
|
ttl: float | timedelta | None = None,
|
|
121
122
|
autocommit: bool = False,
|
|
122
|
-
**kwargs,
|
|
123
|
+
**kwargs: Any,
|
|
123
124
|
) -> SQLConnection:
|
|
124
125
|
pass
|
|
125
126
|
|
|
@@ -131,7 +132,7 @@ def connection_factory(
|
|
|
131
132
|
max_entries: int | None = None,
|
|
132
133
|
ttl: float | timedelta | None = None,
|
|
133
134
|
autocommit: bool = False,
|
|
134
|
-
**kwargs,
|
|
135
|
+
**kwargs: Any,
|
|
135
136
|
) -> SQLConnection:
|
|
136
137
|
pass
|
|
137
138
|
|
|
@@ -142,7 +143,7 @@ def connection_factory(
|
|
|
142
143
|
max_entries: int | None = None,
|
|
143
144
|
ttl: float | timedelta | None = None,
|
|
144
145
|
autocommit: bool = False,
|
|
145
|
-
**kwargs,
|
|
146
|
+
**kwargs: Any,
|
|
146
147
|
) -> SnowflakeConnection:
|
|
147
148
|
pass
|
|
148
149
|
|
|
@@ -154,7 +155,7 @@ def connection_factory(
|
|
|
154
155
|
max_entries: int | None = None,
|
|
155
156
|
ttl: float | timedelta | None = None,
|
|
156
157
|
autocommit: bool = False,
|
|
157
|
-
**kwargs,
|
|
158
|
+
**kwargs: Any,
|
|
158
159
|
) -> SnowflakeConnection:
|
|
159
160
|
pass
|
|
160
161
|
|
|
@@ -164,7 +165,7 @@ def connection_factory(
|
|
|
164
165
|
name: Literal["snowpark"],
|
|
165
166
|
max_entries: int | None = None,
|
|
166
167
|
ttl: float | timedelta | None = None,
|
|
167
|
-
**kwargs,
|
|
168
|
+
**kwargs: Any,
|
|
168
169
|
) -> SnowparkConnection:
|
|
169
170
|
pass
|
|
170
171
|
|
|
@@ -175,7 +176,7 @@ def connection_factory(
|
|
|
175
176
|
type: Literal["snowpark"],
|
|
176
177
|
max_entries: int | None = None,
|
|
177
178
|
ttl: float | timedelta | None = None,
|
|
178
|
-
**kwargs,
|
|
179
|
+
**kwargs: Any,
|
|
179
180
|
) -> SnowparkConnection:
|
|
180
181
|
pass
|
|
181
182
|
|
|
@@ -186,7 +187,7 @@ def connection_factory(
|
|
|
186
187
|
type: type[ConnectionClass],
|
|
187
188
|
max_entries: int | None = None,
|
|
188
189
|
ttl: float | timedelta | None = None,
|
|
189
|
-
**kwargs,
|
|
190
|
+
**kwargs: Any,
|
|
190
191
|
) -> ConnectionClass:
|
|
191
192
|
pass
|
|
192
193
|
|
|
@@ -197,12 +198,12 @@ def connection_factory(
|
|
|
197
198
|
type: str | None = None,
|
|
198
199
|
max_entries: int | None = None,
|
|
199
200
|
ttl: float | timedelta | None = None,
|
|
200
|
-
**kwargs,
|
|
201
|
+
**kwargs: Any,
|
|
201
202
|
) -> BaseConnection[Any]:
|
|
202
203
|
pass
|
|
203
204
|
|
|
204
205
|
|
|
205
|
-
def connection_factory(
|
|
206
|
+
def connection_factory( # type: ignore
|
|
206
207
|
name,
|
|
207
208
|
type=None,
|
|
208
209
|
max_entries=None,
|
|
@@ -233,7 +234,7 @@ def connection_factory(
|
|
|
233
234
|
The type of connection to create. This can be one of the following:
|
|
234
235
|
|
|
235
236
|
- ``None`` (default): Streamlit will infer the connection type from
|
|
236
|
-
``name``. If the type is not
|
|
237
|
+
``name``. If the type is not inferable from ``name``, the type must
|
|
237
238
|
be specified in ``secrets.toml`` instead.
|
|
238
239
|
- ``"snowflake"``: Streamlit will initialize a connection with
|
|
239
240
|
|SnowflakeConnection|_.
|
|
@@ -267,7 +268,7 @@ def connection_factory(
|
|
|
267
268
|
**kwargs : any
|
|
268
269
|
Connection-specific keyword arguments that are passed to the
|
|
269
270
|
connection's ``._connect()`` method. ``**kwargs`` are typically
|
|
270
|
-
combined with (and take
|
|
271
|
+
combined with (and take precedence over) key-value pairs in
|
|
271
272
|
``secrets.toml``. To learn more, see the specific connection's
|
|
272
273
|
documentation.
|
|
273
274
|
|
|
@@ -366,19 +367,23 @@ def connection_factory(
|
|
|
366
367
|
>>> conn = st.connection("my_sql_connection", type=SQLConnection)
|
|
367
368
|
|
|
368
369
|
"""
|
|
369
|
-
USE_ENV_PREFIX = "env:"
|
|
370
370
|
|
|
371
|
-
if name.startswith(
|
|
371
|
+
if name.startswith(_USE_ENV_PREFIX):
|
|
372
372
|
# It'd be nice to use str.removeprefix() here, but we won't be able to do that
|
|
373
|
-
# until the
|
|
374
|
-
envvar_name = name[len(
|
|
373
|
+
# until the minimum Python version we support is 3.9.
|
|
374
|
+
envvar_name = name[len(_USE_ENV_PREFIX) :]
|
|
375
375
|
name = os.environ[envvar_name]
|
|
376
376
|
|
|
377
|
-
|
|
378
|
-
|
|
377
|
+
# type is a nice kwarg name for the st.connection user but is annoying to work with
|
|
378
|
+
# since it conflicts with the builtin function name and thus gets syntax
|
|
379
|
+
# highlighted.
|
|
380
|
+
connection_class = type
|
|
381
|
+
|
|
382
|
+
if connection_class is None:
|
|
383
|
+
if name in _FIRST_PARTY_CONNECTIONS:
|
|
379
384
|
# We allow users to simply write `st.connection("sql")` instead of
|
|
380
385
|
# `st.connection("sql", type="sql")`.
|
|
381
|
-
|
|
386
|
+
connection_class = _get_first_party_connection(name)
|
|
382
387
|
else:
|
|
383
388
|
# The user didn't specify a type, so we try to pull it out from their
|
|
384
389
|
# secrets.toml file. NOTE: we're okay with any of the dict lookups below
|
|
@@ -386,12 +391,7 @@ def connection_factory(
|
|
|
386
391
|
# it must be the case that it's defined in secrets.toml and should raise an
|
|
387
392
|
# Exception otherwise.
|
|
388
393
|
secrets_singleton.load_if_toml_exists()
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
# type is a nice kwarg name for the st.connection user but is annoying to work with
|
|
392
|
-
# since it conflicts with the builtin function name and thus gets syntax
|
|
393
|
-
# highlighted.
|
|
394
|
-
connection_class = type
|
|
394
|
+
connection_class = secrets_singleton["connections"][name]["type"]
|
|
395
395
|
|
|
396
396
|
if isinstance(connection_class, str):
|
|
397
397
|
# We assume that a connection_class specified via string is either the fully
|
|
@@ -424,12 +424,12 @@ def connection_factory(
|
|
|
424
424
|
return conn
|
|
425
425
|
except ModuleNotFoundError as e:
|
|
426
426
|
err_string = str(e)
|
|
427
|
-
missing_module = re.search(
|
|
427
|
+
missing_module = re.search(_MODULE_EXTRACTION_REGEX, err_string)
|
|
428
428
|
|
|
429
429
|
extra_info = "You may be missing a dependency required to use this connection."
|
|
430
430
|
if missing_module:
|
|
431
|
-
pypi_package =
|
|
431
|
+
pypi_package = _MODULES_TO_PYPI_PACKAGES.get(missing_module.group(1))
|
|
432
432
|
if pypi_package:
|
|
433
433
|
extra_info = f"You need to install the '{pypi_package}' package to use this connection."
|
|
434
434
|
|
|
435
|
-
raise ModuleNotFoundError(f"{
|
|
435
|
+
raise ModuleNotFoundError(f"{e}. {extra_info}")
|
streamlit/runtime/context.py
CHANGED
|
@@ -17,12 +17,13 @@ from __future__ import annotations
|
|
|
17
17
|
from collections.abc import Iterable, Iterator, Mapping
|
|
18
18
|
from functools import lru_cache
|
|
19
19
|
from types import MappingProxyType
|
|
20
|
-
from typing import TYPE_CHECKING, Any, cast
|
|
20
|
+
from typing import TYPE_CHECKING, Any, Literal, cast
|
|
21
21
|
|
|
22
22
|
from streamlit import runtime
|
|
23
23
|
from streamlit.runtime.context_util import maybe_add_page_path, maybe_trim_page_path
|
|
24
24
|
from streamlit.runtime.metrics_util import gather_metrics
|
|
25
25
|
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
|
26
|
+
from streamlit.util import AttributeDictionary
|
|
26
27
|
|
|
27
28
|
if TYPE_CHECKING:
|
|
28
29
|
from http.cookies import Morsel
|
|
@@ -63,8 +64,28 @@ def _normalize_header(name: str) -> str:
|
|
|
63
64
|
return "-".join(w.capitalize() for w in name.split("-"))
|
|
64
65
|
|
|
65
66
|
|
|
67
|
+
class StreamlitTheme(AttributeDictionary):
|
|
68
|
+
"""A dictionary-like object containing theme information.
|
|
69
|
+
|
|
70
|
+
This class extends the functionality of a standard dictionary to allow items
|
|
71
|
+
to be accessed via attribute-style dot notation in addition to the traditional
|
|
72
|
+
key-based access. If a dictionary item is accessed and is itself a dictionary,
|
|
73
|
+
it is automatically wrapped in another `AttributeDictionary`, enabling recursive
|
|
74
|
+
attribute-style access.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
type: Literal["dark", "light"] | None
|
|
78
|
+
|
|
79
|
+
def __init__(self, theme_info: dict[str, str | None]):
|
|
80
|
+
super().__init__(theme_info)
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def from_context_info(cls, context_dict: dict[str, str | None]) -> StreamlitTheme:
|
|
84
|
+
return cls(context_dict)
|
|
85
|
+
|
|
86
|
+
|
|
66
87
|
class StreamlitHeaders(Mapping[str, str]):
|
|
67
|
-
def __init__(self, headers: Iterable[tuple[str, str]]):
|
|
88
|
+
def __init__(self, headers: Iterable[tuple[str, str]]) -> None:
|
|
68
89
|
dict_like_headers: dict[str, list[str]] = {}
|
|
69
90
|
|
|
70
91
|
for key, value in headers:
|
|
@@ -98,7 +119,7 @@ class StreamlitHeaders(Mapping[str, str]):
|
|
|
98
119
|
|
|
99
120
|
|
|
100
121
|
class StreamlitCookies(Mapping[str, str]):
|
|
101
|
-
def __init__(self, cookies: Mapping[str, str]):
|
|
122
|
+
def __init__(self, cookies: Mapping[str, str]) -> None:
|
|
102
123
|
self._cookies = MappingProxyType(cookies)
|
|
103
124
|
|
|
104
125
|
@classmethod
|
|
@@ -215,6 +236,38 @@ class ContextProxy:
|
|
|
215
236
|
cookies = session_client_request.cookies
|
|
216
237
|
return StreamlitCookies.from_tornado_cookies(cookies)
|
|
217
238
|
|
|
239
|
+
@property
|
|
240
|
+
@gather_metrics("context.theme")
|
|
241
|
+
def theme(self) -> StreamlitTheme:
|
|
242
|
+
"""A read-only, dictionary-like object containing theme information.
|
|
243
|
+
|
|
244
|
+
Theme information is restricted to the ``type`` of the theme (dark or
|
|
245
|
+
light) and is inferred from the background color of the app.
|
|
246
|
+
|
|
247
|
+
.. note::
|
|
248
|
+
Changes made to the background color through CSS are not included.
|
|
249
|
+
|
|
250
|
+
Attributes
|
|
251
|
+
----------
|
|
252
|
+
type : "light", "dark"
|
|
253
|
+
The theme type inferred from the background color of the app.
|
|
254
|
+
|
|
255
|
+
Example
|
|
256
|
+
-------
|
|
257
|
+
Access the theme type of the app:
|
|
258
|
+
|
|
259
|
+
>>> import streamlit as st
|
|
260
|
+
>>>
|
|
261
|
+
>>> st.write(f"The current theme type is {st.context.theme.type}.")
|
|
262
|
+
|
|
263
|
+
"""
|
|
264
|
+
ctx = get_script_run_ctx()
|
|
265
|
+
|
|
266
|
+
if ctx is None or ctx.context_info is None:
|
|
267
|
+
return StreamlitTheme({"type": None})
|
|
268
|
+
|
|
269
|
+
return StreamlitTheme.from_context_info({"type": ctx.context_info.color_scheme})
|
|
270
|
+
|
|
218
271
|
@property
|
|
219
272
|
@gather_metrics("context.timezone")
|
|
220
273
|
def timezone(self) -> str | None:
|
|
@@ -328,11 +381,7 @@ class ContextProxy:
|
|
|
328
381
|
url_without_page_prefix = maybe_trim_page_path(
|
|
329
382
|
url_from_frontend, ctx.pages_manager
|
|
330
383
|
)
|
|
331
|
-
|
|
332
|
-
url_without_page_prefix, ctx.pages_manager
|
|
333
|
-
)
|
|
334
|
-
|
|
335
|
-
return url_with_page_prefix
|
|
384
|
+
return maybe_add_page_path(url_without_page_prefix, ctx.pages_manager)
|
|
336
385
|
|
|
337
386
|
@property
|
|
338
387
|
@gather_metrics("context.ip_address")
|
|
@@ -367,7 +416,7 @@ class ContextProxy:
|
|
|
367
416
|
session_client_request = _get_request()
|
|
368
417
|
if session_client_request is not None:
|
|
369
418
|
remote_ip = session_client_request.remote_ip
|
|
370
|
-
if remote_ip
|
|
419
|
+
if remote_ip in {"::1", "127.0.0.1"}:
|
|
371
420
|
return None
|
|
372
421
|
return remote_ip
|
|
373
422
|
return None
|
streamlit/runtime/credentials.py
CHANGED
|
@@ -20,7 +20,7 @@ import json
|
|
|
20
20
|
import os
|
|
21
21
|
import sys
|
|
22
22
|
import textwrap
|
|
23
|
-
from typing import Final, NamedTuple, NoReturn
|
|
23
|
+
from typing import Final, NamedTuple, NoReturn, cast
|
|
24
24
|
from uuid import uuid4
|
|
25
25
|
|
|
26
26
|
from streamlit import cli_util, env_util, file_util, util
|
|
@@ -29,10 +29,11 @@ from streamlit.logger import get_logger
|
|
|
29
29
|
_LOGGER: Final = get_logger(__name__)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
_CONFIG_FILE_PATH: Final = (
|
|
33
|
+
r"%userprofile%/.streamlit/config.toml"
|
|
34
|
+
if env_util.IS_WINDOWS
|
|
35
|
+
else "~/.streamlit/config.toml"
|
|
36
|
+
)
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
class _Activation(NamedTuple):
|
|
@@ -53,7 +54,7 @@ def email_prompt() -> str:
|
|
|
53
54
|
return f"""
|
|
54
55
|
{"👋 " if show_emoji else ""}{cli_util.style_for_cli("Welcome to Streamlit!", bold=True)}
|
|
55
56
|
|
|
56
|
-
If you
|
|
57
|
+
If you'd like to receive helpful onboarding emails, news, offers, promotions,
|
|
57
58
|
and the occasional swag, please enter your email address below. Otherwise,
|
|
58
59
|
leave this field blank.
|
|
59
60
|
|
|
@@ -65,7 +66,7 @@ Collecting usage statistics. To deactivate, set browser.gatherUsageStats to fals
|
|
|
65
66
|
"""
|
|
66
67
|
|
|
67
68
|
|
|
68
|
-
def _send_email(email: str) -> None:
|
|
69
|
+
def _send_email(email: str | None) -> None:
|
|
69
70
|
"""Send the user's email for metrics, if submitted."""
|
|
70
71
|
import requests
|
|
71
72
|
|
|
@@ -79,7 +80,7 @@ def _send_email(email: str) -> None:
|
|
|
79
80
|
).json()
|
|
80
81
|
metrics_url = response_json.get("url", "")
|
|
81
82
|
except Exception:
|
|
82
|
-
_LOGGER.
|
|
83
|
+
_LOGGER.exception("Failed to fetch metrics URL")
|
|
83
84
|
return
|
|
84
85
|
|
|
85
86
|
headers = {
|
|
@@ -104,6 +105,7 @@ def _send_email(email: str) -> None:
|
|
|
104
105
|
metrics_url,
|
|
105
106
|
headers=headers,
|
|
106
107
|
data=json.dumps(data).encode(),
|
|
108
|
+
timeout=10,
|
|
107
109
|
)
|
|
108
110
|
|
|
109
111
|
response.raise_for_status()
|
|
@@ -115,22 +117,22 @@ class Credentials:
|
|
|
115
117
|
_singleton: Credentials | None = None
|
|
116
118
|
|
|
117
119
|
@classmethod
|
|
118
|
-
def get_current(cls):
|
|
120
|
+
def get_current(cls) -> Credentials:
|
|
119
121
|
"""Return the singleton instance."""
|
|
120
122
|
if cls._singleton is None:
|
|
121
123
|
Credentials()
|
|
122
124
|
|
|
123
|
-
return Credentials._singleton
|
|
125
|
+
return cast("Credentials", Credentials._singleton)
|
|
124
126
|
|
|
125
|
-
def __init__(self):
|
|
127
|
+
def __init__(self) -> None:
|
|
126
128
|
"""Initialize class."""
|
|
127
129
|
if Credentials._singleton is not None:
|
|
128
130
|
raise RuntimeError(
|
|
129
131
|
"Credentials already initialized. Use .get_current() instead"
|
|
130
132
|
)
|
|
131
133
|
|
|
132
|
-
self.activation = None
|
|
133
|
-
self._conf_file = _get_credential_file_path()
|
|
134
|
+
self.activation: _Activation | None = None
|
|
135
|
+
self._conf_file: str = _get_credential_file_path()
|
|
134
136
|
|
|
135
137
|
Credentials._singleton = self
|
|
136
138
|
|
|
@@ -149,7 +151,7 @@ class Credentials:
|
|
|
149
151
|
with open(self._conf_file) as f:
|
|
150
152
|
data = toml.load(f).get("general")
|
|
151
153
|
if data is None:
|
|
152
|
-
raise
|
|
154
|
+
raise RuntimeError # noqa: TRY301
|
|
153
155
|
self.activation = _verify_email(data.get("email"))
|
|
154
156
|
except FileNotFoundError:
|
|
155
157
|
if auto_resolve:
|
|
@@ -163,7 +165,7 @@ class Credentials:
|
|
|
163
165
|
self.reset()
|
|
164
166
|
self.activate(show_instructions=not auto_resolve)
|
|
165
167
|
return
|
|
166
|
-
raise
|
|
168
|
+
raise RuntimeError(
|
|
167
169
|
textwrap.dedent(
|
|
168
170
|
"""
|
|
169
171
|
Unable to load credentials from %s.
|
|
@@ -261,43 +263,30 @@ class Credentials:
|
|
|
261
263
|
if self.activation.is_valid:
|
|
262
264
|
self.save()
|
|
263
265
|
# IMPORTANT: Break the text below at 80 chars.
|
|
264
|
-
|
|
265
|
-
You can find our privacy policy at
|
|
266
|
+
telemetry_text = f"""
|
|
267
|
+
You can find our privacy policy at {cli_util.style_for_cli("https://streamlit.io/privacy-policy", underline=True)}
|
|
266
268
|
|
|
267
269
|
Summary:
|
|
268
270
|
- This open source library collects usage statistics.
|
|
269
271
|
- We cannot see and do not store information contained inside Streamlit apps,
|
|
270
272
|
such as text, charts, images, etc.
|
|
271
273
|
- Telemetry data is stored in servers in the United States.
|
|
272
|
-
- If you'd like to opt out, add the following to
|
|
274
|
+
- If you'd like to opt out, add the following to {cli_util.style_for_cli(_CONFIG_FILE_PATH)},
|
|
273
275
|
creating that file if necessary:
|
|
274
276
|
|
|
275
277
|
[browser]
|
|
276
278
|
gatherUsageStats = false
|
|
277
|
-
"""
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
),
|
|
281
|
-
"config": cli_util.style_for_cli(_CONFIG_FILE_PATH),
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
cli_util.print_to_cli(TELEMETRY_TEXT)
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
cli_util.print_to_cli(telemetry_text)
|
|
285
282
|
if show_instructions:
|
|
286
283
|
# IMPORTANT: Break the text below at 80 chars.
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
"""
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
),
|
|
294
|
-
"prompt": cli_util.style_for_cli("$", fg="blue"),
|
|
295
|
-
"hello": cli_util.style_for_cli(
|
|
296
|
-
"streamlit hello", bold=True
|
|
297
|
-
),
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
cli_util.print_to_cli(INSTRUCTIONS_TEXT)
|
|
284
|
+
instructions_text = f"""
|
|
285
|
+
{cli_util.style_for_cli("Get started by typing:", fg="blue", bold=True)}
|
|
286
|
+
{cli_util.style_for_cli("$", fg="blue")} {cli_util.style_for_cli("streamlit hello", bold=True)}
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
cli_util.print_to_cli(instructions_text)
|
|
301
290
|
activated = True
|
|
302
291
|
else: # pragma: nocover
|
|
303
292
|
_LOGGER.error("Please try again.")
|
|
@@ -41,7 +41,7 @@ class ForwardMsgQueue:
|
|
|
41
41
|
"""
|
|
42
42
|
ForwardMsgQueue._before_enqueue_msg = before_enqueue_msg
|
|
43
43
|
|
|
44
|
-
def __init__(self):
|
|
44
|
+
def __init__(self) -> None:
|
|
45
45
|
self._queue: list[ForwardMsg] = []
|
|
46
46
|
# A mapping of (delta_path -> _queue.indexof(msg)) for each
|
|
47
47
|
# Delta message in the queue. We use this for coalescing
|
|
@@ -82,13 +82,13 @@ class ForwardMsgQueue:
|
|
|
82
82
|
# since the queue can be flushed to the browser at any time.
|
|
83
83
|
# For example:
|
|
84
84
|
# queue 1:
|
|
85
|
-
# empty [0, 0] <- skipped
|
|
86
|
-
# markdown [0, 0]
|
|
87
|
-
# empty [1, 0] <- send to frontend
|
|
85
|
+
# > empty [0, 0] <- skipped
|
|
86
|
+
# > markdown [0, 0]
|
|
87
|
+
# > empty [1, 0] <- send to frontend
|
|
88
88
|
#
|
|
89
89
|
# queue 2:
|
|
90
|
-
# markdown [1, 0]
|
|
91
|
-
# ...
|
|
90
|
+
# > markdown [1, 0]
|
|
91
|
+
# > ...
|
|
92
92
|
|
|
93
93
|
delta_key = tuple(msg.metadata.delta_path)
|
|
94
94
|
if delta_key in self._delta_index_map:
|
|
@@ -184,7 +184,7 @@ def _is_composable_message(msg: ForwardMsg) -> bool:
|
|
|
184
184
|
# operation can raise errors, and we don't have a good way of handling
|
|
185
185
|
# those errors in the message queue.
|
|
186
186
|
delta_type = msg.delta.WhichOneof("type")
|
|
187
|
-
return delta_type
|
|
187
|
+
return delta_type not in {"add_rows", "arrow_add_rows"}
|
|
188
188
|
|
|
189
189
|
|
|
190
190
|
def _maybe_compose_delta_msgs(
|
|
@@ -204,9 +204,9 @@ def _maybe_compose_delta_msgs(
|
|
|
204
204
|
# We never replace add_block deltas, because blocks can have
|
|
205
205
|
# other dependent deltas later in the queue. For example:
|
|
206
206
|
#
|
|
207
|
-
#
|
|
208
|
-
#
|
|
209
|
-
#
|
|
207
|
+
# > placeholder = st.empty()
|
|
208
|
+
# > placeholder.columns(1)
|
|
209
|
+
# > placeholder.empty()
|
|
210
210
|
#
|
|
211
211
|
# The call to "placeholder.columns(1)" creates two blocks, a parent
|
|
212
212
|
# container with delta_path (0, 0), and a column child with
|
|
@@ -222,7 +222,7 @@ def _maybe_compose_delta_msgs(
|
|
|
222
222
|
return new_msg
|
|
223
223
|
|
|
224
224
|
new_delta_type = new_msg.delta.WhichOneof("type")
|
|
225
|
-
if new_delta_type
|
|
225
|
+
if new_delta_type in {"new_element", "add_block"}:
|
|
226
226
|
return new_msg
|
|
227
227
|
|
|
228
228
|
return None
|
streamlit/runtime/fragment.py
CHANGED
|
@@ -155,11 +155,10 @@ def _fragment(
|
|
|
155
155
|
)
|
|
156
156
|
|
|
157
157
|
return wrapper
|
|
158
|
-
|
|
159
|
-
non_optional_func = func
|
|
158
|
+
non_optional_func = func
|
|
160
159
|
|
|
161
160
|
@wraps(non_optional_func)
|
|
162
|
-
def wrap(*args, **kwargs):
|
|
161
|
+
def wrap(*args: Any, **kwargs: Any) -> Any:
|
|
163
162
|
from streamlit.delta_generator_singletons import context_dg_stack
|
|
164
163
|
|
|
165
164
|
ctx = get_script_run_ctx()
|
|
@@ -176,7 +175,7 @@ def _fragment(
|
|
|
176
175
|
# that the fragment is associated with the correct script running.
|
|
177
176
|
initialized_active_script_hash = ctx.active_script_hash
|
|
178
177
|
|
|
179
|
-
def wrapped_fragment():
|
|
178
|
+
def wrapped_fragment() -> Any:
|
|
180
179
|
import streamlit as st
|
|
181
180
|
|
|
182
181
|
if should_show_deprecation_warning:
|
|
@@ -193,7 +192,8 @@ def _fragment(
|
|
|
193
192
|
# fragment runs will generally run in a new script run, thus we'll have a
|
|
194
193
|
# new ctx.
|
|
195
194
|
ctx = get_script_run_ctx(suppress_warning=True)
|
|
196
|
-
|
|
195
|
+
if ctx is None:
|
|
196
|
+
raise RuntimeError("ctx is None. This should never happen.")
|
|
197
197
|
|
|
198
198
|
if ctx.fragment_ids_this_run:
|
|
199
199
|
# This script run is a run of one or more fragments. We restore the
|
|
@@ -246,11 +246,11 @@ def _fragment(
|
|
|
246
246
|
except (
|
|
247
247
|
RerunException,
|
|
248
248
|
StopException,
|
|
249
|
-
)
|
|
249
|
+
):
|
|
250
250
|
# The wrapped_fragment function is executed
|
|
251
251
|
# inside of a exec_func_with_error_handling call, so
|
|
252
252
|
# there is a correct handler for these exceptions.
|
|
253
|
-
raise
|
|
253
|
+
raise
|
|
254
254
|
except Exception as e:
|
|
255
255
|
# render error here so that the delta path is correct
|
|
256
256
|
# for full app runs, the error will be displayed by the
|