streamlit 1.53.1__py3-none-any.whl → 1.54.0__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 +1 -31
- streamlit/auth_util.py +91 -2
- streamlit/cli_util.py +3 -2
- streamlit/commands/echo.py +2 -2
- streamlit/commands/execution_control.py +1 -1
- streamlit/commands/logo.py +76 -24
- streamlit/commands/navigation.py +1 -1
- streamlit/components/types/base_custom_component.py +0 -2
- streamlit/components/v1/custom_component.py +0 -2
- streamlit/components/v2/bidi_component/main.py +2 -2
- streamlit/components/v2/component_path_utils.py +17 -29
- streamlit/components/v2/manifest_scanner.py +8 -3
- streamlit/components/v2/presentation.py +1 -1
- streamlit/config.py +57 -13
- streamlit/config_util.py +5 -5
- streamlit/connections/snowflake_connection.py +5 -3
- streamlit/dataframe_util.py +10 -10
- streamlit/deprecation_util.py +19 -1
- streamlit/elements/arrow.py +18 -8
- streamlit/elements/deck_gl_json_chart.py +6 -2
- streamlit/elements/exception.py +4 -2
- streamlit/elements/form.py +1 -1
- streamlit/elements/layouts.py +1 -1
- streamlit/elements/lib/built_in_chart_utils.py +36 -13
- streamlit/elements/lib/color_util.py +21 -2
- streamlit/elements/lib/column_config_utils.py +9 -7
- streamlit/elements/lib/dialog.py +1 -1
- streamlit/elements/lib/image_utils.py +5 -5
- streamlit/elements/lib/layout_utils.py +1 -1
- streamlit/elements/lib/options_selector_utils.py +72 -22
- streamlit/elements/lib/policies.py +1 -1
- streamlit/elements/lib/streamlit_plotly_theme.py +9 -11
- streamlit/elements/lib/utils.py +1 -1
- streamlit/elements/map.py +6 -6
- streamlit/elements/plotly_chart.py +2 -2
- streamlit/elements/toast.py +1 -1
- streamlit/elements/vega_charts.py +30 -7
- streamlit/elements/widgets/button.py +3 -3
- streamlit/elements/widgets/button_group.py +3 -3
- streamlit/elements/widgets/chat.py +1 -1
- streamlit/elements/widgets/data_editor.py +6 -6
- streamlit/elements/widgets/multiselect.py +1 -1
- streamlit/elements/widgets/number_input.py +1 -1
- streamlit/elements/widgets/radio.py +91 -31
- streamlit/elements/widgets/select_slider.py +123 -37
- streamlit/elements/widgets/slider.py +5 -5
- streamlit/elements/widgets/time_widgets.py +150 -18
- streamlit/elements/write.py +2 -3
- streamlit/env_util.py +1 -1
- streamlit/errors.py +2 -14
- streamlit/external/langchain/streamlit_callback_handler.py +1 -1
- streamlit/hello/dataframe_demo.py +1 -1
- streamlit/hello/plotting_demo.py +19 -12
- streamlit/path_security.py +98 -0
- streamlit/proto/Alert_pb2.py +2 -3
- streamlit/proto/AppPage_pb2.py +2 -3
- streamlit/proto/ArrowData_pb2.py +2 -3
- streamlit/proto/ArrowNamedDataSet_pb2.py +2 -3
- streamlit/proto/ArrowVegaLiteChart_pb2.py +2 -3
- streamlit/proto/Arrow_pb2.py +2 -3
- streamlit/proto/AudioInput_pb2.py +2 -3
- streamlit/proto/Audio_pb2.py +2 -3
- streamlit/proto/AuthRedirect_pb2.py +2 -3
- streamlit/proto/AutoRerun_pb2.py +2 -3
- streamlit/proto/BackMsg_pb2.py +2 -3
- streamlit/proto/Balloons_pb2.py +2 -3
- streamlit/proto/BidiComponent_pb2.py +2 -3
- streamlit/proto/Block_pb2.py +2 -3
- streamlit/proto/BokehChart_pb2.py +2 -3
- streamlit/proto/ButtonGroup_pb2.py +2 -3
- streamlit/proto/ButtonLikeIconPosition_pb2.py +2 -3
- streamlit/proto/Button_pb2.py +2 -3
- streamlit/proto/CameraInput_pb2.py +2 -3
- streamlit/proto/ChatInput_pb2.py +2 -3
- streamlit/proto/Checkbox_pb2.py +2 -3
- streamlit/proto/ClientState_pb2.py +2 -3
- streamlit/proto/Code_pb2.py +2 -3
- streamlit/proto/ColorPicker_pb2.py +2 -3
- streamlit/proto/Common_pb2.py +2 -3
- streamlit/proto/Components_pb2.py +2 -3
- streamlit/proto/DataFrame_pb2.py +2 -3
- streamlit/proto/DateInput_pb2.py +2 -3
- streamlit/proto/DateTimeInput_pb2.py +2 -3
- streamlit/proto/DeckGlJsonChart_pb2.py +2 -3
- streamlit/proto/Delta_pb2.py +2 -3
- streamlit/proto/DocString_pb2.py +2 -3
- streamlit/proto/DownloadButton_pb2.py +2 -3
- streamlit/proto/Element_pb2.py +2 -3
- streamlit/proto/Empty_pb2.py +2 -3
- streamlit/proto/Exception_pb2.py +2 -3
- streamlit/proto/Favicon_pb2.py +2 -3
- streamlit/proto/FileUploader_pb2.py +2 -3
- streamlit/proto/ForwardMsg_pb2.py +2 -3
- streamlit/proto/GapSize_pb2.py +2 -3
- streamlit/proto/GitInfo_pb2.py +2 -3
- streamlit/proto/GraphVizChart_pb2.py +2 -3
- streamlit/proto/Heading_pb2.py +2 -3
- streamlit/proto/HeightConfig_pb2.py +2 -3
- streamlit/proto/Html_pb2.py +2 -3
- streamlit/proto/IFrame_pb2.py +2 -3
- streamlit/proto/Image_pb2.py +2 -3
- streamlit/proto/Json_pb2.py +2 -3
- streamlit/proto/LabelVisibilityMessage_pb2.py +2 -3
- streamlit/proto/LinkButton_pb2.py +2 -3
- streamlit/proto/Logo_pb2.py +6 -5
- streamlit/proto/Logo_pb2.pyi +25 -1
- streamlit/proto/Markdown_pb2.py +2 -3
- streamlit/proto/Metric_pb2.py +2 -3
- streamlit/proto/MetricsEvent_pb2.py +2 -3
- streamlit/proto/MultiSelect_pb2.py +2 -3
- streamlit/proto/NamedDataSet_pb2.py +2 -3
- streamlit/proto/Navigation_pb2.py +2 -3
- streamlit/proto/NewSession_pb2.py +25 -24
- streamlit/proto/NewSession_pb2.pyi +28 -2
- streamlit/proto/NumberInput_pb2.py +2 -3
- streamlit/proto/PageConfig_pb2.py +2 -3
- streamlit/proto/PageInfo_pb2.py +2 -3
- streamlit/proto/PageLink_pb2.py +2 -3
- streamlit/proto/PageNotFound_pb2.py +2 -3
- streamlit/proto/PageProfile_pb2.py +2 -3
- streamlit/proto/PagesChanged_pb2.py +2 -3
- streamlit/proto/ParentMessage_pb2.py +2 -3
- streamlit/proto/PlotlyChart_pb2.py +2 -3
- streamlit/proto/Progress_pb2.py +2 -3
- streamlit/proto/Radio_pb2.py +5 -4
- streamlit/proto/Radio_pb2.pyi +20 -3
- streamlit/proto/RootContainer_pb2.py +2 -3
- streamlit/proto/Selectbox_pb2.py +2 -3
- streamlit/proto/SessionEvent_pb2.py +2 -3
- streamlit/proto/SessionStatus_pb2.py +2 -3
- streamlit/proto/Skeleton_pb2.py +2 -3
- streamlit/proto/Slider_pb2.py +7 -8
- streamlit/proto/Slider_pb2.pyi +9 -1
- streamlit/proto/Snow_pb2.py +2 -3
- streamlit/proto/Space_pb2.py +2 -3
- streamlit/proto/Spinner_pb2.py +2 -3
- streamlit/proto/TextAlignmentConfig_pb2.py +2 -3
- streamlit/proto/TextArea_pb2.py +2 -3
- streamlit/proto/TextInput_pb2.py +2 -3
- streamlit/proto/Text_pb2.py +2 -3
- streamlit/proto/TimeInput_pb2.py +2 -3
- streamlit/proto/Toast_pb2.py +2 -3
- streamlit/proto/Transient_pb2.py +2 -3
- streamlit/proto/VegaLiteChart_pb2.py +2 -3
- streamlit/proto/Video_pb2.py +2 -3
- streamlit/proto/WidgetStates_pb2.py +2 -3
- streamlit/proto/WidthConfig_pb2.py +2 -3
- streamlit/proto/openmetrics_data_model_pb2.py +2 -3
- streamlit/runtime/app_session.py +106 -60
- streamlit/runtime/caching/cache_data_api.py +3 -3
- streamlit/runtime/caching/cache_errors.py +0 -2
- streamlit/runtime/caching/cache_resource_api.py +1 -1
- streamlit/runtime/caching/cache_utils.py +2 -2
- streamlit/runtime/caching/hashing.py +1 -3
- streamlit/runtime/caching/storage/cache_storage_protocol.py +0 -3
- streamlit/runtime/connection_factory.py +1 -1
- streamlit/runtime/credentials.py +2 -2
- streamlit/runtime/metrics_util.py +3 -3
- streamlit/runtime/runtime.py +6 -6
- streamlit/runtime/scriptrunner/script_runner.py +17 -0
- streamlit/runtime/scriptrunner_utils/exceptions.py +0 -4
- streamlit/runtime/scriptrunner_utils/script_run_context.py +13 -31
- streamlit/runtime/secrets.py +3 -4
- streamlit/runtime/state/__init__.py +7 -1
- streamlit/runtime/state/common.py +13 -0
- streamlit/runtime/state/query_params.py +493 -24
- streamlit/runtime/state/session_state.py +179 -4
- streamlit/runtime/state/widgets.py +26 -1
- streamlit/runtime/stats.py +1 -10
- streamlit/static/index.html +1 -1
- streamlit/static/manifest.json +304 -304
- streamlit/static/static/js/{ErrorOutline.esm.CScZvf44.js → ErrorOutline.esm.BWk6F-Tz.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.COCxTZxP.js → FileDownload.esm.AllYUuOW.js} +1 -1
- streamlit/static/static/js/{FileHelper.Bhs-iVRI.js → FileHelper.BvVTNdmy.js} +1 -1
- streamlit/static/static/js/{FormClearHelper.CA_5b-Ut.js → FormClearHelper.C__r5Llk.js} +1 -1
- streamlit/static/static/js/{InputInstructions.Bzb0MCfv.js → InputInstructions.DOtkdOMV.js} +1 -1
- streamlit/static/static/js/Particles.DCsqQZlE.js +1 -0
- streamlit/static/static/js/{ProgressBar.DyQNhVsJ.js → ProgressBar.DLCRvt4m.js} +2 -2
- streamlit/static/static/js/{StreamlitSyntaxHighlighter.BOkJThtV.js → StreamlitSyntaxHighlighter.CYFWoZHb.js} +1 -1
- streamlit/static/static/js/{TableChart.esm.a60nntBC.js → TableChart.esm.D6ydHcIm.js} +1 -1
- streamlit/static/static/js/Toolbar.BHDNzWBx.js +1 -0
- streamlit/static/static/js/{WidgetLabelHelpIconInline.BjIku2ic.js → WidgetLabelHelpIconInline.DEXBrVlc.js} +1 -1
- streamlit/static/static/js/{base-input.avGkArOc.js → base-input.TSQjctlq.js} +4 -4
- streamlit/static/static/js/{checkbox.Q8mCuqps.js → checkbox.BKgfzJZV.js} +1 -1
- streamlit/static/static/js/{createDownloadLinkElement.CfqHRpxo.js → createDownloadLinkElement.CG7nr2a4.js} +1 -1
- streamlit/static/static/js/{data-grid-overlay-editor.PuoMl3yV.js → data-grid-overlay-editor.ChXO__lP.js} +1 -1
- streamlit/static/static/js/{downloader.CjG2csSm.js → downloader.DJ3R_zWA.js} +1 -1
- streamlit/static/static/js/embed.u3PPfLkw.js +193 -0
- streamlit/static/static/js/{es6.CQD6uUK7.js → es6.C5Mfy8nd.js} +2 -2
- streamlit/static/static/js/{formatNumber.CtjUO-if.js → formatNumber.CMRgW9EJ.js} +1 -1
- streamlit/static/static/js/{iconPosition.7Qt6oUiI.js → iconPosition.B4EEXI3E.js} +1 -1
- streamlit/static/static/js/{iframeResizer.contentWindow._oj2Xh0v.js → iframeResizer.contentWindow.WSvOiTW0.js} +1 -1
- streamlit/static/static/js/index.-FOBV3nz.js +1 -0
- streamlit/static/static/js/{index.BuBkymZd.js → index.-NF8OSF5.js} +1 -1
- streamlit/static/static/js/{index.B-XrnnK6.js → index.4cBg8kn5.js} +1 -1
- streamlit/static/static/js/{index.B_ylV_tl.js → index.B0pzzCsH.js} +1 -1
- streamlit/static/static/js/{index.BhJwyXH6.js → index.BID6ND5j.js} +2 -2
- streamlit/static/static/js/index.BMp5bGjh.js +1 -0
- streamlit/static/static/js/{index.Cptu1tS-.js → index.BQcmlvas.js} +1 -1
- streamlit/static/static/js/{index.DXQ_Fvpt.js → index.BRcmclgI.js} +1 -1
- streamlit/static/static/js/index.BaUZR4IG.js +1 -0
- streamlit/static/static/js/{index.CMBgAPh6.js → index.BbMJj4PN.js} +1 -1
- streamlit/static/static/js/{index.CVRgrLT-.js → index.BdCTJtq3.js} +2 -2
- streamlit/static/static/js/index.BdETLMuI.js +1 -0
- streamlit/static/static/js/index.BnKMWhs1.js +1 -0
- streamlit/static/static/js/index.Br1kXwQW.js +2 -0
- streamlit/static/static/js/{index.XGft6-dq.js → index.Bt2olRE4.js} +1 -1
- streamlit/static/static/js/{index.B2fAYU1N.js → index.Bxwsv5T8.js} +1 -1
- streamlit/static/static/js/index.C4KskYz6.js +1 -0
- streamlit/static/static/js/{index.DZE_91Ym.js → index.C6bmbXk0.js} +1 -1
- streamlit/static/static/js/{index.Egabyb7u.js → index.CEfKfbta.js} +1 -1
- streamlit/static/static/js/index.CIuaA8q0.js +2 -0
- streamlit/static/static/js/{index.DVtfSohT.js → index.CV1sObFX.js} +1 -1
- streamlit/static/static/js/{index.BlJhnb4M.js → index.CbR6dgaV.js} +1 -1
- streamlit/static/static/js/index.Cq6szKqJ.js +1 -0
- streamlit/static/static/js/index.CyouXqCz.js +1 -0
- streamlit/static/static/js/{index.B5wmZkRW.js → index.D1NUgMFI.js} +1 -1
- streamlit/static/static/js/{index.euRMkmNi.js → index.D7SWG4Om.js} +1 -1
- streamlit/static/static/js/{index.Bg-9YNUa.js → index.DAYPEwLI.js} +1 -1
- streamlit/static/static/js/index.DKS75Vfg.js +11 -0
- streamlit/static/static/js/{index.CIizdLeb.js → index.DOXrMIxB.js} +1 -1
- streamlit/static/static/js/{index.BRegnbUa.js → index.DOzYX8yS.js} +3 -3
- streamlit/static/static/js/{index.BksGMsW0.js → index.DRFMYcC4.js} +4 -4
- streamlit/static/static/js/{index.B8PovXCX.js → index.Divl5FCY.js} +1 -1
- streamlit/static/static/js/{index.DxQuXlXH.js → index.DjAJ_CUa.js} +1 -1
- streamlit/static/static/js/{index.BrRuSP42.js → index.Dncue2pm.js} +33 -33
- streamlit/static/static/js/{index.DSTThs-t.js → index.Drusyo5m.js} +47 -47
- streamlit/static/static/js/{index.BOafPwIE.js → index.DuUyDGnP.js} +1 -1
- streamlit/static/static/js/{index.D1bkwsLT.js → index.DvgT2rB2.js} +223 -223
- streamlit/static/static/js/{index.BmDXWfgx.js → index.DzutABu5.js} +2 -2
- streamlit/static/static/js/index.Dzw2iPzi.js +3 -0
- streamlit/static/static/js/{index.DJsqD2Sc.js → index.FsTmxLbT.js} +1 -1
- streamlit/static/static/js/{index.BOTEMJfV.js → index.OIwPqGYN.js} +1 -1
- streamlit/static/static/js/{index.CBqST2Yj.js → index.RXLN7YFT.js} +2 -2
- streamlit/static/static/js/{index.Ft2Zxbhr.js → index.YYb2u0jk.js} +2 -2
- streamlit/static/static/js/{index.BWCFtBS4.js → index.h8ejt-W3.js} +1 -1
- streamlit/static/static/js/{index.KuLql7H0.js → index.lFMCi9am.js} +1 -1
- streamlit/static/static/js/{index.D8t7R4QQ.js → index.pOgf4cEj.js} +1 -1
- streamlit/static/static/js/{index.CsoN0h7K.js → index.s_E0s7LB.js} +51 -51
- streamlit/static/static/js/{index.BVX_bqnf.js → index.xLCbzoqj.js} +1 -1
- streamlit/static/static/js/{input.Cf97CQME.js → input.BLG7kWaj.js} +2 -2
- streamlit/static/static/js/{main.Ccuk53yQ.js → main.D_CmqChN.js} +1 -1
- streamlit/static/static/js/{memory.Bng6Ij0g.js → memory.T8u9KqIQ.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.CFLv-CWC.js → number-overlay-editor.BKBSXkAM.js} +2 -2
- streamlit/static/static/js/{pandasStylerUtils.C2hcAKiv.js → pandasStylerUtils.B4tLYMwS.js} +1 -1
- streamlit/static/static/js/{sandbox.BXdeD-wA.js → sandbox.jRlkcPem.js} +1 -1
- streamlit/static/static/js/{styled-components.Br04Ogac.js → styled-components.D2QhNwzd.js} +1 -1
- streamlit/static/static/js/{throttle.mI9ItGre.js → throttle.Cyw_V0Dq.js} +1 -1
- streamlit/static/static/js/{timepicker.poFdB0sd.js → timepicker.PzyuDDWl.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.92-fANS-.js → toConsumableArray.gE9fMkLj.js} +1 -1
- streamlit/static/static/js/uniqueId.B1GeHnT1.js +1 -0
- streamlit/static/static/js/{useBasicWidgetState.DzKGLAv_.js → useBasicWidgetState.DFklfao0.js} +1 -1
- streamlit/static/static/js/{useIntlLocale.BMma2iiY.js → useIntlLocale.C3tUGWTU.js} +8 -8
- streamlit/static/static/js/{useTextInputAutoExpand.DQbIhdma.js → useTextInputAutoExpand.D9nU_y-e.js} +1 -1
- streamlit/static/static/js/useUpdateUiValue.ClTdrkJN.js +1 -0
- streamlit/static/static/js/{useWaveformController.AH0ggRyc.js → useWaveformController.lzTbjMW2.js} +1 -1
- streamlit/static/static/js/{withCalculatedWidth.G5xJ-MbS.js → withCalculatedWidth.Dxs9I5Oe.js} +1 -1
- streamlit/static/static/js/{withFullScreenWrapper.rdRu6zZ4.js → withFullScreenWrapper.DfpAcJxf.js} +1 -1
- streamlit/string_util.py +2 -2
- streamlit/testing/v1/app_test.py +1 -1
- streamlit/testing/v1/element_tree.py +33 -20
- streamlit/type_util.py +2 -2
- streamlit/url_util.py +2 -2
- streamlit/user_info.py +2 -41
- streamlit/util.py +1 -1
- streamlit/watcher/event_based_path_watcher.py +37 -7
- streamlit/watcher/path_watcher.py +61 -2
- streamlit/watcher/util.py +26 -10
- streamlit/web/bootstrap.py +16 -4
- streamlit/web/cli.py +1 -4
- streamlit/web/server/app_discovery.py +2 -1
- streamlit/web/server/app_static_file_handler.py +9 -0
- streamlit/web/server/bidi_component_request_handler.py +4 -4
- streamlit/web/server/component_file_utils.py +14 -6
- streamlit/web/server/component_request_handler.py +2 -2
- streamlit/web/server/oauth_authlib_routes.py +14 -42
- streamlit/web/server/server.py +1 -1
- streamlit/web/server/server_util.py +23 -1
- streamlit/web/server/starlette/starlette_app.py +7 -1
- streamlit/web/server/starlette/starlette_auth_routes.py +94 -16
- streamlit/web/server/starlette/starlette_path_security_middleware.py +97 -0
- streamlit/web/server/starlette/starlette_routes.py +16 -9
- streamlit/web/server/starlette/starlette_server.py +2 -2
- streamlit/web/server/starlette/starlette_static_routes.py +14 -4
- streamlit/web/server/stats_request_handler.py +1 -3
- {streamlit-1.53.1.dist-info → streamlit-1.54.0.dist-info}/METADATA +10 -25
- {streamlit-1.53.1.dist-info → streamlit-1.54.0.dist-info}/RECORD +290 -290
- {streamlit-1.53.1.dist-info → streamlit-1.54.0.dist-info}/WHEEL +1 -1
- streamlit/commands/experimental_query_params.py +0 -169
- streamlit/static/static/js/Particles.ix5_l22I.js +0 -1
- streamlit/static/static/js/Toolbar.CxkcuBQ8.js +0 -1
- streamlit/static/static/js/embed.DZ-CLCPz.js +0 -195
- streamlit/static/static/js/index.B6ZAXv47.js +0 -1
- streamlit/static/static/js/index.BDm-Ia27.js +0 -1
- streamlit/static/static/js/index.BeCZLkzg.js +0 -1
- streamlit/static/static/js/index.BuEBeckn.js +0 -11
- streamlit/static/static/js/index.CL2eCR01.js +0 -1
- streamlit/static/static/js/index.CdLlbsiN.js +0 -1
- streamlit/static/static/js/index.CwIIk90V.js +0 -1
- streamlit/static/static/js/index.DDk0U8rh.js +0 -2
- streamlit/static/static/js/index.DNB79dOd.js +0 -3
- streamlit/static/static/js/index.DNj5S4tY.js +0 -1
- streamlit/static/static/js/index.DOY0ZriT.js +0 -2
- streamlit/static/static/js/index.r0gCrMFP.js +0 -1
- streamlit/static/static/js/uniqueId.BUj-C6GA.js +0 -1
- streamlit/static/static/js/useUpdateUiValue.Bk5OIXup.js +0 -1
- streamlit-1.53.1.data/scripts/streamlit.cmd +0 -16
- {streamlit-1.53.1.dist-info → streamlit-1.54.0.dist-info}/entry_points.txt +0 -0
- {streamlit-1.53.1.dist-info → streamlit-1.54.0.dist-info}/top_level.txt +0 -0
streamlit/__init__.py
CHANGED
|
@@ -60,7 +60,6 @@ _os.environ["MPLBACKEND"] = "Agg"
|
|
|
60
60
|
# Must be at the top, to avoid circular dependency.
|
|
61
61
|
from streamlit import logger as _logger
|
|
62
62
|
from streamlit import config as _config
|
|
63
|
-
from streamlit.deprecation_util import deprecate_func_name as _deprecate_func_name
|
|
64
63
|
from streamlit.version import STREAMLIT_VERSION_STRING as _STREAMLIT_VERSION_STRING
|
|
65
64
|
|
|
66
65
|
# Give the package a version.
|
|
@@ -112,14 +111,9 @@ from streamlit.runtime.state import (
|
|
|
112
111
|
)
|
|
113
112
|
from streamlit.user_info import (
|
|
114
113
|
UserInfoProxy as _UserInfoProxy,
|
|
115
|
-
DeprecatedUserInfoProxy as _DeprecatedUserInfoProxy,
|
|
116
114
|
login as _login,
|
|
117
115
|
logout as _logout,
|
|
118
116
|
)
|
|
119
|
-
from streamlit.commands.experimental_query_params import (
|
|
120
|
-
get_query_params as _get_query_params,
|
|
121
|
-
set_query_params as _set_query_params,
|
|
122
|
-
)
|
|
123
117
|
|
|
124
118
|
import streamlit.column_config as _column_config
|
|
125
119
|
|
|
@@ -280,32 +274,8 @@ logout = _logout
|
|
|
280
274
|
# User
|
|
281
275
|
user = _UserInfoProxy()
|
|
282
276
|
|
|
283
|
-
# Experimental APIs
|
|
284
|
-
experimental_user = _DeprecatedUserInfoProxy()
|
|
285
|
-
|
|
286
|
-
_EXPERIMENTAL_QUERY_PARAMS_DEPRECATE_MSG = (
|
|
287
|
-
"Refer to our [docs page](https://docs.streamlit.io/develop/api-reference/caching-and-state/st.query_params) "
|
|
288
|
-
"for more information."
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
experimental_get_query_params = _deprecate_func_name(
|
|
292
|
-
_get_query_params,
|
|
293
|
-
"experimental_get_query_params",
|
|
294
|
-
"2024-04-11",
|
|
295
|
-
_EXPERIMENTAL_QUERY_PARAMS_DEPRECATE_MSG,
|
|
296
|
-
name_override="query_params",
|
|
297
|
-
)
|
|
298
|
-
experimental_set_query_params = _deprecate_func_name(
|
|
299
|
-
_set_query_params,
|
|
300
|
-
"experimental_set_query_params",
|
|
301
|
-
"2024-04-11",
|
|
302
|
-
_EXPERIMENTAL_QUERY_PARAMS_DEPRECATE_MSG,
|
|
303
|
-
name_override="query_params",
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
|
|
307
277
|
# make it possible to call streamlit.components.v1.html etc. by importing it here
|
|
308
278
|
# import in the very end to avoid partially-initialized module import errors, because
|
|
309
279
|
# streamlit.components.v1 also uses some streamlit imports
|
|
310
|
-
import streamlit.components.v1
|
|
280
|
+
import streamlit.components.v1 # noqa: F401
|
|
311
281
|
import streamlit.components.v2 # noqa: F401
|
streamlit/auth_util.py
CHANGED
|
@@ -19,7 +19,7 @@ import re
|
|
|
19
19
|
from collections.abc import Callable, Mapping
|
|
20
20
|
from datetime import datetime, timedelta, timezone
|
|
21
21
|
from typing import TYPE_CHECKING, Any, Final, TypedDict, cast
|
|
22
|
-
from urllib.parse import urlparse
|
|
22
|
+
from urllib.parse import urlencode, urlparse
|
|
23
23
|
|
|
24
24
|
from streamlit import config
|
|
25
25
|
from streamlit.errors import StreamlitAuthError
|
|
@@ -148,6 +148,95 @@ def get_redirect_uri(auth_section: AttrDict) -> str | None:
|
|
|
148
148
|
return redirect_uri_parsed.geturl()
|
|
149
149
|
|
|
150
150
|
|
|
151
|
+
def get_validated_redirect_uri() -> str | None:
|
|
152
|
+
"""Get the redirect_uri from secrets, validating it ends with /oauth2callback.
|
|
153
|
+
|
|
154
|
+
This is used for logout flows where we need a validated redirect URI
|
|
155
|
+
that matches the OAuth callback path.
|
|
156
|
+
|
|
157
|
+
Returns
|
|
158
|
+
-------
|
|
159
|
+
str | None
|
|
160
|
+
The validated redirect URI, or None if not configured or invalid.
|
|
161
|
+
"""
|
|
162
|
+
auth_section = get_secrets_auth_section()
|
|
163
|
+
if not auth_section:
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
redirect_uri = get_redirect_uri(auth_section)
|
|
167
|
+
if not redirect_uri:
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
if not redirect_uri.endswith("/oauth2callback"):
|
|
171
|
+
_LOGGER.warning("Redirect URI does not end with /oauth2callback")
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
return redirect_uri
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def get_origin_from_redirect_uri() -> str | None:
|
|
178
|
+
"""Extract the origin (scheme + host) from the configured redirect_uri.
|
|
179
|
+
|
|
180
|
+
Returns
|
|
181
|
+
-------
|
|
182
|
+
str | None
|
|
183
|
+
The origin in format "scheme://host:port", or None if not configured.
|
|
184
|
+
"""
|
|
185
|
+
auth_section = get_secrets_auth_section()
|
|
186
|
+
if not auth_section:
|
|
187
|
+
return None
|
|
188
|
+
|
|
189
|
+
redirect_uri = get_redirect_uri(auth_section)
|
|
190
|
+
if not redirect_uri:
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
redirect_uri_parsed = urlparse(redirect_uri)
|
|
194
|
+
return f"{redirect_uri_parsed.scheme}://{redirect_uri_parsed.netloc}"
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def build_logout_url(
|
|
198
|
+
end_session_endpoint: str,
|
|
199
|
+
client_id: str,
|
|
200
|
+
post_logout_redirect_uri: str,
|
|
201
|
+
id_token: str | None = None,
|
|
202
|
+
) -> str:
|
|
203
|
+
"""Build an OIDC logout URL with the required parameters.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
end_session_endpoint
|
|
208
|
+
The OIDC provider's end_session_endpoint URL.
|
|
209
|
+
client_id
|
|
210
|
+
The OAuth client ID.
|
|
211
|
+
post_logout_redirect_uri
|
|
212
|
+
The URI to redirect to after logout.
|
|
213
|
+
id_token
|
|
214
|
+
Optional ID token to include as id_token_hint for the logout request.
|
|
215
|
+
|
|
216
|
+
Returns
|
|
217
|
+
-------
|
|
218
|
+
str
|
|
219
|
+
The complete logout URL with query parameters.
|
|
220
|
+
"""
|
|
221
|
+
from urllib.parse import parse_qsl
|
|
222
|
+
|
|
223
|
+
logout_params: dict[str, str] = {
|
|
224
|
+
"client_id": client_id,
|
|
225
|
+
"post_logout_redirect_uri": post_logout_redirect_uri,
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if id_token:
|
|
229
|
+
logout_params["id_token_hint"] = id_token
|
|
230
|
+
|
|
231
|
+
# Per OIDC spec, end_session_endpoint should be a clean URL without query params,
|
|
232
|
+
# but we handle existing params defensively for non-standard providers.
|
|
233
|
+
parsed = urlparse(end_session_endpoint)
|
|
234
|
+
existing_params = dict(parse_qsl(parsed.query))
|
|
235
|
+
merged_params = {**existing_params, **logout_params}
|
|
236
|
+
new_query = urlencode(merged_params)
|
|
237
|
+
return parsed._replace(query=new_query).geturl()
|
|
238
|
+
|
|
239
|
+
|
|
151
240
|
def encode_provider_token(provider: str) -> str:
|
|
152
241
|
"""Returns a signed JWT token with the provider and expiration time."""
|
|
153
242
|
try:
|
|
@@ -376,7 +465,7 @@ def get_cookie_with_chunks(
|
|
|
376
465
|
chunk_name = f"{cookie_name}_{i + 1}"
|
|
377
466
|
chunk_value = get_single_cookie_fn(chunk_name)
|
|
378
467
|
if chunk_value is None:
|
|
379
|
-
_LOGGER.
|
|
468
|
+
_LOGGER.error("Missing chunk %d for cookie '%s'", i + 1, cookie_name)
|
|
380
469
|
return None
|
|
381
470
|
chunks.append(chunk_value)
|
|
382
471
|
|
streamlit/cli_util.py
CHANGED
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
import os
|
|
20
|
-
import subprocess
|
|
21
20
|
from typing import Any
|
|
22
21
|
|
|
23
22
|
from streamlit import env_util, errors
|
|
@@ -60,7 +59,9 @@ def _open_browser_with_webbrowser(url: str) -> None:
|
|
|
60
59
|
|
|
61
60
|
def _open_browser_with_command(command: str, url: str) -> None:
|
|
62
61
|
cmd_line = [command, url]
|
|
63
|
-
with open(os.devnull, "w") as devnull:
|
|
62
|
+
with open(os.devnull, "w", encoding="utf-8") as devnull:
|
|
63
|
+
import subprocess # noqa: S404
|
|
64
|
+
|
|
64
65
|
subprocess.Popen(cmd_line, stdout=devnull, stderr=subprocess.STDOUT) # noqa: S603
|
|
65
66
|
|
|
66
67
|
|
streamlit/commands/echo.py
CHANGED
|
@@ -26,8 +26,8 @@ from streamlit.runtime.metrics_util import gather_metrics
|
|
|
26
26
|
if TYPE_CHECKING:
|
|
27
27
|
from collections.abc import Generator, Iterable
|
|
28
28
|
|
|
29
|
-
_SPACES_RE = re.compile("
|
|
30
|
-
_EMPTY_LINE_RE = re.compile("
|
|
29
|
+
_SPACES_RE = re.compile(r"\s*")
|
|
30
|
+
_EMPTY_LINE_RE = re.compile(r"\s*\n")
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@gather_metrics("echo")
|
streamlit/commands/logo.py
CHANGED
|
@@ -23,8 +23,10 @@ from streamlit.elements.lib.image_utils import AtomicImage, image_to_url
|
|
|
23
23
|
from streamlit.elements.lib.layout_utils import LayoutConfig
|
|
24
24
|
from streamlit.errors import StreamlitAPIException
|
|
25
25
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
|
26
|
+
from streamlit.proto.Logo_pb2 import Logo as LogoProto
|
|
26
27
|
from streamlit.runtime.metrics_util import gather_metrics
|
|
27
28
|
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
|
29
|
+
from streamlit.string_util import is_emoji, validate_material_icon
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
def _invalid_logo_text(field_name: str) -> str:
|
|
@@ -35,13 +37,59 @@ def _invalid_logo_text(field_name: str) -> str:
|
|
|
35
37
|
)
|
|
36
38
|
|
|
37
39
|
|
|
40
|
+
def _process_logo_image(
|
|
41
|
+
image: AtomicImage | str, image_id: str
|
|
42
|
+
) -> tuple[LogoProto.ImageType.ValueType, str]:
|
|
43
|
+
"""Detects the image type and prepares the image data for the frontend.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
image :
|
|
48
|
+
The image that was provided by the user. Can be an image file,
|
|
49
|
+
emoji, or material icon string.
|
|
50
|
+
image_id : str
|
|
51
|
+
The image ID used when serving local images via the media file manager.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
tuple[ImageType, str]
|
|
56
|
+
The detected image type and the prepared image data.
|
|
57
|
+
|
|
58
|
+
Raises
|
|
59
|
+
------
|
|
60
|
+
StreamlitAPIException
|
|
61
|
+
If the image is an empty string or a plain text string that is not
|
|
62
|
+
a valid file path, URL, emoji, or material icon.
|
|
63
|
+
"""
|
|
64
|
+
ImageType = LogoProto.ImageType # noqa: N806
|
|
65
|
+
|
|
66
|
+
# Check if it's a material icon
|
|
67
|
+
if isinstance(image, str) and image.startswith(":material"):
|
|
68
|
+
return ImageType.ICON, validate_material_icon(image)
|
|
69
|
+
|
|
70
|
+
# Check if it's an emoji
|
|
71
|
+
if isinstance(image, str) and is_emoji(image):
|
|
72
|
+
return ImageType.EMOJI, image
|
|
73
|
+
|
|
74
|
+
# Otherwise, treat it as an image file
|
|
75
|
+
image_url = image_to_url(
|
|
76
|
+
image,
|
|
77
|
+
layout_config=LayoutConfig(width="content"),
|
|
78
|
+
clamp=False,
|
|
79
|
+
channels="RGB",
|
|
80
|
+
output_format="auto",
|
|
81
|
+
image_id=image_id,
|
|
82
|
+
)
|
|
83
|
+
return ImageType.IMAGE, image_url
|
|
84
|
+
|
|
85
|
+
|
|
38
86
|
@gather_metrics("logo")
|
|
39
87
|
def logo(
|
|
40
|
-
image: AtomicImage,
|
|
88
|
+
image: AtomicImage | str,
|
|
41
89
|
*, # keyword-only args:
|
|
42
90
|
size: Literal["small", "medium", "large"] = "medium",
|
|
43
91
|
link: str | None = None,
|
|
44
|
-
icon_image: AtomicImage | None = None,
|
|
92
|
+
icon_image: AtomicImage | str | None = None,
|
|
45
93
|
) -> None:
|
|
46
94
|
r"""
|
|
47
95
|
Renders a logo in the upper-left corner of your app and its sidebar.
|
|
@@ -60,12 +108,26 @@ def logo(
|
|
|
60
108
|
|
|
61
109
|
Parameters
|
|
62
110
|
----------
|
|
63
|
-
image: Anything supported by st.image (except list)
|
|
111
|
+
image: Anything supported by st.image (except list) or str
|
|
64
112
|
The image to display in the upper-left corner of your app and its
|
|
65
|
-
sidebar.
|
|
66
|
-
a list. If ``icon_image`` is also provided, then Streamlit will only
|
|
113
|
+
sidebar. If ``icon_image`` is also provided, then Streamlit will only
|
|
67
114
|
display ``image`` in the sidebar.
|
|
68
115
|
|
|
116
|
+
``image`` can be any of the types supported by |st.image|_ except
|
|
117
|
+
a list. Additionally, the following strings are valid:
|
|
118
|
+
|
|
119
|
+
- A single-character emoji. For example, you can set ``image="🏠"``
|
|
120
|
+
or ``image="🚀"``. Emoji short codes are not supported.
|
|
121
|
+
|
|
122
|
+
- An icon from the Material Symbols library (rounded style) in the
|
|
123
|
+
format ``":material/icon_name:"`` where "icon_name" is the name
|
|
124
|
+
of the icon in snake case.
|
|
125
|
+
|
|
126
|
+
For example, ``image=":material/home:"`` will display the
|
|
127
|
+
Home icon. Find additional icons in the `Material Symbols \
|
|
128
|
+
<https://fonts.google.com/icons?icon.set=Material+Symbols&icon.style=Rounded>`_
|
|
129
|
+
font library.
|
|
130
|
+
|
|
69
131
|
Streamlit scales the image to a max height set by ``size`` and a max
|
|
70
132
|
width to fit within the sidebar.
|
|
71
133
|
|
|
@@ -84,10 +146,10 @@ def logo(
|
|
|
84
146
|
The external URL to open when a user clicks on the logo. The URL must
|
|
85
147
|
start with "\http://" or "\https://". If ``link`` is ``None`` (default),
|
|
86
148
|
the logo will not include a hyperlink.
|
|
87
|
-
icon_image: Anything supported by st.image (except list) or None
|
|
149
|
+
icon_image: Anything supported by st.image (except list), str, or None
|
|
88
150
|
An optional, typically smaller image to replace ``image`` in the
|
|
89
151
|
upper-left corner when the sidebar is closed. This can be any of the
|
|
90
|
-
types
|
|
152
|
+
types allowed for the ``image`` parameter. If ``icon_image`` is
|
|
91
153
|
``None`` (default), Streamlit will always display ``image`` in the
|
|
92
154
|
upper-left corner, regardless of whether the sidebar is open or closed.
|
|
93
155
|
Otherwise, Streamlit will render ``icon_image`` in the upper-left
|
|
@@ -143,15 +205,9 @@ def logo(
|
|
|
143
205
|
fwd_msg = ForwardMsg()
|
|
144
206
|
|
|
145
207
|
try:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
clamp=False,
|
|
150
|
-
channels="RGB",
|
|
151
|
-
output_format="auto",
|
|
152
|
-
image_id="logo",
|
|
153
|
-
)
|
|
154
|
-
fwd_msg.logo.image = image_url
|
|
208
|
+
image_type, image_value = _process_logo_image(image, "logo")
|
|
209
|
+
fwd_msg.logo.image = image_value
|
|
210
|
+
fwd_msg.logo.image_type = image_type
|
|
155
211
|
except Exception as ex:
|
|
156
212
|
raise StreamlitAPIException(_invalid_logo_text("image")) from ex
|
|
157
213
|
|
|
@@ -167,15 +223,11 @@ def logo(
|
|
|
167
223
|
|
|
168
224
|
if icon_image:
|
|
169
225
|
try:
|
|
170
|
-
|
|
171
|
-
icon_image,
|
|
172
|
-
layout_config=LayoutConfig(width="content"),
|
|
173
|
-
clamp=False,
|
|
174
|
-
channels="RGB",
|
|
175
|
-
output_format="auto",
|
|
176
|
-
image_id="icon-image",
|
|
226
|
+
icon_image_type, icon_image_value = _process_logo_image(
|
|
227
|
+
icon_image, "icon-image"
|
|
177
228
|
)
|
|
178
|
-
fwd_msg.logo.icon_image =
|
|
229
|
+
fwd_msg.logo.icon_image = icon_image_value
|
|
230
|
+
fwd_msg.logo.icon_image_type = icon_image_type
|
|
179
231
|
except Exception as ex:
|
|
180
232
|
raise StreamlitAPIException(_invalid_logo_text("icon_image")) from ex
|
|
181
233
|
|
streamlit/commands/navigation.py
CHANGED
|
@@ -292,7 +292,7 @@ def navigation(
|
|
|
292
292
|
|
|
293
293
|
"""
|
|
294
294
|
# Validate position parameter
|
|
295
|
-
if not isinstance(position, str) or position not in
|
|
295
|
+
if not isinstance(position, str) or position not in {"sidebar", "hidden", "top"}:
|
|
296
296
|
raise StreamlitAPIException(
|
|
297
297
|
f'Invalid position "{position}". '
|
|
298
298
|
'The position parameter must be one of "sidebar", "hidden", or "top".'
|
|
@@ -480,7 +480,7 @@ class BidiComponentMixin:
|
|
|
480
480
|
deserializer=serde.deserialize,
|
|
481
481
|
serializer=serde.serialize,
|
|
482
482
|
ctx=ctx,
|
|
483
|
-
callbacks=callbacks_by_event
|
|
483
|
+
callbacks=callbacks_by_event or None,
|
|
484
484
|
value_type="json_value",
|
|
485
485
|
presenter=presenter,
|
|
486
486
|
)
|
|
@@ -495,7 +495,7 @@ class BidiComponentMixin:
|
|
|
495
495
|
deserializer=deserialize_trigger_list, # always returns list or None
|
|
496
496
|
serializer=lambda v: json.dumps(v), # send dict as JSON
|
|
497
497
|
ctx=ctx,
|
|
498
|
-
callbacks=callbacks_by_event
|
|
498
|
+
callbacks=callbacks_by_event or None,
|
|
499
499
|
value_type="json_trigger_value",
|
|
500
500
|
)
|
|
501
501
|
|
|
@@ -22,12 +22,12 @@ outside of a declared package root.
|
|
|
22
22
|
|
|
23
23
|
from __future__ import annotations
|
|
24
24
|
|
|
25
|
-
import os
|
|
26
25
|
from pathlib import Path
|
|
27
26
|
from typing import Final
|
|
28
27
|
|
|
29
28
|
from streamlit.errors import StreamlitComponentRegistryError
|
|
30
29
|
from streamlit.logger import get_logger
|
|
30
|
+
from streamlit.path_security import is_unsafe_path_pattern
|
|
31
31
|
|
|
32
32
|
_LOGGER: Final = get_logger(__name__)
|
|
33
33
|
|
|
@@ -132,7 +132,12 @@ class ComponentPathUtils:
|
|
|
132
132
|
|
|
133
133
|
@staticmethod
|
|
134
134
|
def _assert_relative_no_traversal(path: str, *, label: str) -> None:
|
|
135
|
-
"""Raise if ``path`` is absolute or
|
|
135
|
+
"""Raise if ``path`` is absolute, contains traversal, or has unsafe patterns.
|
|
136
|
+
|
|
137
|
+
This method uses the shared ``is_unsafe_path_pattern`` function to ensure
|
|
138
|
+
consistent security checks across the codebase. The shared function also
|
|
139
|
+
checks for additional patterns like null bytes, forward-slash UNC paths,
|
|
140
|
+
and drive-relative paths (e.g., ``C:foo``).
|
|
136
141
|
|
|
137
142
|
Parameters
|
|
138
143
|
----------
|
|
@@ -141,34 +146,17 @@ class ComponentPathUtils:
|
|
|
141
146
|
label : str
|
|
142
147
|
Human-readable label used in error messages (e.g., "component paths").
|
|
143
148
|
"""
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
# Consider rooted backslash paths "\\dir" as absolute on Windows-like inputs
|
|
154
|
-
is_rooted_backslash = path.startswith("\\") and not is_unc_abs
|
|
155
|
-
|
|
156
|
-
if (
|
|
157
|
-
os.path.isabs(path)
|
|
158
|
-
or is_windows_drive_abs
|
|
159
|
-
or is_unc_abs
|
|
160
|
-
or is_rooted_backslash
|
|
161
|
-
):
|
|
162
|
-
raise StreamlitComponentRegistryError(
|
|
163
|
-
f"Absolute paths are not allowed in {label}: {path}"
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
# Segment-based traversal detection to avoid false positives (e.g. "file..js")
|
|
167
|
-
normalized = path.replace("\\", "/")
|
|
168
|
-
segments = [seg for seg in normalized.split("/") if seg != ""]
|
|
169
|
-
if any(seg == ".." for seg in segments):
|
|
149
|
+
if is_unsafe_path_pattern(path):
|
|
150
|
+
# Determine appropriate error message based on pattern.
|
|
151
|
+
# Use segment-based check to avoid false positives like "file..js"
|
|
152
|
+
normalized = path.replace("\\", "/")
|
|
153
|
+
segments = [seg for seg in normalized.split("/") if seg]
|
|
154
|
+
if ".." in segments:
|
|
155
|
+
raise StreamlitComponentRegistryError(
|
|
156
|
+
f"Path traversal attempts are not allowed in {label}: {path}"
|
|
157
|
+
)
|
|
170
158
|
raise StreamlitComponentRegistryError(
|
|
171
|
-
f"
|
|
159
|
+
f"Unsafe paths are not allowed in {label}: {path}"
|
|
172
160
|
)
|
|
173
161
|
|
|
174
162
|
@staticmethod
|
|
@@ -187,8 +187,13 @@ def _is_likely_streamlit_component_package(
|
|
|
187
187
|
bool
|
|
188
188
|
True if the package might contain streamlit components, False otherwise.
|
|
189
189
|
"""
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
dist_name = dist.name
|
|
191
|
+
if not isinstance(dist_name, str) or not dist_name:
|
|
192
|
+
# We do not expect a distribution to be missing its name, be defensive
|
|
193
|
+
# and fail closed to prevent runtime issues.
|
|
194
|
+
return False
|
|
195
|
+
|
|
196
|
+
name = dist_name.lower()
|
|
192
197
|
summary = dist.metadata["Summary"].lower() if "Summary" in dist.metadata else ""
|
|
193
198
|
|
|
194
199
|
# Filter 1: Package name suggests streamlit component
|
|
@@ -386,7 +391,7 @@ def _validate_pyproject_for_package(
|
|
|
386
391
|
canonical_package = packaging_utils.canonicalize_name(package_name)
|
|
387
392
|
|
|
388
393
|
# Check if project name matches either the distribution name or the package name
|
|
389
|
-
return canonical_project in
|
|
394
|
+
return canonical_project in {canonical_dist, canonical_package}
|
|
390
395
|
|
|
391
396
|
# If we can't determine ownership, be conservative and reject it
|
|
392
397
|
return False
|
|
@@ -127,7 +127,7 @@ def make_bidi_component_presenter(
|
|
|
127
127
|
# st.session_state[component_user_key][name] = value. Using a
|
|
128
128
|
# dict subclass ensures pretty-printing and JSON serialization
|
|
129
129
|
# behave as expected for st.write and logs.
|
|
130
|
-
class _WriteThrough(dict[str, object]):
|
|
130
|
+
class _WriteThrough(dict[str, object]): # noqa: FURB189
|
|
131
131
|
def __init__(self, data: dict[str, object]) -> None:
|
|
132
132
|
super().__init__(data)
|
|
133
133
|
|
streamlit/config.py
CHANGED
|
@@ -99,11 +99,11 @@ class ShowErrorDetailsConfigOptions(str, Enum):
|
|
|
99
99
|
|
|
100
100
|
@staticmethod
|
|
101
101
|
def is_true_variation(val: str | bool) -> bool:
|
|
102
|
-
return val in
|
|
102
|
+
return val in {"true", "True", True}
|
|
103
103
|
|
|
104
104
|
@staticmethod
|
|
105
105
|
def is_false_variation(val: str | bool) -> bool:
|
|
106
|
-
return val in
|
|
106
|
+
return val in {"false", "False", False}
|
|
107
107
|
|
|
108
108
|
# Config options can be set from several places including the command-line and
|
|
109
109
|
# the user's script. Legacy config options (true/false) will have type string
|
|
@@ -617,6 +617,19 @@ _create_option(
|
|
|
617
617
|
scriptable=True,
|
|
618
618
|
)
|
|
619
619
|
|
|
620
|
+
_create_option(
|
|
621
|
+
"client.showErrorLinks",
|
|
622
|
+
description="""
|
|
623
|
+
Controls whether to show external help links (Google, ChatGPT) in
|
|
624
|
+
error displays. The following values are valid:
|
|
625
|
+
- "auto" (default): Links are shown only on localhost.
|
|
626
|
+
- True: Links are shown on all domains.
|
|
627
|
+
- False: Links are never shown.
|
|
628
|
+
""",
|
|
629
|
+
default_val="auto",
|
|
630
|
+
type_=str,
|
|
631
|
+
)
|
|
632
|
+
|
|
620
633
|
# Config Section: Runner #
|
|
621
634
|
|
|
622
635
|
_create_section("runner", "Settings for how Streamlit executes your script")
|
|
@@ -1077,9 +1090,11 @@ def _browser_server_port() -> int:
|
|
|
1077
1090
|
|
|
1078
1091
|
|
|
1079
1092
|
_SSL_PRODUCTION_WARNING = [
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1093
|
+
(
|
|
1094
|
+
"DO NOT USE THIS OPTION IN A PRODUCTION ENVIRONMENT. It has not gone through "
|
|
1095
|
+
"security audits or performance tests. For a production environment, we "
|
|
1096
|
+
"recommend performing SSL termination through a load balancer or reverse proxy."
|
|
1097
|
+
)
|
|
1083
1098
|
]
|
|
1084
1099
|
|
|
1085
1100
|
_create_option(
|
|
@@ -2279,6 +2294,35 @@ _create_theme_options(
|
|
|
2279
2294
|
""",
|
|
2280
2295
|
)
|
|
2281
2296
|
|
|
2297
|
+
_create_theme_options(
|
|
2298
|
+
"chartDivergingColors",
|
|
2299
|
+
categories=["theme"],
|
|
2300
|
+
description="""
|
|
2301
|
+
An array of ten colors to use for diverging chart data.
|
|
2302
|
+
|
|
2303
|
+
The ten colors create a diverging color scale, typically used for data
|
|
2304
|
+
with a meaningful midpoint. These colors apply to Plotly, Altair, and
|
|
2305
|
+
Vega-Lite charts.
|
|
2306
|
+
|
|
2307
|
+
Invalid color strings are skipped. If there are not exactly ten
|
|
2308
|
+
valid colors specified, Streamlit uses a default set of colors.
|
|
2309
|
+
|
|
2310
|
+
The default colors are:
|
|
2311
|
+
[
|
|
2312
|
+
"#7d353b", #red100
|
|
2313
|
+
"#bd4043", #red90
|
|
2314
|
+
"#ff4b4b", #red70
|
|
2315
|
+
"#ff8c8c", #red50
|
|
2316
|
+
"#ffc7c7", #red30
|
|
2317
|
+
"#a6dcff", #blue30
|
|
2318
|
+
"#60b4ff", #blue50
|
|
2319
|
+
"#1c83e1", #blue70
|
|
2320
|
+
"#0054a3", #blue90
|
|
2321
|
+
"#004280", #blue100
|
|
2322
|
+
]
|
|
2323
|
+
""",
|
|
2324
|
+
)
|
|
2325
|
+
|
|
2282
2326
|
# Config Section: Secrets #
|
|
2283
2327
|
|
|
2284
2328
|
_create_section("secrets", "Secrets configuration.")
|
|
@@ -2347,10 +2391,10 @@ def is_manually_set(option_name: str) -> bool:
|
|
|
2347
2391
|
True if the option has been set by the user.
|
|
2348
2392
|
|
|
2349
2393
|
"""
|
|
2350
|
-
return get_where_defined(option_name) not in
|
|
2394
|
+
return get_where_defined(option_name) not in {
|
|
2351
2395
|
ConfigOption.DEFAULT_DEFINITION,
|
|
2352
2396
|
ConfigOption.STREAMLIT_DEFINITION,
|
|
2353
|
-
|
|
2397
|
+
}
|
|
2354
2398
|
|
|
2355
2399
|
|
|
2356
2400
|
def show_config() -> None:
|
|
@@ -2433,19 +2477,19 @@ def _is_valid_theme_section(section_path: str) -> bool:
|
|
|
2433
2477
|
|
|
2434
2478
|
# theme.sidebar/light/dark is valid (2 parts: "theme" + section)
|
|
2435
2479
|
if len(parts) == 2:
|
|
2436
|
-
return parts[1] in
|
|
2480
|
+
return parts[1] in {
|
|
2437
2481
|
CustomThemeCategories.SIDEBAR.value,
|
|
2438
2482
|
CustomThemeCategories.LIGHT.value,
|
|
2439
2483
|
CustomThemeCategories.DARK.value,
|
|
2440
|
-
|
|
2484
|
+
}
|
|
2441
2485
|
|
|
2442
2486
|
# theme.light.sidebar/theme.dark.sidebar are the only valid 3-part patterns
|
|
2443
2487
|
if len(parts) == 3:
|
|
2444
2488
|
# Only allow light/dark as the middle level, with sidebar as the final level
|
|
2445
|
-
if parts[1] in
|
|
2489
|
+
if parts[1] in {
|
|
2446
2490
|
CustomThemeCategories.LIGHT.value,
|
|
2447
2491
|
CustomThemeCategories.DARK.value,
|
|
2448
|
-
|
|
2492
|
+
}:
|
|
2449
2493
|
return parts[2] == CustomThemeCategories.SIDEBAR.value
|
|
2450
2494
|
# sidebar cannot have nested sections (theme.sidebar.light/dark)
|
|
2451
2495
|
return False
|
|
@@ -2517,11 +2561,11 @@ def _update_config_with_toml(raw_toml: str, where_defined: str) -> None:
|
|
|
2517
2561
|
for name, value in section_data.items():
|
|
2518
2562
|
option_name = f"{section_path}.{name}"
|
|
2519
2563
|
# Only check for nested sections when we're already in a theme section
|
|
2520
|
-
if section_path.startswith("theme") and name in
|
|
2564
|
+
if section_path.startswith("theme") and name in {
|
|
2521
2565
|
CustomThemeCategories.SIDEBAR.value,
|
|
2522
2566
|
CustomThemeCategories.LIGHT.value,
|
|
2523
2567
|
CustomThemeCategories.DARK.value,
|
|
2524
|
-
|
|
2568
|
+
}:
|
|
2525
2569
|
# Validate the theme section before processing
|
|
2526
2570
|
if not _is_valid_theme_section(option_name):
|
|
2527
2571
|
raise StreamlitInvalidThemeSectionError(
|