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/config_util.py
CHANGED
|
@@ -194,7 +194,7 @@ def _clean(txt: str) -> str:
|
|
|
194
194
|
|
|
195
195
|
Preserves leading and trailing spaces, and does not modify spaces in between lines.
|
|
196
196
|
"""
|
|
197
|
-
return re.sub(" +", " ", txt)
|
|
197
|
+
return re.sub(r" +", " ", txt)
|
|
198
198
|
|
|
199
199
|
|
|
200
200
|
def _clean_paragraphs(txt: str) -> list[str]:
|
|
@@ -741,7 +741,7 @@ def process_theme_inheritance(
|
|
|
741
741
|
base_value = base_option.value
|
|
742
742
|
|
|
743
743
|
# Check if it's a file path or URL (not just "light" or "dark")
|
|
744
|
-
if base_value in
|
|
744
|
+
if base_value in {"light", "dark"}:
|
|
745
745
|
return
|
|
746
746
|
|
|
747
747
|
def _raise_invalid_nested_base() -> None:
|
|
@@ -756,7 +756,7 @@ def process_theme_inheritance(
|
|
|
756
756
|
|
|
757
757
|
# Validate that theme.base of the referenced theme file doesn't reference another file
|
|
758
758
|
theme_base = theme_file_content.get("theme", {}).get("base")
|
|
759
|
-
if theme_base and theme_base not in
|
|
759
|
+
if theme_base and theme_base not in {"light", "dark"}:
|
|
760
760
|
_raise_invalid_nested_base()
|
|
761
761
|
|
|
762
762
|
# Get current theme options from main config.toml
|
|
@@ -777,10 +777,10 @@ def process_theme_inheritance(
|
|
|
777
777
|
opt_name.startswith("theme.")
|
|
778
778
|
and opt_name != "theme.base"
|
|
779
779
|
and opt_config.where_defined
|
|
780
|
-
in
|
|
780
|
+
in {
|
|
781
781
|
"environment variable",
|
|
782
782
|
"command-line argument or environment variable",
|
|
783
|
-
|
|
783
|
+
}
|
|
784
784
|
):
|
|
785
785
|
high_precedence_theme_options[opt_name] = {
|
|
786
786
|
"value": opt_config.value,
|
|
@@ -135,7 +135,9 @@ class BaseSnowflakeConnection(BaseConnection["InternalSnowflakeConnection"]):
|
|
|
135
135
|
),
|
|
136
136
|
wait=wait_fixed(1),
|
|
137
137
|
)
|
|
138
|
-
|
|
138
|
+
# `params` must be an explicit parameter (not captured from closure) so that
|
|
139
|
+
# `@st.cache_data` includes it in the cache key.
|
|
140
|
+
def _query(sql: str, params: Any = None) -> DataFrame:
|
|
139
141
|
cur = self._instance.cursor()
|
|
140
142
|
cur.execute(sql, params=params, **kwargs)
|
|
141
143
|
return cur.fetch_pandas_all() # type: ignore
|
|
@@ -153,7 +155,7 @@ class BaseSnowflakeConnection(BaseConnection["InternalSnowflakeConnection"]):
|
|
|
153
155
|
ttl=ttl,
|
|
154
156
|
)(_query)
|
|
155
157
|
|
|
156
|
-
return _query(sql)
|
|
158
|
+
return _query(sql, params)
|
|
157
159
|
|
|
158
160
|
def write_pandas(
|
|
159
161
|
self,
|
|
@@ -685,7 +687,7 @@ class SnowflakeCallersRightsConnection(SnowflakeConnection):
|
|
|
685
687
|
@classmethod
|
|
686
688
|
def _read_token_file(cls) -> str:
|
|
687
689
|
"""Returns the contents of the Snowpark token file on disk."""
|
|
688
|
-
with open(SNOWPARK_CONNECTION_TOKEN_FILE) as token_file:
|
|
690
|
+
with open(SNOWPARK_CONNECTION_TOKEN_FILE, encoding="utf-8") as token_file:
|
|
689
691
|
return token_file.read()
|
|
690
692
|
|
|
691
693
|
@classmethod
|
streamlit/dataframe_util.py
CHANGED
|
@@ -464,7 +464,7 @@ def _is_list_of_scalars(data: Iterable[Any]) -> bool:
|
|
|
464
464
|
|
|
465
465
|
# Overview on all value that are interpreted as scalar:
|
|
466
466
|
# https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_scalar.html
|
|
467
|
-
return infer_dtype(data, skipna=True) not in
|
|
467
|
+
return infer_dtype(data, skipna=True) not in {"mixed", "unknown-array"}
|
|
468
468
|
|
|
469
469
|
|
|
470
470
|
def _iterable_to_list(
|
|
@@ -1056,9 +1056,7 @@ def is_colum_type_arrow_incompatible(column: Series[Any] | Index[Any]) -> bool:
|
|
|
1056
1056
|
"""
|
|
1057
1057
|
from pandas.api.types import infer_dtype, is_dict_like, is_list_like
|
|
1058
1058
|
|
|
1059
|
-
if column.dtype.kind
|
|
1060
|
-
"c", # complex64, complex128, complex256
|
|
1061
|
-
]:
|
|
1059
|
+
if column.dtype.kind == "c": # complex64, complex128, complex256
|
|
1062
1060
|
return True
|
|
1063
1061
|
|
|
1064
1062
|
if str(column.dtype) in {
|
|
@@ -1074,15 +1072,17 @@ def is_colum_type_arrow_incompatible(column: Series[Any] | Index[Any]) -> bool:
|
|
|
1074
1072
|
return True
|
|
1075
1073
|
|
|
1076
1074
|
if column.dtype == "object":
|
|
1077
|
-
# The dtype of mixed type columns is always object
|
|
1078
|
-
#
|
|
1075
|
+
# The dtype of mixed type columns is always object. In pandas 3.0+, pure
|
|
1076
|
+
# string columns use StringDtype instead of object, so they won't enter
|
|
1077
|
+
# this block (and they're Arrow-compatible anyway). The actual type of
|
|
1078
|
+
# object dtype column values can be determined via the infer_dtype function:
|
|
1079
1079
|
# https://pandas.pydata.org/docs/reference/api/pandas.api.types.infer_dtype.html
|
|
1080
1080
|
inferred_type = infer_dtype(column, skipna=True)
|
|
1081
1081
|
|
|
1082
|
-
if inferred_type in
|
|
1082
|
+
if inferred_type in {
|
|
1083
1083
|
"mixed-integer",
|
|
1084
1084
|
"complex",
|
|
1085
|
-
|
|
1085
|
+
}:
|
|
1086
1086
|
return True
|
|
1087
1087
|
if inferred_type == "mixed":
|
|
1088
1088
|
# This includes most of the more complex/custom types (objects, dicts,
|
|
@@ -1405,11 +1405,11 @@ def convert_pandas_df_to_data_format(
|
|
|
1405
1405
|
return _unify_missing_values(df).to_dict(orient="list")
|
|
1406
1406
|
if data_format == DataFormat.COLUMN_SERIES_MAPPING:
|
|
1407
1407
|
return df.to_dict(orient="series")
|
|
1408
|
-
if data_format in
|
|
1408
|
+
if data_format in {
|
|
1409
1409
|
DataFormat.LIST_OF_VALUES,
|
|
1410
1410
|
DataFormat.TUPLE_OF_VALUES,
|
|
1411
1411
|
DataFormat.SET_OF_VALUES,
|
|
1412
|
-
|
|
1412
|
+
}:
|
|
1413
1413
|
df = _unify_missing_values(df)
|
|
1414
1414
|
return_list = []
|
|
1415
1415
|
if len(df.columns) == 1:
|
streamlit/deprecation_util.py
CHANGED
|
@@ -21,12 +21,17 @@ from typing import Any, Final, TypeVar, cast
|
|
|
21
21
|
import streamlit
|
|
22
22
|
from streamlit import config
|
|
23
23
|
from streamlit.logger import get_logger
|
|
24
|
+
from streamlit.util import calc_md5
|
|
24
25
|
|
|
25
26
|
_LOGGER: Final = get_logger(__name__)
|
|
26
27
|
|
|
27
28
|
TFunc = TypeVar("TFunc", bound=Callable[..., Any])
|
|
28
29
|
TObj = TypeVar("TObj", bound=object)
|
|
29
30
|
|
|
31
|
+
# Set to track which deprecation warnings have been shown (by message hash)
|
|
32
|
+
# when show_once=True is used
|
|
33
|
+
_shown_warnings: set[str] = set()
|
|
34
|
+
|
|
30
35
|
|
|
31
36
|
def _error_details_in_browser_enabled() -> bool:
|
|
32
37
|
"""True if we should print deprecation warnings to the browser.
|
|
@@ -42,7 +47,9 @@ def _error_details_in_browser_enabled() -> bool:
|
|
|
42
47
|
)
|
|
43
48
|
|
|
44
49
|
|
|
45
|
-
def show_deprecation_warning(
|
|
50
|
+
def show_deprecation_warning(
|
|
51
|
+
message: str, show_in_browser: bool = True, show_once: bool = False
|
|
52
|
+
) -> None:
|
|
46
53
|
"""Show a deprecation warning message.
|
|
47
54
|
|
|
48
55
|
Parameters
|
|
@@ -55,7 +62,18 @@ def show_deprecation_warning(message: str, show_in_browser: bool = True) -> None
|
|
|
55
62
|
set `client.showErrorDetails` to "full" or the legacy True value. All
|
|
56
63
|
other values ("stacktrace", "type", "none", False) will hide deprecation
|
|
57
64
|
warnings in the browser (but still log them to the console).
|
|
65
|
+
show_once : bool, default=False
|
|
66
|
+
If True, the warning will only be shown once per unique message (based on
|
|
67
|
+
message hash). Subsequent calls with the same message will be skipped.
|
|
68
|
+
This is useful for warnings that may be triggered many times during a
|
|
69
|
+
script run.
|
|
58
70
|
"""
|
|
71
|
+
if show_once:
|
|
72
|
+
message_hash = calc_md5(message)
|
|
73
|
+
if message_hash in _shown_warnings:
|
|
74
|
+
return
|
|
75
|
+
_shown_warnings.add(message_hash)
|
|
76
|
+
|
|
59
77
|
if _error_details_in_browser_enabled() and show_in_browser:
|
|
60
78
|
streamlit.warning(message)
|
|
61
79
|
|
streamlit/elements/arrow.py
CHANGED
|
@@ -647,7 +647,7 @@ class ArrowMixin:
|
|
|
647
647
|
"""
|
|
648
648
|
import pyarrow as pa
|
|
649
649
|
|
|
650
|
-
if on_select not in
|
|
650
|
+
if on_select not in {"ignore", "rerun"} and not callable(on_select):
|
|
651
651
|
raise StreamlitAPIException(
|
|
652
652
|
f"You have passed {on_select} to `on_select`. But only 'ignore', "
|
|
653
653
|
"'rerun', or a callable is supported."
|
|
@@ -744,13 +744,18 @@ class ArrowMixin:
|
|
|
744
744
|
elif (
|
|
745
745
|
# Hide index column if row selections are activated and the dataframe has a range index.
|
|
746
746
|
# The range index usually does not add a lot of value.
|
|
747
|
-
is_selection_activated
|
|
748
|
-
and selection_mode in ["multi-row", "single-row"]
|
|
749
|
-
and has_range_index
|
|
747
|
+
is_selection_activated and has_range_index
|
|
750
748
|
):
|
|
751
|
-
|
|
752
|
-
|
|
749
|
+
# Normalize selection_mode to a set to check for row selection modes
|
|
750
|
+
mode_set = (
|
|
751
|
+
{selection_mode}
|
|
752
|
+
if isinstance(selection_mode, str)
|
|
753
|
+
else set(selection_mode)
|
|
753
754
|
)
|
|
755
|
+
if mode_set & {"multi-row", "single-row"}:
|
|
756
|
+
update_column_config(
|
|
757
|
+
column_config_mapping, INDEX_IDENTIFIER, {"hidden": True}
|
|
758
|
+
)
|
|
754
759
|
|
|
755
760
|
marshall_column_config(proto, column_config_mapping)
|
|
756
761
|
|
|
@@ -771,7 +776,11 @@ class ArrowMixin:
|
|
|
771
776
|
proto.id = compute_and_register_element_id(
|
|
772
777
|
"dataframe",
|
|
773
778
|
user_key=key,
|
|
774
|
-
|
|
779
|
+
# There are some edge cases where selections can become orphaned when the data changes
|
|
780
|
+
# - e.g. when rows get removed. The frontend can handle this without errors,
|
|
781
|
+
# but it might be a nice enhancement to automatically reset the backend & frontend
|
|
782
|
+
# selection state in this case.
|
|
783
|
+
key_as_main_identity={"selection_mode", "is_selection_activated"},
|
|
775
784
|
dg=self.dg,
|
|
776
785
|
data=proto.data,
|
|
777
786
|
width=width,
|
|
@@ -974,7 +983,8 @@ class ArrowMixin:
|
|
|
974
983
|
" If you have a specific use-case that requires the `add_rows` "
|
|
975
984
|
"functionality, please tell us via this "
|
|
976
985
|
"[issue on Github](https://github.com/streamlit/streamlit/issues/13063).",
|
|
977
|
-
show_in_browser=
|
|
986
|
+
show_in_browser=True,
|
|
987
|
+
show_once=True,
|
|
978
988
|
)
|
|
979
989
|
|
|
980
990
|
return _arrow_add_rows(self.dg, data, **kwargs)
|
|
@@ -531,7 +531,7 @@ class PydeckMixin:
|
|
|
531
531
|
key = to_key(key)
|
|
532
532
|
is_selection_activated = on_select != "ignore"
|
|
533
533
|
|
|
534
|
-
if on_select not in
|
|
534
|
+
if on_select not in {"ignore", "rerun"} and not callable(on_select):
|
|
535
535
|
raise StreamlitAPIException(
|
|
536
536
|
f"You have passed {on_select} to `on_select`. "
|
|
537
537
|
"But only 'ignore', 'rerun', or a callable is supported."
|
|
@@ -556,7 +556,11 @@ class PydeckMixin:
|
|
|
556
556
|
pydeck_proto.id = compute_and_register_element_id(
|
|
557
557
|
"deck_gl_json_chart",
|
|
558
558
|
user_key=key,
|
|
559
|
-
|
|
559
|
+
# When a key is provided, only selection_mode affects the element ID.
|
|
560
|
+
# This allows selection state to persist across data/spec changes.
|
|
561
|
+
# Note: This can lead to orphaned selections if data length shrinks,
|
|
562
|
+
# but the frontend handles this by sanitizing invalid indices.
|
|
563
|
+
key_as_main_identity={"selection_mode"},
|
|
560
564
|
dg=self.dg,
|
|
561
565
|
is_selection_activated=is_selection_activated,
|
|
562
566
|
selection_mode=selection_mode,
|
streamlit/elements/exception.py
CHANGED
|
@@ -278,8 +278,10 @@ def _get_stack_trace_str_list(exception: BaseException) -> list[str]:
|
|
|
278
278
|
# Format the extracted traceback and add it to the protobuf element.
|
|
279
279
|
if extracted_traceback is None:
|
|
280
280
|
trace_str_list = [
|
|
281
|
-
|
|
282
|
-
|
|
281
|
+
(
|
|
282
|
+
"Cannot extract the stack trace for this exception. "
|
|
283
|
+
"Try calling exception() within the `catch` block."
|
|
284
|
+
)
|
|
283
285
|
]
|
|
284
286
|
else:
|
|
285
287
|
internal_frames, external_frames = _split_internal_streamlit_frames(
|
streamlit/elements/form.py
CHANGED
|
@@ -413,7 +413,7 @@ class FormMixin:
|
|
|
413
413
|
width = "stretch" if use_container_width else "content"
|
|
414
414
|
|
|
415
415
|
# Checks whether the entered button type is one of the allowed options
|
|
416
|
-
if type not in
|
|
416
|
+
if type not in {"primary", "secondary", "tertiary"}:
|
|
417
417
|
raise StreamlitAPIException(
|
|
418
418
|
'The type argument to st.form_submit_button must be "primary", "secondary", or "tertiary". \n'
|
|
419
419
|
f'The argument passed was "{type}".'
|
streamlit/elements/layouts.py
CHANGED
|
@@ -1036,7 +1036,7 @@ class LayoutsMixin:
|
|
|
1036
1036
|
width = "stretch" if use_container_width else "content"
|
|
1037
1037
|
|
|
1038
1038
|
# Checks whether the entered button type is one of the allowed options
|
|
1039
|
-
if type not in
|
|
1039
|
+
if type not in {"primary", "secondary", "tertiary"}:
|
|
1040
1040
|
raise StreamlitAPIException(
|
|
1041
1041
|
'The type argument to st.popover must be "primary", "secondary", or "tertiary". '
|
|
1042
1042
|
f'\nThe argument passed was "{type}".'
|
|
@@ -24,6 +24,7 @@ from typing import TYPE_CHECKING, Any, Final, Literal, TypeAlias, TypedDict, cas
|
|
|
24
24
|
from streamlit import dataframe_util, type_util
|
|
25
25
|
from streamlit.elements.lib.color_util import (
|
|
26
26
|
Color,
|
|
27
|
+
is_builtin_color_name,
|
|
27
28
|
is_color_like,
|
|
28
29
|
is_color_tuple_like,
|
|
29
30
|
is_hex_color_like,
|
|
@@ -136,7 +137,7 @@ def maybe_raise_stack_warning(
|
|
|
136
137
|
stack: bool | ChartStackType | None, command: str | None, docs_link: str
|
|
137
138
|
) -> None:
|
|
138
139
|
# Check that the stack parameter is valid, raise more informative error if not
|
|
139
|
-
if stack not in
|
|
140
|
+
if stack not in {None, True, False, "normalize", "center", "layered"}:
|
|
140
141
|
raise StreamlitAPIException(
|
|
141
142
|
f"Invalid value for stack parameter: {stack}. Stack must be one of True, "
|
|
142
143
|
'False, "normalize", "center", "layered" or None. See documentation '
|
|
@@ -425,13 +426,13 @@ def _infer_vegalite_type(
|
|
|
425
426
|
# requires Pandas 1.3.
|
|
426
427
|
typ = infer_dtype(data)
|
|
427
428
|
|
|
428
|
-
if typ in
|
|
429
|
+
if typ in {
|
|
429
430
|
"floating",
|
|
430
431
|
"mixed-integer-float",
|
|
431
432
|
"integer",
|
|
432
433
|
"mixed-integer",
|
|
433
434
|
"complex",
|
|
434
|
-
|
|
435
|
+
}:
|
|
435
436
|
return "quantitative"
|
|
436
437
|
|
|
437
438
|
if typ == "categorical" and data.cat.ordered:
|
|
@@ -442,9 +443,9 @@ def _infer_vegalite_type(
|
|
|
442
443
|
# Altair already extracts the correct sort order somewhere else.
|
|
443
444
|
# More info about the issue here: https://github.com/streamlit/streamlit/issues/7776
|
|
444
445
|
return "ordinal"
|
|
445
|
-
if typ in
|
|
446
|
+
if typ in {"string", "bytes", "categorical", "boolean", "mixed", "unicode"}:
|
|
446
447
|
return "nominal"
|
|
447
|
-
if typ in
|
|
448
|
+
if typ in {
|
|
448
449
|
"datetime",
|
|
449
450
|
"datetime64",
|
|
450
451
|
"timedelta",
|
|
@@ -452,7 +453,7 @@ def _infer_vegalite_type(
|
|
|
452
453
|
"date",
|
|
453
454
|
"time",
|
|
454
455
|
"period",
|
|
455
|
-
|
|
456
|
+
}:
|
|
456
457
|
return "temporal"
|
|
457
458
|
# STREAMLIT MOD: I commented this out since Streamlit doesn't use warnings.warn.
|
|
458
459
|
# > warnings.warn(
|
|
@@ -611,6 +612,9 @@ def _melt_data(
|
|
|
611
612
|
|
|
612
613
|
y_series = melted_df[new_y_column_name]
|
|
613
614
|
if (
|
|
615
|
+
# After melting columns of different dtypes, the result has object dtype.
|
|
616
|
+
# In pandas 3.0+, melting columns with the same StringDtype keeps StringDtype,
|
|
617
|
+
# so this check correctly identifies only truly mixed-type scenarios.
|
|
614
618
|
y_series.dtype == "object"
|
|
615
619
|
and "mixed" in infer_dtype(y_series)
|
|
616
620
|
and len(y_series.unique()) > 100
|
|
@@ -859,9 +863,9 @@ def _maybe_melt(
|
|
|
859
863
|
color_column = _MELTED_COLOR_COLUMN_NAME
|
|
860
864
|
|
|
861
865
|
columns_to_leave_alone = [x_column]
|
|
862
|
-
if size_column:
|
|
866
|
+
if size_column and size_column not in columns_to_leave_alone:
|
|
863
867
|
columns_to_leave_alone.append(size_column)
|
|
864
|
-
if sort_column:
|
|
868
|
+
if sort_column and sort_column not in columns_to_leave_alone:
|
|
865
869
|
columns_to_leave_alone.append(sort_column)
|
|
866
870
|
|
|
867
871
|
df = _melt_data(
|
|
@@ -913,7 +917,7 @@ def _get_axis_encodings(
|
|
|
913
917
|
_update_encoding_with_stack(stack, stack_encoding)
|
|
914
918
|
|
|
915
919
|
# Handle sorting - only relevant for bar charts
|
|
916
|
-
if chart_type in
|
|
920
|
+
if chart_type in {ChartType.VERTICAL_BAR, ChartType.HORIZONTAL_BAR}:
|
|
917
921
|
_update_encoding_with_sort(sort_from_user, sort_encoding)
|
|
918
922
|
|
|
919
923
|
return x_encoding, y_encoding
|
|
@@ -1077,6 +1081,14 @@ def _get_color_encoding(
|
|
|
1077
1081
|
|
|
1078
1082
|
return alt.ColorValue(to_css_color(cast("Any", color_value)))
|
|
1079
1083
|
|
|
1084
|
+
# Check for built-in color names (resolved on frontend, not converted here)
|
|
1085
|
+
if isinstance(color_value, str) and is_builtin_color_name(color_value):
|
|
1086
|
+
if len(y_column_list) != 1:
|
|
1087
|
+
raise StreamlitColorLengthError(
|
|
1088
|
+
[color_value] if color_value else [], y_column_list
|
|
1089
|
+
)
|
|
1090
|
+
return alt.ColorValue(color_value)
|
|
1091
|
+
|
|
1080
1092
|
# If the color value is a list of colors of appropriate length, return that.
|
|
1081
1093
|
if isinstance(color_value, (list, tuple)):
|
|
1082
1094
|
color_values = cast("Collection[Color]", color_value)
|
|
@@ -1085,12 +1097,23 @@ def _get_color_encoding(
|
|
|
1085
1097
|
raise StreamlitColorLengthError(color_values, y_column_list)
|
|
1086
1098
|
|
|
1087
1099
|
if len(color_values) == 1:
|
|
1088
|
-
|
|
1100
|
+
first_color = cast("Any", color_value[0])
|
|
1101
|
+
# Pass through built-in color names as-is (resolved on frontend)
|
|
1102
|
+
if isinstance(first_color, str) and is_builtin_color_name(first_color):
|
|
1103
|
+
return alt.ColorValue(first_color)
|
|
1104
|
+
return alt.ColorValue(to_css_color(first_color))
|
|
1105
|
+
|
|
1106
|
+
# Convert colors, but pass through built-in color names as-is
|
|
1107
|
+
resolved_colors: list[Color] = []
|
|
1108
|
+
for c in color_values:
|
|
1109
|
+
if isinstance(c, str) and is_builtin_color_name(c):
|
|
1110
|
+
resolved_colors.append(c)
|
|
1111
|
+
else:
|
|
1112
|
+
resolved_colors.append(to_css_color(c))
|
|
1113
|
+
|
|
1089
1114
|
return alt.Color(
|
|
1090
1115
|
field=color_column if color_column is not None else alt.Undefined,
|
|
1091
|
-
scale=alt.Scale(
|
|
1092
|
-
domain=y_column_list, range=[to_css_color(c) for c in color_values]
|
|
1093
|
-
),
|
|
1116
|
+
scale=alt.Scale(domain=y_column_list, range=resolved_colors),
|
|
1094
1117
|
legend=_COLOR_LEGEND_SETTINGS,
|
|
1095
1118
|
type="nominal",
|
|
1096
1119
|
title=" ",
|
|
@@ -15,10 +15,16 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
from collections.abc import Callable, Collection
|
|
18
|
-
from typing import Any, TypeAlias, cast
|
|
18
|
+
from typing import Any, Final, TypeAlias, cast
|
|
19
19
|
|
|
20
20
|
from streamlit.errors import StreamlitInvalidColorError
|
|
21
21
|
|
|
22
|
+
# Built-in color names that map to Streamlit theme colors.
|
|
23
|
+
# These are resolved to actual color values on the frontend.
|
|
24
|
+
BUILTIN_COLOR_NAMES: Final[frozenset[str]] = frozenset(
|
|
25
|
+
{"red", "orange", "yellow", "green", "blue", "violet", "gray", "grey", "primary"}
|
|
26
|
+
)
|
|
27
|
+
|
|
22
28
|
# components go from 0.0 to 1.0
|
|
23
29
|
# Supported by Pillow and pretty common.
|
|
24
30
|
FloatRGBColorTuple: TypeAlias = tuple[float, float, float]
|
|
@@ -131,11 +137,24 @@ def is_color_tuple_like(color: MaybeColor) -> bool:
|
|
|
131
137
|
)
|
|
132
138
|
|
|
133
139
|
|
|
140
|
+
def is_builtin_color_name(color: MaybeColor) -> bool:
|
|
141
|
+
"""Check whether the input is a built-in Streamlit color name.
|
|
142
|
+
|
|
143
|
+
Built-in color names (red, orange, yellow, green, blue, violet, gray/grey, primary)
|
|
144
|
+
are resolved to theme colors on the frontend.
|
|
145
|
+
"""
|
|
146
|
+
return isinstance(color, str) and color.lower() in BUILTIN_COLOR_NAMES
|
|
147
|
+
|
|
148
|
+
|
|
134
149
|
def is_color_like(color: MaybeColor) -> bool:
|
|
135
150
|
"""A fairly lightweight check of whether the input is a color.
|
|
136
151
|
|
|
137
152
|
This isn't meant to be a definitive answer. The definitive solution is to
|
|
138
153
|
try to convert and see if an error is thrown.
|
|
154
|
+
|
|
155
|
+
NOTE: This does NOT include built-in color names (red, blue, etc.) because
|
|
156
|
+
those require special handling and cannot be converted via to_css_color().
|
|
157
|
+
Use is_builtin_color_name() separately when validating color parameter arguments.
|
|
139
158
|
"""
|
|
140
159
|
return is_css_color_like(color) or is_color_tuple_like(color)
|
|
141
160
|
|
|
@@ -245,7 +264,7 @@ def _float_formatter(component: float, color: MaybeColor) -> float:
|
|
|
245
264
|
Anything too small will become 0.0, and anything too large will become 1.0.
|
|
246
265
|
"""
|
|
247
266
|
if isinstance(component, int):
|
|
248
|
-
component
|
|
267
|
+
component /= 255.0
|
|
249
268
|
|
|
250
269
|
if isinstance(component, float):
|
|
251
270
|
return min(1.0, max(component, 0.0))
|
|
@@ -255,7 +255,9 @@ def _determine_data_kind_via_pandas_dtype(
|
|
|
255
255
|
if pd.api.types.is_object_dtype(
|
|
256
256
|
column_dtype
|
|
257
257
|
) is False and pd.api.types.is_string_dtype(column_dtype):
|
|
258
|
-
#
|
|
258
|
+
# This handles pandas 3.0+ StringDtype (and PyArrow-backed string types).
|
|
259
|
+
# We exclude object dtype here because object columns with string values
|
|
260
|
+
# are handled via _determine_data_kind_via_inferred_type in the caller.
|
|
259
261
|
return ColumnDataKind.STRING
|
|
260
262
|
|
|
261
263
|
return ColumnDataKind.UNKNOWN
|
|
@@ -289,7 +291,7 @@ def _determine_data_kind_via_inferred_type(
|
|
|
289
291
|
if inferred_type == "bytes":
|
|
290
292
|
return ColumnDataKind.BYTES
|
|
291
293
|
|
|
292
|
-
if inferred_type in
|
|
294
|
+
if inferred_type in {"floating", "mixed-integer-float"}:
|
|
293
295
|
return ColumnDataKind.FLOAT
|
|
294
296
|
|
|
295
297
|
if inferred_type == "integer":
|
|
@@ -304,13 +306,13 @@ def _determine_data_kind_via_inferred_type(
|
|
|
304
306
|
if inferred_type == "boolean":
|
|
305
307
|
return ColumnDataKind.BOOLEAN
|
|
306
308
|
|
|
307
|
-
if inferred_type in
|
|
309
|
+
if inferred_type in {"datetime64", "datetime"}:
|
|
308
310
|
return ColumnDataKind.DATETIME
|
|
309
311
|
|
|
310
312
|
if inferred_type == "date":
|
|
311
313
|
return ColumnDataKind.DATE
|
|
312
314
|
|
|
313
|
-
if inferred_type in
|
|
315
|
+
if inferred_type in {"timedelta64", "timedelta"}:
|
|
314
316
|
return ColumnDataKind.TIMEDELTA
|
|
315
317
|
|
|
316
318
|
if inferred_type == "time":
|
|
@@ -411,7 +413,7 @@ ColumnConfigMappingInput: TypeAlias = Mapping[
|
|
|
411
413
|
# allowing int here leads mypy to complain about simple dict[str, ...]
|
|
412
414
|
# as input -> which seems like a mypy bug.
|
|
413
415
|
IndexIdentifierType | str,
|
|
414
|
-
ColumnConfig |
|
|
416
|
+
ColumnConfig | str | None,
|
|
415
417
|
]
|
|
416
418
|
|
|
417
419
|
|
|
@@ -499,7 +501,7 @@ def apply_data_specific_configs(
|
|
|
499
501
|
# Pandas adds a range index as default to all datastructures
|
|
500
502
|
# but for most of the non-pandas data objects it is unnecessary
|
|
501
503
|
# to show this index to the user. Therefore, we will hide it as default.
|
|
502
|
-
if data_format in
|
|
504
|
+
if data_format in {
|
|
503
505
|
DataFormat.SET_OF_VALUES,
|
|
504
506
|
DataFormat.TUPLE_OF_VALUES,
|
|
505
507
|
DataFormat.LIST_OF_VALUES,
|
|
@@ -516,7 +518,7 @@ def apply_data_specific_configs(
|
|
|
516
518
|
DataFormat.POLARS_LAZYFRAME,
|
|
517
519
|
DataFormat.PYARROW_ARRAY,
|
|
518
520
|
DataFormat.RAY_DATASET,
|
|
519
|
-
|
|
521
|
+
}:
|
|
520
522
|
update_column_config(columns_config, INDEX_IDENTIFIER, {"hidden": True})
|
|
521
523
|
|
|
522
524
|
|
streamlit/elements/lib/dialog.py
CHANGED
|
@@ -91,7 +91,7 @@ class Dialog(DeltaGenerator):
|
|
|
91
91
|
on_dismiss: Literal["ignore", "rerun"] | WidgetCallback = "ignore",
|
|
92
92
|
) -> Dialog:
|
|
93
93
|
# Validation for on_dismiss parameter
|
|
94
|
-
if on_dismiss not in
|
|
94
|
+
if on_dismiss not in {"ignore", "rerun"} and not callable(on_dismiss):
|
|
95
95
|
raise StreamlitAPIException(
|
|
96
96
|
f"You have passed {on_dismiss} to `on_dismiss`. But only 'ignore', "
|
|
97
97
|
"'rerun', or a callable is supported."
|
|
@@ -80,7 +80,7 @@ its column width"""
|
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
def _image_may_have_alpha_channel(image: PILImage) -> bool:
|
|
83
|
-
return image.mode in
|
|
83
|
+
return image.mode in {"RGBA", "LA", "P"}
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
def _image_is_gif(image: PILImage) -> bool:
|
|
@@ -155,9 +155,9 @@ def _np_array_to_bytes(array: npt.NDArray[Any], output_format: str = "JPEG") ->
|
|
|
155
155
|
|
|
156
156
|
def _verify_np_shape(array: npt.NDArray[Any]) -> npt.NDArray[Any]:
|
|
157
157
|
shape: NumpyShape = array.shape
|
|
158
|
-
if len(shape) not in
|
|
158
|
+
if len(shape) not in {2, 3}:
|
|
159
159
|
raise StreamlitAPIException("Numpy shape has to be of length 2 or 3.")
|
|
160
|
-
if len(shape) == 3 and shape[-1] not in
|
|
160
|
+
if len(shape) == 3 and shape[-1] not in {1, 3, 4}:
|
|
161
161
|
raise StreamlitAPIException(
|
|
162
162
|
f"Channel can only be 1, 3, or 4 got {shape[-1]}. Shape is {shape}"
|
|
163
163
|
)
|
|
@@ -224,7 +224,7 @@ def _clip_image(image: npt.NDArray[Any], clamp: bool) -> npt.NDArray[Any]:
|
|
|
224
224
|
data = np.clip(image, 0, 1.0)
|
|
225
225
|
elif np.amin(image) < 0.0 or np.amax(image) > 1.0:
|
|
226
226
|
raise RuntimeError("Data is outside [0.0, 1.0] and clamp is not set.")
|
|
227
|
-
data = data * 255
|
|
227
|
+
data = data * 255 # noqa: PLR6104
|
|
228
228
|
elif clamp:
|
|
229
229
|
data = np.clip(image, 0, 255)
|
|
230
230
|
elif np.amin(image) < 0 or np.amax(image) > 255:
|
|
@@ -265,7 +265,7 @@ def image_to_url(
|
|
|
265
265
|
|
|
266
266
|
if image.endswith(".svg") and os.path.isfile(image):
|
|
267
267
|
# Unpack local SVG image file to an SVG string
|
|
268
|
-
with open(image) as textfile:
|
|
268
|
+
with open(image, encoding="utf-8") as textfile:
|
|
269
269
|
image = textfile.read()
|
|
270
270
|
|
|
271
271
|
# Following regex allows svg image files to start either via a "<?xml...>" tag
|
|
@@ -273,7 +273,7 @@ def get_justify(
|
|
|
273
273
|
justify = map_to_flex_terminology[alignment]
|
|
274
274
|
if justify not in valid_justify:
|
|
275
275
|
return Block.FlexContainer.Justify.JUSTIFY_UNDEFINED
|
|
276
|
-
if justify in
|
|
276
|
+
if justify in {"start", "end", "center"}:
|
|
277
277
|
return cast(
|
|
278
278
|
"Block.FlexContainer.Justify.ValueType",
|
|
279
279
|
getattr(Block.FlexContainer.Justify, f"JUSTIFY_{justify.upper()}"),
|