streamlit 1.50.0__py3-none-any.whl → 1.52.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 +5 -1
- streamlit/commands/execution_control.py +89 -14
- streamlit/commands/navigation.py +4 -6
- streamlit/commands/page_config.py +4 -6
- streamlit/components/v1/component_arrow.py +7 -7
- streamlit/components/v2/__init__.py +514 -0
- streamlit/components/v2/bidi_component/__init__.py +20 -0
- streamlit/components/v2/bidi_component/constants.py +29 -0
- streamlit/components/v2/bidi_component/main.py +534 -0
- streamlit/components/v2/bidi_component/serialization.py +272 -0
- streamlit/components/v2/bidi_component/state.py +92 -0
- streamlit/components/v2/component_definition_resolver.py +143 -0
- streamlit/components/v2/component_file_watcher.py +403 -0
- streamlit/components/v2/component_manager.py +439 -0
- streamlit/components/v2/component_manifest_handler.py +122 -0
- streamlit/components/v2/component_path_utils.py +245 -0
- streamlit/components/v2/component_registry.py +426 -0
- streamlit/components/v2/get_bidi_component_manager.py +51 -0
- streamlit/components/v2/manifest_scanner.py +615 -0
- streamlit/components/v2/presentation.py +198 -0
- streamlit/components/v2/types.py +324 -0
- streamlit/config.py +456 -53
- streamlit/config_option.py +4 -1
- streamlit/config_util.py +650 -1
- streamlit/connections/snowflake_connection.py +1 -1
- streamlit/connections/snowpark_connection.py +1 -1
- streamlit/dataframe_util.py +33 -26
- streamlit/delta_generator.py +13 -4
- streamlit/delta_generator_singletons.py +11 -15
- streamlit/deprecation_util.py +17 -6
- streamlit/elements/alert.py +16 -0
- streamlit/elements/arrow.py +68 -10
- streamlit/elements/bokeh_chart.py +10 -78
- streamlit/elements/code.py +2 -2
- streamlit/elements/deck_gl_json_chart.py +98 -40
- streamlit/elements/dialog_decorator.py +2 -1
- streamlit/elements/exception.py +4 -2
- streamlit/elements/form.py +27 -0
- streamlit/elements/graphviz_chart.py +1 -3
- streamlit/elements/heading.py +63 -10
- streamlit/elements/html.py +13 -2
- streamlit/elements/image.py +3 -5
- streamlit/elements/layouts.py +59 -33
- streamlit/elements/lib/built_in_chart_utils.py +50 -19
- streamlit/elements/lib/color_util.py +9 -19
- streamlit/elements/lib/column_config_utils.py +9 -12
- streamlit/elements/lib/column_types.py +40 -12
- streamlit/elements/lib/dialog.py +2 -2
- streamlit/elements/lib/image_utils.py +3 -5
- streamlit/elements/lib/layout_utils.py +100 -13
- streamlit/elements/lib/mutable_status_container.py +2 -2
- streamlit/elements/lib/options_selector_utils.py +2 -2
- streamlit/elements/lib/pandas_styler_utils.py +17 -9
- streamlit/elements/lib/shortcut_utils.py +152 -0
- streamlit/elements/lib/utils.py +4 -4
- streamlit/elements/map.py +80 -37
- streamlit/elements/markdown.py +50 -3
- streamlit/elements/media.py +5 -7
- streamlit/elements/metric.py +34 -6
- streamlit/elements/pdf.py +2 -4
- streamlit/elements/plotly_chart.py +197 -20
- streamlit/elements/progress.py +2 -4
- streamlit/elements/space.py +113 -0
- streamlit/elements/spinner.py +1 -1
- streamlit/elements/text.py +20 -3
- streamlit/elements/toast.py +2 -0
- streamlit/elements/vega_charts.py +356 -149
- streamlit/elements/widgets/audio_input.py +12 -11
- streamlit/elements/widgets/button.py +280 -43
- streamlit/elements/widgets/button_group.py +60 -9
- streamlit/elements/widgets/camera_input.py +3 -5
- streamlit/elements/widgets/chat.py +307 -43
- streamlit/elements/widgets/color_picker.py +8 -1
- streamlit/elements/widgets/data_editor.py +88 -44
- streamlit/elements/widgets/file_uploader.py +9 -11
- streamlit/elements/widgets/multiselect.py +4 -3
- streamlit/elements/widgets/number_input.py +4 -4
- streamlit/elements/widgets/radio.py +10 -3
- streamlit/elements/widgets/select_slider.py +8 -5
- streamlit/elements/widgets/selectbox.py +6 -3
- streamlit/elements/widgets/slider.py +38 -42
- streamlit/elements/widgets/text_widgets.py +2 -0
- streamlit/elements/widgets/time_widgets.py +587 -21
- streamlit/elements/write.py +27 -6
- streamlit/emojis.py +1 -1
- streamlit/errors.py +137 -0
- streamlit/git_util.py +1 -1
- streamlit/hello/hello.py +8 -0
- streamlit/hello/utils.py +2 -1
- streamlit/material_icon_names.py +1 -1
- streamlit/navigation/page.py +11 -1
- streamlit/net_util.py +2 -2
- streamlit/proto/Alert_pb2.pyi +3 -3
- streamlit/proto/AppPage_pb2.pyi +7 -1
- streamlit/proto/ArrowData_pb2.py +27 -0
- streamlit/proto/ArrowData_pb2.pyi +52 -0
- streamlit/proto/ArrowNamedDataSet_pb2.pyi +7 -1
- streamlit/proto/ArrowVegaLiteChart_pb2.pyi +7 -1
- streamlit/proto/Arrow_pb2.py +10 -10
- streamlit/proto/Arrow_pb2.pyi +19 -12
- streamlit/proto/AudioInput_pb2.pyi +7 -1
- streamlit/proto/Audio_pb2.pyi +7 -1
- streamlit/proto/AuthRedirect_pb2.pyi +7 -1
- streamlit/proto/AutoRerun_pb2.pyi +7 -1
- streamlit/proto/BackMsg_pb2.py +4 -2
- streamlit/proto/BackMsg_pb2.pyi +34 -4
- streamlit/proto/Balloons_pb2.pyi +7 -1
- streamlit/proto/BidiComponent_pb2.py +34 -0
- streamlit/proto/BidiComponent_pb2.pyi +159 -0
- streamlit/proto/Block_pb2.py +7 -7
- streamlit/proto/Block_pb2.pyi +39 -36
- streamlit/proto/BokehChart_pb2.pyi +7 -1
- streamlit/proto/ButtonGroup_pb2.pyi +9 -9
- streamlit/proto/Button_pb2.py +2 -2
- streamlit/proto/Button_pb2.pyi +11 -2
- streamlit/proto/CameraInput_pb2.pyi +7 -1
- streamlit/proto/ChatInput_pb2.py +6 -6
- streamlit/proto/ChatInput_pb2.pyi +18 -6
- streamlit/proto/Checkbox_pb2.pyi +3 -3
- streamlit/proto/ClientState_pb2.pyi +10 -4
- streamlit/proto/Code_pb2.pyi +7 -1
- streamlit/proto/ColorPicker_pb2.pyi +7 -1
- streamlit/proto/Common_pb2.py +3 -3
- streamlit/proto/Common_pb2.pyi +35 -23
- streamlit/proto/Components_pb2.pyi +19 -13
- streamlit/proto/DataFrame_pb2.pyi +55 -49
- streamlit/proto/DateInput_pb2.pyi +7 -1
- streamlit/proto/DateTimeInput_pb2.py +28 -0
- streamlit/proto/DateTimeInput_pb2.pyi +92 -0
- streamlit/proto/DeckGlJsonChart_pb2.py +10 -4
- streamlit/proto/DeckGlJsonChart_pb2.pyi +12 -6
- streamlit/proto/Delta_pb2.pyi +7 -1
- streamlit/proto/DocString_pb2.pyi +10 -4
- streamlit/proto/DownloadButton_pb2.py +2 -2
- streamlit/proto/DownloadButton_pb2.pyi +16 -2
- streamlit/proto/Element_pb2.py +7 -3
- streamlit/proto/Element_pb2.pyi +33 -5
- streamlit/proto/Empty_pb2.pyi +7 -1
- streamlit/proto/Exception_pb2.pyi +7 -1
- streamlit/proto/Favicon_pb2.pyi +7 -1
- streamlit/proto/FileUploader_pb2.pyi +7 -1
- streamlit/proto/ForwardMsg_pb2.py +12 -10
- streamlit/proto/ForwardMsg_pb2.pyi +42 -15
- streamlit/proto/GapSize_pb2.pyi +4 -4
- streamlit/proto/GitInfo_pb2.pyi +3 -3
- streamlit/proto/GraphVizChart_pb2.pyi +7 -1
- streamlit/proto/Heading_pb2.pyi +7 -1
- streamlit/proto/HeightConfig_pb2.py +2 -2
- streamlit/proto/HeightConfig_pb2.pyi +13 -4
- streamlit/proto/Html_pb2.py +2 -2
- streamlit/proto/Html_pb2.pyi +11 -2
- streamlit/proto/IFrame_pb2.pyi +7 -1
- streamlit/proto/Image_pb2.pyi +10 -4
- streamlit/proto/Json_pb2.pyi +7 -1
- streamlit/proto/LabelVisibilityMessage_pb2.pyi +3 -3
- streamlit/proto/LinkButton_pb2.py +2 -2
- streamlit/proto/LinkButton_pb2.pyi +15 -2
- streamlit/proto/Logo_pb2.pyi +7 -1
- streamlit/proto/Markdown_pb2.pyi +3 -3
- streamlit/proto/Metric_pb2.pyi +7 -7
- streamlit/proto/MetricsEvent_pb2.pyi +10 -4
- streamlit/proto/MultiSelect_pb2.pyi +7 -1
- streamlit/proto/NamedDataSet_pb2.pyi +7 -1
- streamlit/proto/Navigation_pb2.pyi +3 -3
- streamlit/proto/NewSession_pb2.py +18 -18
- streamlit/proto/NewSession_pb2.pyi +59 -40
- streamlit/proto/NumberInput_pb2.pyi +3 -3
- streamlit/proto/PageConfig_pb2.pyi +7 -7
- streamlit/proto/PageInfo_pb2.pyi +7 -1
- streamlit/proto/PageLink_pb2.py +2 -2
- streamlit/proto/PageLink_pb2.pyi +11 -2
- streamlit/proto/PageNotFound_pb2.pyi +7 -1
- streamlit/proto/PageProfile_pb2.pyi +13 -7
- streamlit/proto/PagesChanged_pb2.pyi +7 -1
- streamlit/proto/ParentMessage_pb2.pyi +7 -1
- streamlit/proto/PlotlyChart_pb2.py +8 -6
- streamlit/proto/PlotlyChart_pb2.pyi +9 -7
- streamlit/proto/Progress_pb2.pyi +7 -1
- streamlit/proto/Radio_pb2.pyi +7 -1
- streamlit/proto/RootContainer_pb2.pyi +1 -1
- streamlit/proto/Selectbox_pb2.pyi +7 -1
- streamlit/proto/SessionEvent_pb2.pyi +7 -1
- streamlit/proto/SessionStatus_pb2.pyi +7 -1
- streamlit/proto/Skeleton_pb2.pyi +3 -3
- streamlit/proto/Slider_pb2.pyi +5 -5
- streamlit/proto/Snow_pb2.pyi +7 -1
- streamlit/proto/Space_pb2.py +27 -0
- streamlit/proto/Space_pb2.pyi +48 -0
- streamlit/proto/Spinner_pb2.pyi +7 -1
- streamlit/proto/TextAlignmentConfig_pb2.py +29 -0
- streamlit/proto/TextAlignmentConfig_pb2.pyi +68 -0
- streamlit/proto/TextArea_pb2.pyi +7 -1
- streamlit/proto/TextInput_pb2.pyi +3 -3
- streamlit/proto/Text_pb2.pyi +7 -1
- streamlit/proto/TimeInput_pb2.pyi +7 -1
- streamlit/proto/Toast_pb2.pyi +7 -1
- streamlit/proto/VegaLiteChart_pb2.pyi +7 -1
- streamlit/proto/Video_pb2.pyi +6 -6
- streamlit/proto/WidgetStates_pb2.py +2 -2
- streamlit/proto/WidgetStates_pb2.pyi +23 -7
- streamlit/proto/WidthConfig_pb2.py +2 -2
- streamlit/proto/WidthConfig_pb2.pyi +13 -4
- streamlit/proto/openmetrics_data_model_pb2.pyi +52 -52
- streamlit/runtime/app_session.py +65 -2
- streamlit/runtime/caching/cache_data_api.py +5 -5
- streamlit/runtime/caching/cache_errors.py +4 -1
- streamlit/runtime/caching/cache_resource_api.py +5 -4
- streamlit/runtime/caching/cache_utils.py +3 -2
- streamlit/runtime/caching/cached_message_replay.py +3 -3
- streamlit/runtime/caching/hashing.py +4 -5
- streamlit/runtime/caching/legacy_cache_api.py +2 -1
- streamlit/runtime/connection_factory.py +1 -3
- streamlit/runtime/download_data_util.py +53 -0
- streamlit/runtime/forward_msg_queue.py +5 -1
- streamlit/runtime/fragment.py +2 -1
- streamlit/runtime/media_file_manager.py +178 -2
- streamlit/runtime/memory_media_file_storage.py +1 -1
- streamlit/runtime/metrics_util.py +91 -3
- streamlit/runtime/runtime.py +14 -0
- streamlit/runtime/scriptrunner/exec_code.py +2 -1
- streamlit/runtime/scriptrunner/script_runner.py +5 -3
- streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -6
- streamlit/runtime/secrets.py +2 -4
- streamlit/runtime/session_manager.py +3 -1
- streamlit/runtime/state/common.py +30 -5
- streamlit/runtime/state/presentation.py +85 -0
- streamlit/runtime/state/query_params.py +80 -29
- streamlit/runtime/state/safe_session_state.py +2 -2
- streamlit/runtime/state/session_state.py +221 -17
- streamlit/runtime/state/widgets.py +19 -3
- streamlit/runtime/websocket_session_manager.py +3 -1
- streamlit/source_util.py +2 -2
- streamlit/static/index.html +2 -2
- streamlit/static/manifest.json +557 -239
- streamlit/static/static/css/{index.CIiu7Ygf.css → index.BpABIXK9.css} +1 -1
- streamlit/static/static/css/index.DgR7E2CV.css +1 -0
- streamlit/static/static/js/{ErrorOutline.esm.DUpR0_Ka.js → ErrorOutline.esm.ZJDbmVTx.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.CN4j9-1w.js → FileDownload.esm.Dx0vI3vH.js} +1 -1
- streamlit/static/static/js/{FileHelper.CaIUKG91.js → FileHelper.B7Ero7qQ.js} +3 -3
- streamlit/static/static/js/{FormClearHelper.DTcdrasw.js → FormClearHelper.CG2XN1_g.js} +1 -1
- streamlit/static/static/js/IFrameUtil.DefezniK.js +1 -0
- streamlit/static/static/js/InputInstructions.Cj5-1zf6.js +1 -0
- streamlit/static/static/js/Particles.BfWfv0Aw.js +1 -0
- streamlit/static/static/js/{ProgressBar.DetlP5aY.js → ProgressBar.CGQ8OgfO.js} +2 -2
- streamlit/static/static/js/StreamlitSyntaxHighlighter.DTKLpwhl.js +20 -0
- streamlit/static/static/js/{Toolbar.C77ar7rq.js → Toolbar.B2qFUmd9.js} +1 -1
- streamlit/static/static/js/_arrayIncludes.B19Iyn2B.js +1 -0
- streamlit/static/static/js/_baseIndexOf.BTknn6Gb.js +1 -0
- streamlit/static/static/js/{base-input.BQft14La.js → base-input.o9tL8MDP.js} +4 -4
- streamlit/static/static/js/{checkbox.yZOfXCeX.js → checkbox.0BeV1IBL.js} +1 -1
- streamlit/static/static/js/{createSuper.Dh9w1cs8.js → createSuper.RBO59fEm.js} +1 -1
- streamlit/static/static/js/data-grid-overlay-editor.CiTkUy0t.js +1 -0
- streamlit/static/static/js/{downloader.MeHtkq8r.js → downloader.DwNZg3Mw.js} +1 -1
- streamlit/static/static/js/embed.XT9xNd3F.js +195 -0
- streamlit/static/static/js/{es6.VpBPGCnM.js → es6.x9KsYQg-.js} +2 -2
- streamlit/static/static/js/{iframeResizer.contentWindow.yMw_ARIL.js → iframeResizer.contentWindow.ZVXpMPi0.js} +1 -1
- streamlit/static/static/js/index.5VPOamri.js +1 -0
- streamlit/static/static/js/index.8HslT92O.js +14 -0
- streamlit/static/static/js/index.AnXMIBz3.js +7 -0
- streamlit/static/static/js/index.B0yp3bM1.js +6 -0
- streamlit/static/static/js/index.B1fRb5wF.js +1 -0
- streamlit/static/static/js/index.B527JZdO.js +3 -0
- streamlit/static/static/js/index.BHgV-yW4.js +1 -0
- streamlit/static/static/js/index.BQr-XwGV.js +1 -0
- streamlit/static/static/js/index.BTtmaLDB.js +1 -0
- streamlit/static/static/js/index.BWB_91TA.js +1 -0
- streamlit/static/static/js/index.BfEKaEmw.js +1 -0
- streamlit/static/static/js/index.BfXjTO8b.js +1 -0
- streamlit/static/static/js/index.Bjy4NRu9.js +3 -0
- streamlit/static/static/js/index.Bu5JWpT_.js +1 -0
- streamlit/static/static/js/index.BuCx76ZV.js +1 -0
- streamlit/static/static/js/index.BxjzhVUb.js +2 -0
- streamlit/static/static/js/index.By55VdPY.js +1 -0
- streamlit/static/static/js/index.CF5MxTbK.js +1 -0
- streamlit/static/static/js/index.CLmq_z9K.js +1 -0
- streamlit/static/static/js/index.CNH4rdSz.js +1 -0
- streamlit/static/static/js/{index.B0H9IXUJ.js → index.CTgm_-jO.js} +10 -41
- streamlit/static/static/js/index.C_rK-Swb.js +188 -0
- streamlit/static/static/js/index.CjozwSzS.js +1 -0
- streamlit/static/static/js/{index.CH1tqnSs.js → index.CkGVt6-G.js} +1 -1
- streamlit/static/static/js/index.CuvXOyER.js +2 -0
- streamlit/static/static/js/{index.FFOzOWzC.js → index.CyUHWoCC.js} +2 -2
- streamlit/static/static/js/index.CyroQtI4.js +2 -0
- streamlit/static/static/js/index.D6HmkoDm.js +263 -0
- streamlit/static/static/js/index.DAqCNvsO.js +1 -0
- streamlit/static/static/js/index.DB_w_CZQ.js +1 -0
- streamlit/static/static/js/index.DBalctjj.js +2 -0
- streamlit/static/static/js/index.DK0RFJUG.js +11 -0
- streamlit/static/static/js/index.DMxc2XFp.js +151 -0
- streamlit/static/static/js/index.DO5utP74.js +2 -0
- streamlit/static/static/js/index.DS7lf09n.js +1 -0
- streamlit/static/static/js/index.DWexTVLY.js +1 -0
- streamlit/static/static/js/index.DXxnU5ej.js +1 -0
- streamlit/static/static/js/index.DcU3uDvB.js +2 -0
- streamlit/static/static/js/index.DlltaH7J.js +1 -0
- streamlit/static/static/js/index.DpNTZz82.js +27 -0
- streamlit/static/static/js/index.Dr9HIhQw.js +1 -0
- streamlit/static/static/js/index.DsgAU5lc.js +1 -0
- streamlit/static/static/js/{index.64ejlaaT.js → index.KfXqjDYy.js} +1 -1
- streamlit/static/static/js/index.PaidgjCs.js +1 -0
- streamlit/static/static/js/index.RJZuWCGA.js +1 -0
- streamlit/static/static/js/{index.Ctn27_AE.js → index.hbeqcRTn.js} +53 -122
- streamlit/static/static/js/index.q5hIQwAY.js +1 -0
- streamlit/static/static/js/index.rORSX6IW.js +1 -0
- streamlit/static/static/js/index.uSX757_v.js +1 -0
- streamlit/static/static/js/index.x_QRaLMd.js +1 -0
- streamlit/static/static/js/{input.s6pjQ49A.js → input.D5oh9-aB.js} +2 -2
- streamlit/static/static/js/main.q9oGOg0H.js +13 -0
- streamlit/static/static/js/{memory.Cuvsdfrl.js → memory.5kCSFUJS.js} +1 -1
- streamlit/static/static/js/moment.C3j7ZXd7.js +4 -0
- streamlit/static/static/js/number-overlay-editor.Cn_LsK8N.js +9 -0
- streamlit/static/static/js/pandasStylerUtils.BqhXt51_.js +1 -0
- streamlit/static/static/js/{possibleConstructorReturn.CqidKeei.js → possibleConstructorReturn.DD9NK1Z8.js} +1 -1
- streamlit/static/static/js/record.B-tDciZb.js +1 -0
- streamlit/static/static/js/{sandbox.CCQREcJx.js → sandbox.DACSyz29.js} +1 -1
- streamlit/static/static/js/styled-components.C3R090At.js +1 -0
- streamlit/static/static/js/threshold.Q1mXg5rX.js +1 -0
- streamlit/static/static/js/throttle.B0GR3Iyz.js +1 -0
- streamlit/static/static/js/{timepicker.mkJF97Bb.js → timepicker.BdhzPxrv.js} +1 -1
- streamlit/static/static/js/timer.C2hYhUse.js +1 -0
- streamlit/static/static/js/{toConsumableArray.De7I7KVR.js → toConsumableArray.Db2pdqM2.js} +1 -1
- streamlit/static/static/js/uniqueId.CtqIr-Yh.js +1 -0
- streamlit/static/static/js/urls.BwSlolu9.js +1 -0
- streamlit/static/static/js/{useBasicWidgetState.CedkNjUW.js → useBasicWidgetState.Bfp6TnSw.js} +1 -1
- streamlit/static/static/js/useIntlLocale.hRV75Xgj.js +12 -0
- streamlit/static/static/js/{useTextInputAutoExpand.Ca7w8dVs.js → useTextInputAutoExpand.QepX7n8Y.js} +1 -1
- streamlit/static/static/js/useUpdateUiValue.DHx8TzX6.js +1 -0
- streamlit/static/static/js/useWaveformController.WxVzpzEX.js +1 -0
- streamlit/static/static/js/value.B4vHRSi7.js +1 -0
- streamlit/static/static/js/wavesurfer.esm.vI8Eid4k.js +73 -0
- streamlit/static/static/js/withCalculatedWidth.DcKeRSWJ.js +1 -0
- streamlit/static/static/js/withFullScreenWrapper.CrHddARq.js +1 -0
- streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
- streamlit/string_util.py +9 -4
- streamlit/testing/v1/app_test.py +17 -2
- streamlit/testing/v1/element_tree.py +85 -9
- streamlit/testing/v1/util.py +2 -2
- streamlit/type_util.py +3 -4
- streamlit/url_util.py +1 -3
- streamlit/user_info.py +1 -2
- streamlit/util.py +3 -1
- streamlit/watcher/event_based_path_watcher.py +23 -12
- streamlit/watcher/local_sources_watcher.py +11 -1
- streamlit/watcher/path_watcher.py +9 -6
- streamlit/watcher/polling_path_watcher.py +4 -1
- streamlit/watcher/util.py +2 -2
- streamlit/web/bootstrap.py +24 -0
- streamlit/web/cli.py +51 -22
- streamlit/web/server/bidi_component_request_handler.py +193 -0
- streamlit/web/server/component_file_utils.py +97 -0
- streamlit/web/server/component_request_handler.py +8 -21
- streamlit/web/server/oauth_authlib_routes.py +5 -2
- streamlit/web/server/oidc_mixin.py +3 -1
- streamlit/web/server/routes.py +2 -2
- streamlit/web/server/server.py +9 -0
- streamlit/web/server/server_util.py +3 -1
- streamlit/web/server/upload_file_request_handler.py +19 -1
- {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/METADATA +10 -7
- streamlit-1.52.0.dist-info/RECORD +620 -0
- streamlit/static/static/css/index.CHEnSPGk.css +0 -1
- streamlit/static/static/js/Hooks.BRba_Own.js +0 -1
- streamlit/static/static/js/InputInstructions.xnSDuYeQ.js +0 -1
- streamlit/static/static/js/Particles.CElH0XX2.js +0 -1
- streamlit/static/static/js/data-grid-overlay-editor.DcuHuCyW.js +0 -1
- streamlit/static/static/js/index.6xX1278W.js +0 -975
- streamlit/static/static/js/index.B-hiXRzw.js +0 -1
- streamlit/static/static/js/index.B4cAbHP6.js +0 -1
- streamlit/static/static/js/index.B4dUQfni.js +0 -1
- streamlit/static/static/js/index.BPQo7BKk.js +0 -1
- streamlit/static/static/js/index.Baqa90pe.js +0 -2
- streamlit/static/static/js/index.Bj9JgOEC.js +0 -1
- streamlit/static/static/js/index.BjCwMzj4.js +0 -3
- streamlit/static/static/js/index.Bm3VbPB5.js +0 -1
- streamlit/static/static/js/index.Bxz2yX3P.js +0 -1
- streamlit/static/static/js/index.BycLveZ4.js +0 -1
- streamlit/static/static/js/index.C9BdUqTi.js +0 -1
- streamlit/static/static/js/index.CFMf5_ez.js +0 -197
- streamlit/static/static/js/index.CGYqqs6j.js +0 -1
- streamlit/static/static/js/index.CMItVsFA.js +0 -1
- streamlit/static/static/js/index.CTBk8Vk2.js +0 -1
- streamlit/static/static/js/index.CiAQIz1H.js +0 -7
- streamlit/static/static/js/index.Cj7DSzVR.js +0 -73
- streamlit/static/static/js/index.Ck8rQ9OL.js +0 -1
- streamlit/static/static/js/index.ClELlchS.js +0 -1617
- streamlit/static/static/js/index.Cnpi3o3E.js +0 -1
- streamlit/static/static/js/index.D2QEXQq_.js +0 -1
- streamlit/static/static/js/index.DH71Ezyj.js +0 -1
- streamlit/static/static/js/index.DHh-U0dK.js +0 -3
- streamlit/static/static/js/index.DK7hD7_w.js +0 -1
- streamlit/static/static/js/index.DKv_lNO7.js +0 -2
- streamlit/static/static/js/index.DNLrMXgm.js +0 -12
- streamlit/static/static/js/index.DW0Grddz.js +0 -1
- streamlit/static/static/js/index.Dbe-Q3C-.js +0 -2
- streamlit/static/static/js/index.DcPNYEUo.js +0 -1
- streamlit/static/static/js/index.DuxqVQpd.js +0 -1
- streamlit/static/static/js/index.GRUzrudl.js +0 -1
- streamlit/static/static/js/number-overlay-editor.DdgVR5m3.js +0 -9
- streamlit/static/static/js/uniqueId.RI1LJdtz.js +0 -1
- streamlit/static/static/js/useUpdateUiValue.DeXelfRH.js +0 -1
- streamlit/static/static/js/withFullScreenWrapper.C3561XxJ.js +0 -1
- streamlit/static/static/media/MaterialSymbols-Rounded.DeCZgS-4.woff2 +0 -0
- streamlit-1.50.0.dist-info/RECORD +0 -557
- {streamlit-1.50.0.data → streamlit-1.52.0.data}/scripts/streamlit.cmd +0 -0
- {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/WHEEL +0 -0
- {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/entry_points.txt +0 -0
- {streamlit-1.50.0.dist-info → streamlit-1.52.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
20
|
+
|
|
21
|
+
from streamlit.components.v2.bidi_component.constants import ARROW_REF_KEY
|
|
22
|
+
from streamlit.dataframe_util import convert_anything_to_arrow_bytes, is_dataframe_like
|
|
23
|
+
from streamlit.logger import get_logger
|
|
24
|
+
from streamlit.proto.BidiComponent_pb2 import BidiComponent as BidiComponentProto
|
|
25
|
+
from streamlit.proto.BidiComponent_pb2 import MixedData as MixedDataProto
|
|
26
|
+
from streamlit.util import AttributeDictionary, calc_md5
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from streamlit.components.v2.bidi_component.state import BidiComponentState
|
|
30
|
+
|
|
31
|
+
_LOGGER = get_logger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _extract_dataframes_from_dict(
|
|
35
|
+
data: dict[str, Any], arrow_blobs: dict[str, bytes] | None = None
|
|
36
|
+
) -> dict[str, Any]:
|
|
37
|
+
"""Extract dataframe-like objects from a dictionary and replace them with
|
|
38
|
+
placeholders.
|
|
39
|
+
|
|
40
|
+
This function traverses the first level of a dictionary, detects any
|
|
41
|
+
dataframe-like objects, stores their Arrow bytes representation in the
|
|
42
|
+
`arrow_blobs` dictionary, and replaces them with JSON-serializable
|
|
43
|
+
placeholder objects.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
data
|
|
48
|
+
The dictionary to process. Only the first level is checked for
|
|
49
|
+
dataframe-like objects.
|
|
50
|
+
arrow_blobs
|
|
51
|
+
The dictionary to store the extracted Arrow bytes in, keyed by a unique
|
|
52
|
+
reference ID.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
dict[str, Any]
|
|
57
|
+
A new dictionary with dataframe-like objects replaced by placeholders.
|
|
58
|
+
"""
|
|
59
|
+
if arrow_blobs is None:
|
|
60
|
+
arrow_blobs = {}
|
|
61
|
+
|
|
62
|
+
processed_data = {}
|
|
63
|
+
|
|
64
|
+
for key, value in data.items():
|
|
65
|
+
if is_dataframe_like(value):
|
|
66
|
+
# This is a dataframe-like object, serialize it to Arrow
|
|
67
|
+
try:
|
|
68
|
+
arrow_bytes = convert_anything_to_arrow_bytes(value)
|
|
69
|
+
# Use deterministic, content-addressed ref IDs so placeholders
|
|
70
|
+
# are stable for identical content on each run. This also provides
|
|
71
|
+
# natural deduplication - identical DataFrames share a single blob.
|
|
72
|
+
ref_id = calc_md5(arrow_bytes)
|
|
73
|
+
arrow_blobs[ref_id] = arrow_bytes
|
|
74
|
+
processed_data[key] = {ARROW_REF_KEY: ref_id}
|
|
75
|
+
except Exception as e:
|
|
76
|
+
# If Arrow serialization fails, keep the original value for JSON
|
|
77
|
+
# serialization attempt downstream.
|
|
78
|
+
_LOGGER.debug(
|
|
79
|
+
"Arrow serialization failed for key %r, keeping original value: %s",
|
|
80
|
+
key,
|
|
81
|
+
e,
|
|
82
|
+
)
|
|
83
|
+
processed_data[key] = value
|
|
84
|
+
else:
|
|
85
|
+
# Not dataframe-like, keep as-is
|
|
86
|
+
processed_data[key] = value
|
|
87
|
+
|
|
88
|
+
return processed_data
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def serialize_mixed_data(data: Any, bidi_component_proto: BidiComponentProto) -> None:
|
|
92
|
+
"""Serialize mixed data with automatic dataframe detection into a protobuf message.
|
|
93
|
+
|
|
94
|
+
This function detects dataframe-like objects in the first level of a dictionary,
|
|
95
|
+
extracts them into separate Arrow blobs, and populates a `MixedDataProto`
|
|
96
|
+
protobuf message for efficient serialization.
|
|
97
|
+
|
|
98
|
+
Parameters
|
|
99
|
+
----------
|
|
100
|
+
data
|
|
101
|
+
The data structure to serialize. If it is a dictionary, its first
|
|
102
|
+
level will be scanned for dataframe-like objects.
|
|
103
|
+
bidi_component_proto
|
|
104
|
+
The protobuf message to populate with the serialized data.
|
|
105
|
+
|
|
106
|
+
"""
|
|
107
|
+
arrow_blobs: dict[str, bytes] = {}
|
|
108
|
+
|
|
109
|
+
# Only process dictionaries for automatic dataframe detection
|
|
110
|
+
if isinstance(data, dict):
|
|
111
|
+
processed_data = _extract_dataframes_from_dict(data, arrow_blobs)
|
|
112
|
+
else:
|
|
113
|
+
# For non-dict data (lists, tuples, etc.), pass through as-is
|
|
114
|
+
# We don't automatically detect dataframes in these structures
|
|
115
|
+
processed_data = data
|
|
116
|
+
|
|
117
|
+
if arrow_blobs:
|
|
118
|
+
# We have dataframes, use mixed data serialization
|
|
119
|
+
mixed_proto = MixedDataProto()
|
|
120
|
+
try:
|
|
121
|
+
mixed_proto.json = json.dumps(processed_data)
|
|
122
|
+
except TypeError:
|
|
123
|
+
# If JSON serialization fails (e.g., due to undetected dataframes),
|
|
124
|
+
# fall back to string representation
|
|
125
|
+
mixed_proto.json = json.dumps(str(processed_data))
|
|
126
|
+
|
|
127
|
+
# Add Arrow blobs to the protobuf
|
|
128
|
+
for ref_id, arrow_bytes in arrow_blobs.items():
|
|
129
|
+
mixed_proto.arrow_blobs[ref_id].data = arrow_bytes
|
|
130
|
+
|
|
131
|
+
bidi_component_proto.mixed.CopyFrom(mixed_proto)
|
|
132
|
+
else:
|
|
133
|
+
# No dataframes found, use regular JSON serialization
|
|
134
|
+
try:
|
|
135
|
+
bidi_component_proto.json = json.dumps(processed_data)
|
|
136
|
+
except TypeError:
|
|
137
|
+
# If JSON serialization fails (e.g., due to dataframes in lists/tuples),
|
|
138
|
+
# fall back to string representation
|
|
139
|
+
bidi_component_proto.json = json.dumps(str(processed_data))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def handle_deserialize(s: str | None) -> Any:
|
|
143
|
+
"""Deserialize a JSON string, returning the string itself if it's not valid JSON.
|
|
144
|
+
|
|
145
|
+
Parameters
|
|
146
|
+
----------
|
|
147
|
+
s
|
|
148
|
+
The string to deserialize.
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
Any
|
|
153
|
+
The deserialized JSON object, or the original string if parsing fails.
|
|
154
|
+
Returns `None` if the input is `None`.
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
if s is None:
|
|
158
|
+
return None
|
|
159
|
+
try:
|
|
160
|
+
return json.loads(s)
|
|
161
|
+
except json.JSONDecodeError:
|
|
162
|
+
return s
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def deserialize_trigger_list(s: str | None) -> list[Any] | None:
|
|
166
|
+
"""Deserialize trigger aggregator payloads as a list.
|
|
167
|
+
|
|
168
|
+
For bidirectional components, the frontend always sends a JSON array of payload
|
|
169
|
+
objects. This deserializer normalizes older or singular payloads into a list
|
|
170
|
+
while preserving ``None`` for cleared values.
|
|
171
|
+
|
|
172
|
+
Parameters
|
|
173
|
+
----------
|
|
174
|
+
s
|
|
175
|
+
The JSON string to deserialize, hopefully representing a list of payloads.
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
list[Any] or None
|
|
180
|
+
A list of payloads, or `None` if the input was `None`.
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
value = handle_deserialize(s)
|
|
184
|
+
if value is None:
|
|
185
|
+
return None
|
|
186
|
+
if isinstance(value, list):
|
|
187
|
+
return value
|
|
188
|
+
return [value]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@dataclass
|
|
192
|
+
class BidiComponentSerde:
|
|
193
|
+
"""Serialization and deserialization logic for a bidirectional component.
|
|
194
|
+
|
|
195
|
+
This class handles the conversion of component state between the frontend
|
|
196
|
+
(JSON strings) and the backend (Python objects).
|
|
197
|
+
|
|
198
|
+
The canonical shape is a flat mapping of state keys to values.
|
|
199
|
+
|
|
200
|
+
Parameters
|
|
201
|
+
----------
|
|
202
|
+
default
|
|
203
|
+
A dictionary of default values to be applied to the state when
|
|
204
|
+
deserializing, if the corresponding keys are not already present.
|
|
205
|
+
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
default: dict[str, Any] | None = None
|
|
209
|
+
|
|
210
|
+
def deserialize(self, ui_value: str | dict[str, Any] | None) -> BidiComponentState:
|
|
211
|
+
"""Deserialize the component's state from a frontend value.
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
ui_value
|
|
216
|
+
The value received from the frontend, which can be a JSON string,
|
|
217
|
+
a dictionary, or `None`.
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
BidiComponentState
|
|
222
|
+
The deserialized state as a flat mapping.
|
|
223
|
+
|
|
224
|
+
"""
|
|
225
|
+
# Normalize the incoming JSON payload into a dict. Any failure to decode
|
|
226
|
+
# (or an unexpected non-mapping structure) results in an empty mapping
|
|
227
|
+
# so that the returned type adheres to :class:`BidiComponentState`.
|
|
228
|
+
|
|
229
|
+
deserialized_value: dict[str, Any]
|
|
230
|
+
|
|
231
|
+
if isinstance(ui_value, dict):
|
|
232
|
+
deserialized_value = ui_value
|
|
233
|
+
elif isinstance(ui_value, str):
|
|
234
|
+
try:
|
|
235
|
+
parsed = json.loads(ui_value)
|
|
236
|
+
deserialized_value = parsed if isinstance(parsed, dict) else {}
|
|
237
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
238
|
+
_LOGGER.warning(
|
|
239
|
+
"Failed to deserialize component state from frontend: %s",
|
|
240
|
+
e,
|
|
241
|
+
exc_info=e,
|
|
242
|
+
)
|
|
243
|
+
deserialized_value = {}
|
|
244
|
+
else:
|
|
245
|
+
deserialized_value = {}
|
|
246
|
+
|
|
247
|
+
# Apply default values for keys that don't exist in the current state
|
|
248
|
+
if self.default is not None:
|
|
249
|
+
for default_key, default_value in self.default.items():
|
|
250
|
+
if default_key not in deserialized_value:
|
|
251
|
+
deserialized_value[default_key] = default_value
|
|
252
|
+
|
|
253
|
+
state: BidiComponentState = cast(
|
|
254
|
+
"BidiComponentState", AttributeDictionary(deserialized_value)
|
|
255
|
+
)
|
|
256
|
+
return state
|
|
257
|
+
|
|
258
|
+
def serialize(self, value: Any) -> str:
|
|
259
|
+
"""Serialize the component's state into a JSON string for the frontend.
|
|
260
|
+
|
|
261
|
+
Parameters
|
|
262
|
+
----------
|
|
263
|
+
value
|
|
264
|
+
The component state to serialize.
|
|
265
|
+
|
|
266
|
+
Returns
|
|
267
|
+
-------
|
|
268
|
+
str
|
|
269
|
+
A JSON string representation of the value.
|
|
270
|
+
|
|
271
|
+
"""
|
|
272
|
+
return json.dumps(value)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import Any, TypedDict
|
|
18
|
+
|
|
19
|
+
from streamlit.util import AttributeDictionary
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BidiComponentState(TypedDict, total=False):
|
|
23
|
+
"""
|
|
24
|
+
The schema for the state of a bidirectional component.
|
|
25
|
+
|
|
26
|
+
The state is a flat dictionary-like object (key -> value) that supports
|
|
27
|
+
both key and attribute notation via :class:`AttributeDictionary`.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
# Flat mapping of state key -> value
|
|
31
|
+
# (kept empty to reflect open set of keys)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class BidiComponentResult(AttributeDictionary):
|
|
35
|
+
"""The schema for the custom component result object.
|
|
36
|
+
|
|
37
|
+
The custom component result object is a dictionary-like object that
|
|
38
|
+
supports both key and attribute notation. It contains all of the
|
|
39
|
+
component's state and trigger values.
|
|
40
|
+
|
|
41
|
+
Attributes
|
|
42
|
+
----------
|
|
43
|
+
<state_keys> : Any
|
|
44
|
+
All state values from the component. State values are persistent across
|
|
45
|
+
app reruns until explicitly changed. You can have multiple state keys
|
|
46
|
+
as attributes.
|
|
47
|
+
<trigger_keys> : Any
|
|
48
|
+
All trigger values from the component. Trigger values are transient and
|
|
49
|
+
reset to ``None`` after one script run. You can have multiple trigger
|
|
50
|
+
keys as attributes.
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
state_vals: dict[str, Any] | None = None,
|
|
57
|
+
trigger_vals: dict[str, Any] | None = None,
|
|
58
|
+
) -> None:
|
|
59
|
+
"""Initialize a BidiComponentResult.
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
state_vals : dict[str, Any] or None
|
|
64
|
+
A dictionary of state values from the component.
|
|
65
|
+
trigger_vals : dict[str, Any] or None
|
|
66
|
+
A dictionary of trigger values from the component.
|
|
67
|
+
"""
|
|
68
|
+
if state_vals is None:
|
|
69
|
+
state_vals = {}
|
|
70
|
+
if trigger_vals is None:
|
|
71
|
+
trigger_vals = {}
|
|
72
|
+
|
|
73
|
+
super().__init__(
|
|
74
|
+
{
|
|
75
|
+
# The order here matters, because all stateful values will
|
|
76
|
+
# always be returned, but trigger values may be transient. This
|
|
77
|
+
# mirrors presentation behavior in
|
|
78
|
+
# `make_bidi_component_presenter`.
|
|
79
|
+
**trigger_vals,
|
|
80
|
+
**state_vals,
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def unwrap_component_state(raw_state: Any) -> dict[str, Any]:
|
|
86
|
+
"""Return flat mapping when given a dict; otherwise, empty dict.
|
|
87
|
+
|
|
88
|
+
The new canonical state is flat, so this is effectively an identity for
|
|
89
|
+
dict inputs and a guard for other types.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
return dict(raw_state) if isinstance(raw_state, dict) else {}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Shared resolver for building component definitions with path validation.
|
|
16
|
+
|
|
17
|
+
This module centralizes the logic for interpreting js/css inputs as inline
|
|
18
|
+
content vs path/glob strings, validating them against a component's asset
|
|
19
|
+
directory, and producing a BidiComponentDefinition with correct asset-relative
|
|
20
|
+
URLs used by the server.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import TYPE_CHECKING
|
|
27
|
+
|
|
28
|
+
from streamlit.components.v2.component_path_utils import ComponentPathUtils
|
|
29
|
+
from streamlit.components.v2.component_registry import BidiComponentDefinition
|
|
30
|
+
from streamlit.errors import StreamlitAPIException
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from streamlit.components.v2.component_manager import BidiComponentManager
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def build_definition_with_validation(
|
|
37
|
+
*,
|
|
38
|
+
manager: BidiComponentManager,
|
|
39
|
+
component_key: str,
|
|
40
|
+
html: str | None,
|
|
41
|
+
css: str | None,
|
|
42
|
+
js: str | None,
|
|
43
|
+
) -> BidiComponentDefinition:
|
|
44
|
+
"""Construct a definition and validate ``js``/``css`` inputs against ``asset_dir``.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
manager : BidiComponentManager
|
|
49
|
+
Component manager used to resolve the component's ``asset_dir`` and
|
|
50
|
+
related metadata.
|
|
51
|
+
component_key : str
|
|
52
|
+
Fully-qualified name of the component to build a definition for.
|
|
53
|
+
html : str | None
|
|
54
|
+
Inline HTML content to include in the definition. If ``None``, the
|
|
55
|
+
component will not include HTML content.
|
|
56
|
+
css : str | None
|
|
57
|
+
Either inline CSS content or a path/glob to a CSS file inside the
|
|
58
|
+
component's ``asset_dir``. Inline strings are kept as-is; file-backed
|
|
59
|
+
inputs are validated and converted to an ``asset_dir``-relative URL.
|
|
60
|
+
js : str | None
|
|
61
|
+
Either inline JavaScript content or a path/glob to a JS file inside the
|
|
62
|
+
component's ``asset_dir``. Inline strings are kept as-is; file-backed
|
|
63
|
+
inputs are validated and converted to an ``asset_dir``-relative URL.
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
BidiComponentDefinition
|
|
68
|
+
A component definition with inline content preserved and file-backed
|
|
69
|
+
entries resolved to absolute filesystem paths plus their
|
|
70
|
+
``asset_dir``-relative URLs.
|
|
71
|
+
|
|
72
|
+
Raises
|
|
73
|
+
------
|
|
74
|
+
StreamlitAPIException
|
|
75
|
+
If a path/glob is provided but the component has no declared
|
|
76
|
+
``asset_dir``, if a glob resolves to zero or multiple files, or if any
|
|
77
|
+
resolved path escapes the declared ``asset_dir``.
|
|
78
|
+
|
|
79
|
+
Notes
|
|
80
|
+
-----
|
|
81
|
+
- Inline strings are treated as content (no manifest required).
|
|
82
|
+
- Path-like strings require the component to be declared in the package
|
|
83
|
+
manifest with an ``asset_dir``.
|
|
84
|
+
- Globs are supported only within ``asset_dir`` and must resolve to exactly
|
|
85
|
+
one file.
|
|
86
|
+
- Relative paths are resolved strictly against the component's ``asset_dir``
|
|
87
|
+
and must remain within it after resolution. Absolute paths are not
|
|
88
|
+
allowed.
|
|
89
|
+
- For file-backed entries, the URL sent to the frontend is the
|
|
90
|
+
``asset_dir``-relative path, served under
|
|
91
|
+
``/_stcore/bidi-components/<component>/<relative_path>``.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
asset_root = manager.get_component_asset_root(component_key)
|
|
95
|
+
|
|
96
|
+
def _resolve_entry(
|
|
97
|
+
value: str | None, *, kind: str
|
|
98
|
+
) -> tuple[str | None, str | None]:
|
|
99
|
+
# Inline content: None rel URL
|
|
100
|
+
if value is None:
|
|
101
|
+
return None, None
|
|
102
|
+
if ComponentPathUtils.looks_like_inline_content(value):
|
|
103
|
+
return value, None
|
|
104
|
+
|
|
105
|
+
# For path-like strings, asset_root must exist
|
|
106
|
+
if asset_root is None:
|
|
107
|
+
raise StreamlitAPIException(
|
|
108
|
+
f"Component '{component_key}' must be declared in pyproject.toml with asset_dir "
|
|
109
|
+
f"to use file-backed {kind}."
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
value_str = value
|
|
113
|
+
|
|
114
|
+
# If looks like a glob, resolve strictly inside asset_root
|
|
115
|
+
if ComponentPathUtils.has_glob_characters(value_str):
|
|
116
|
+
resolved = ComponentPathUtils.resolve_glob_pattern(value_str, asset_root)
|
|
117
|
+
ComponentPathUtils.ensure_within_root(resolved, asset_root, kind=kind)
|
|
118
|
+
# Use resolved absolute paths to avoid macOS /private prefix mismatch
|
|
119
|
+
rel_url = str(
|
|
120
|
+
resolved.resolve().relative_to(asset_root.resolve()).as_posix()
|
|
121
|
+
)
|
|
122
|
+
return str(resolved), rel_url
|
|
123
|
+
|
|
124
|
+
# Concrete path: must be asset-dir-relative (reject absolute & traversal)
|
|
125
|
+
ComponentPathUtils.validate_path_security(value_str)
|
|
126
|
+
candidate = asset_root / Path(value_str)
|
|
127
|
+
ComponentPathUtils.ensure_within_root(candidate, asset_root, kind=kind)
|
|
128
|
+
resolved_candidate = candidate.resolve()
|
|
129
|
+
rel_url = str(resolved_candidate.relative_to(asset_root.resolve()).as_posix())
|
|
130
|
+
return str(resolved_candidate), rel_url
|
|
131
|
+
|
|
132
|
+
css_value, css_rel = _resolve_entry(css, kind="css")
|
|
133
|
+
js_value, js_rel = _resolve_entry(js, kind="js")
|
|
134
|
+
|
|
135
|
+
# Build definition with possible asset_dir-relative paths
|
|
136
|
+
return BidiComponentDefinition(
|
|
137
|
+
name=component_key,
|
|
138
|
+
html=html,
|
|
139
|
+
css=css_value,
|
|
140
|
+
js=js_value,
|
|
141
|
+
css_asset_relative_path=css_rel,
|
|
142
|
+
js_asset_relative_path=js_rel,
|
|
143
|
+
)
|