streamlit-data-editor-plus 0.1.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 +292 -0
- streamlit/__main__.py +20 -0
- streamlit/auth_util.py +583 -0
- streamlit/cli_util.py +107 -0
- streamlit/column_config.py +60 -0
- streamlit/commands/__init__.py +13 -0
- streamlit/commands/echo.py +128 -0
- streamlit/commands/execution_control.py +318 -0
- streamlit/commands/logo.py +250 -0
- streamlit/commands/navigation.py +430 -0
- streamlit/commands/page_config.py +335 -0
- streamlit/components/__init__.py +13 -0
- streamlit/components/lib/__init__.py +13 -0
- streamlit/components/lib/local_component_registry.py +84 -0
- streamlit/components/types/__init__.py +13 -0
- streamlit/components/types/base_component_registry.py +99 -0
- streamlit/components/types/base_custom_component.py +158 -0
- streamlit/components/v1/__init__.py +29 -0
- streamlit/components/v1/component_arrow.py +141 -0
- streamlit/components/v1/component_registry.py +147 -0
- streamlit/components/v1/components.py +38 -0
- streamlit/components/v1/custom_component.py +239 -0
- streamlit/components/v2/__init__.py +531 -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 +537 -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 +233 -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 +620 -0
- streamlit/components/v2/presentation.py +198 -0
- streamlit/components/v2/types.py +317 -0
- streamlit/config.py +2977 -0
- streamlit/config_option.py +319 -0
- streamlit/config_util.py +887 -0
- streamlit/connections/__init__.py +32 -0
- streamlit/connections/base_connection.py +215 -0
- streamlit/connections/snowflake_connection.py +765 -0
- streamlit/connections/snowpark_connection.py +213 -0
- streamlit/connections/sql_connection.py +427 -0
- streamlit/connections/util.py +97 -0
- streamlit/cursor.py +314 -0
- streamlit/dataframe_util.py +1434 -0
- streamlit/delta_generator.py +696 -0
- streamlit/delta_generator_singletons.py +243 -0
- streamlit/deprecation_util.py +253 -0
- streamlit/development.py +21 -0
- streamlit/elements/__init__.py +13 -0
- streamlit/elements/alert.py +341 -0
- streamlit/elements/arrow.py +1065 -0
- streamlit/elements/balloons.py +47 -0
- streamlit/elements/bokeh_chart.py +75 -0
- streamlit/elements/code.py +154 -0
- streamlit/elements/deck_gl_json_chart.py +627 -0
- streamlit/elements/dialog_decorator.py +320 -0
- streamlit/elements/empty.py +130 -0
- streamlit/elements/exception.py +370 -0
- streamlit/elements/form.py +481 -0
- streamlit/elements/graphviz_chart.py +226 -0
- streamlit/elements/heading.py +407 -0
- streamlit/elements/help.py +565 -0
- streamlit/elements/html.py +189 -0
- streamlit/elements/iframe.py +245 -0
- streamlit/elements/image.py +221 -0
- streamlit/elements/json.py +171 -0
- streamlit/elements/layouts.py +1534 -0
- streamlit/elements/lib/__init__.py +13 -0
- streamlit/elements/lib/built_in_chart_utils.py +1316 -0
- streamlit/elements/lib/color_util.py +272 -0
- streamlit/elements/lib/column_config_utils.py +555 -0
- streamlit/elements/lib/column_types.py +2699 -0
- streamlit/elements/lib/dialog.py +212 -0
- streamlit/elements/lib/dicttools.py +152 -0
- streamlit/elements/lib/file_uploader_utils.py +91 -0
- streamlit/elements/lib/form_utils.py +77 -0
- streamlit/elements/lib/image_utils.py +447 -0
- streamlit/elements/lib/js_number.py +105 -0
- streamlit/elements/lib/layout_utils.py +325 -0
- streamlit/elements/lib/mutable_expander_container.py +73 -0
- streamlit/elements/lib/mutable_popover_container.py +73 -0
- streamlit/elements/lib/mutable_status_container.py +194 -0
- streamlit/elements/lib/mutable_tab_container.py +73 -0
- streamlit/elements/lib/options_selector_utils.py +480 -0
- streamlit/elements/lib/pandas_styler_utils.py +302 -0
- streamlit/elements/lib/policies.py +198 -0
- streamlit/elements/lib/shortcut_utils.py +152 -0
- streamlit/elements/lib/streamlit_plotly_theme.py +206 -0
- streamlit/elements/lib/subtitle_utils.py +175 -0
- streamlit/elements/lib/utils.py +274 -0
- streamlit/elements/map.py +526 -0
- streamlit/elements/markdown.py +529 -0
- streamlit/elements/media.py +843 -0
- streamlit/elements/metric.py +529 -0
- streamlit/elements/pdf.py +190 -0
- streamlit/elements/plotly_chart.py +779 -0
- streamlit/elements/progress.py +172 -0
- streamlit/elements/pyplot.py +240 -0
- streamlit/elements/snow.py +47 -0
- streamlit/elements/space.py +121 -0
- streamlit/elements/spinner.py +152 -0
- streamlit/elements/table.py +240 -0
- streamlit/elements/text.py +113 -0
- streamlit/elements/toast.py +175 -0
- streamlit/elements/vega_charts.py +2510 -0
- streamlit/elements/widgets/__init__.py +13 -0
- streamlit/elements/widgets/audio_input.py +334 -0
- streamlit/elements/widgets/button.py +1559 -0
- streamlit/elements/widgets/button_group.py +1061 -0
- streamlit/elements/widgets/camera_input.py +281 -0
- streamlit/elements/widgets/chat.py +1028 -0
- streamlit/elements/widgets/checkbox.py +420 -0
- streamlit/elements/widgets/color_picker.py +329 -0
- streamlit/elements/widgets/data_editor.py +1168 -0
- streamlit/elements/widgets/data_editor_plus.py +902 -0
- streamlit/elements/widgets/feedback.py +322 -0
- streamlit/elements/widgets/file_uploader.py +592 -0
- streamlit/elements/widgets/multiselect.py +654 -0
- streamlit/elements/widgets/number_input.py +719 -0
- streamlit/elements/widgets/radio.py +551 -0
- streamlit/elements/widgets/select_slider.py +568 -0
- streamlit/elements/widgets/selectbox.py +680 -0
- streamlit/elements/widgets/slider.py +1093 -0
- streamlit/elements/widgets/text_widgets.py +779 -0
- streamlit/elements/widgets/time_widgets.py +1712 -0
- streamlit/elements/write.py +585 -0
- streamlit/emojis.py +34 -0
- streamlit/env_util.py +56 -0
- streamlit/error_util.py +112 -0
- streamlit/errors.py +680 -0
- streamlit/external/__init__.py +13 -0
- streamlit/external/langchain/__init__.py +23 -0
- streamlit/external/langchain/streamlit_callback_handler.py +410 -0
- streamlit/file_util.py +266 -0
- streamlit/git_util.py +200 -0
- streamlit/hello/__init__.py +13 -0
- streamlit/hello/__pycache__/__init__.cpython-312.pyc +0 -0
- streamlit/hello/__pycache__/streamlit_app.cpython-312.pyc +0 -0
- streamlit/hello/animation_demo.py +82 -0
- streamlit/hello/dataframe_demo.py +71 -0
- streamlit/hello/hello.py +46 -0
- streamlit/hello/mapping_demo.py +113 -0
- streamlit/hello/plotting_demo.py +62 -0
- streamlit/hello/streamlit_app.py +57 -0
- streamlit/hello/utils.py +30 -0
- streamlit/logger.py +129 -0
- streamlit/material_icon_names.py +25 -0
- streamlit/navigation/__init__.py +13 -0
- streamlit/navigation/page.py +365 -0
- streamlit/net_util.py +125 -0
- streamlit/path_security.py +98 -0
- streamlit/platform.py +31 -0
- streamlit/proto/Alert_pb2.py +28 -0
- streamlit/proto/Alert_pb2.pyi +100 -0
- streamlit/proto/AppPage_pb2.py +25 -0
- streamlit/proto/AppPage_pb2.pyi +75 -0
- streamlit/proto/ArrowData_pb2.py +27 -0
- streamlit/proto/ArrowData_pb2.pyi +103 -0
- streamlit/proto/ArrowNamedDataSet_pb2.py +26 -0
- streamlit/proto/ArrowNamedDataSet_pb2.pyi +65 -0
- streamlit/proto/AudioInput_pb2.py +26 -0
- streamlit/proto/AudioInput_pb2.pyi +72 -0
- streamlit/proto/Audio_pb2.py +26 -0
- streamlit/proto/Audio_pb2.pyi +75 -0
- streamlit/proto/AuthRedirect_pb2.py +25 -0
- streamlit/proto/AuthRedirect_pb2.pyi +48 -0
- streamlit/proto/AutoRerun_pb2.py +25 -0
- streamlit/proto/AutoRerun_pb2.pyi +52 -0
- streamlit/proto/BackMsg_pb2.py +29 -0
- streamlit/proto/BackMsg_pb2.pyi +132 -0
- streamlit/proto/Balloons_pb2.py +25 -0
- streamlit/proto/Balloons_pb2.pyi +48 -0
- streamlit/proto/BidiComponent_pb2.py +32 -0
- streamlit/proto/BidiComponent_pb2.pyi +176 -0
- streamlit/proto/Block_pb2.py +62 -0
- streamlit/proto/Block_pb2.pyi +518 -0
- streamlit/proto/ButtonGroup_pb2.py +32 -0
- streamlit/proto/ButtonGroup_pb2.pyi +157 -0
- streamlit/proto/ButtonLikeIconPosition_pb2.py +25 -0
- streamlit/proto/ButtonLikeIconPosition_pb2.pyi +47 -0
- streamlit/proto/Button_pb2.py +26 -0
- streamlit/proto/Button_pb2.pyi +82 -0
- streamlit/proto/CameraInput_pb2.py +26 -0
- streamlit/proto/CameraInput_pb2.pyi +66 -0
- streamlit/proto/ChatInput_pb2.py +27 -0
- streamlit/proto/ChatInput_pb2.pyi +113 -0
- streamlit/proto/Checkbox_pb2.py +28 -0
- streamlit/proto/Checkbox_pb2.pyi +99 -0
- streamlit/proto/ClientState_pb2.py +28 -0
- streamlit/proto/ClientState_pb2.pyi +137 -0
- streamlit/proto/Code_pb2.py +25 -0
- streamlit/proto/Code_pb2.pyi +59 -0
- streamlit/proto/ColorPicker_pb2.py +26 -0
- streamlit/proto/ColorPicker_pb2.pyi +82 -0
- streamlit/proto/Common_pb2.py +49 -0
- streamlit/proto/Common_pb2.pyi +325 -0
- streamlit/proto/Components_pb2.py +33 -0
- streamlit/proto/Components_pb2.pyi +196 -0
- streamlit/proto/Dataframe_pb2.py +30 -0
- streamlit/proto/Dataframe_pb2.pyi +172 -0
- streamlit/proto/DateInput_pb2.py +26 -0
- streamlit/proto/DateInput_pb2.pyi +91 -0
- streamlit/proto/DateTimeInput_pb2.py +26 -0
- streamlit/proto/DateTimeInput_pb2.pyi +94 -0
- streamlit/proto/DeckGlJsonChart_pb2.py +27 -0
- streamlit/proto/DeckGlJsonChart_pb2.pyi +91 -0
- streamlit/proto/Delta_pb2.py +29 -0
- streamlit/proto/Delta_pb2.pyi +82 -0
- streamlit/proto/DownloadButton_pb2.py +26 -0
- streamlit/proto/DownloadButton_pb2.pyi +92 -0
- streamlit/proto/Element_pb2.py +81 -0
- streamlit/proto/Element_pb2.pyi +348 -0
- streamlit/proto/Empty_pb2.py +25 -0
- streamlit/proto/Empty_pb2.pyi +42 -0
- streamlit/proto/Exception_pb2.py +26 -0
- streamlit/proto/Exception_pb2.pyi +88 -0
- streamlit/proto/Favicon_pb2.py +25 -0
- streamlit/proto/Favicon_pb2.pyi +47 -0
- streamlit/proto/Feedback_pb2.py +27 -0
- streamlit/proto/Feedback_pb2.pyi +93 -0
- streamlit/proto/FileUploader_pb2.py +26 -0
- streamlit/proto/FileUploader_pb2.pyi +90 -0
- streamlit/proto/ForwardMsg_pb2.py +48 -0
- streamlit/proto/ForwardMsg_pb2.pyi +296 -0
- streamlit/proto/GapSize_pb2.py +27 -0
- streamlit/proto/GapSize_pb2.pyi +82 -0
- streamlit/proto/GitInfo_pb2.py +27 -0
- streamlit/proto/GitInfo_pb2.pyi +84 -0
- streamlit/proto/GraphVizChart_pb2.py +25 -0
- streamlit/proto/GraphVizChart_pb2.pyi +56 -0
- streamlit/proto/Heading_pb2.py +25 -0
- streamlit/proto/Heading_pb2.pyi +63 -0
- streamlit/proto/HeightConfig_pb2.py +25 -0
- streamlit/proto/HeightConfig_pb2.pyi +61 -0
- streamlit/proto/Help_pb2.py +27 -0
- streamlit/proto/Help_pb2.pyi +104 -0
- streamlit/proto/Html_pb2.py +25 -0
- streamlit/proto/Html_pb2.pyi +52 -0
- streamlit/proto/IFrame_pb2.py +25 -0
- streamlit/proto/IFrame_pb2.pyi +68 -0
- streamlit/proto/Image_pb2.py +27 -0
- streamlit/proto/Image_pb2.pyi +73 -0
- streamlit/proto/Json_pb2.py +25 -0
- streamlit/proto/Json_pb2.pyi +63 -0
- streamlit/proto/LabelVisibility_pb2.py +27 -0
- streamlit/proto/LabelVisibility_pb2.pyi +69 -0
- streamlit/proto/LinkButton_pb2.py +26 -0
- streamlit/proto/LinkButton_pb2.pyi +76 -0
- streamlit/proto/Logo_pb2.py +27 -0
- streamlit/proto/Logo_pb2.pyi +82 -0
- streamlit/proto/Markdown_pb2.py +27 -0
- streamlit/proto/Markdown_pb2.pyi +83 -0
- streamlit/proto/Metric_pb2.py +32 -0
- streamlit/proto/Metric_pb2.pyi +145 -0
- streamlit/proto/MetricsEvent_pb2.py +28 -0
- streamlit/proto/MetricsEvent_pb2.pyi +224 -0
- streamlit/proto/MultiSelect_pb2.py +26 -0
- streamlit/proto/MultiSelect_pb2.pyi +108 -0
- streamlit/proto/Navigation_pb2.py +28 -0
- streamlit/proto/Navigation_pb2.pyi +89 -0
- streamlit/proto/NewSession_pb2.py +47 -0
- streamlit/proto/NewSession_pb2.pyi +753 -0
- streamlit/proto/NumberInput_pb2.py +28 -0
- streamlit/proto/NumberInput_pb2.pyi +138 -0
- streamlit/proto/PageConfig_pb2.py +33 -0
- streamlit/proto/PageConfig_pb2.pyi +179 -0
- streamlit/proto/PageInfo_pb2.py +25 -0
- streamlit/proto/PageInfo_pb2.pyi +50 -0
- streamlit/proto/PageLink_pb2.py +26 -0
- streamlit/proto/PageLink_pb2.pyi +80 -0
- streamlit/proto/PageNotFound_pb2.py +25 -0
- streamlit/proto/PageNotFound_pb2.pyi +49 -0
- streamlit/proto/PageProfile_pb2.py +29 -0
- streamlit/proto/PageProfile_pb2.pyi +146 -0
- streamlit/proto/ParentMessage_pb2.py +25 -0
- streamlit/proto/ParentMessage_pb2.pyi +53 -0
- streamlit/proto/PlotlyChart_pb2.py +27 -0
- streamlit/proto/PlotlyChart_pb2.pyi +96 -0
- streamlit/proto/Progress_pb2.py +25 -0
- streamlit/proto/Progress_pb2.pyi +50 -0
- streamlit/proto/Radio_pb2.py +26 -0
- streamlit/proto/Radio_pb2.pyi +104 -0
- streamlit/proto/RootContainer_pb2.py +25 -0
- streamlit/proto/RootContainer_pb2.pyi +56 -0
- streamlit/proto/Selectbox_pb2.py +26 -0
- streamlit/proto/Selectbox_pb2.pyi +107 -0
- streamlit/proto/SessionEvent_pb2.py +26 -0
- streamlit/proto/SessionEvent_pb2.pyi +72 -0
- streamlit/proto/SessionStatus_pb2.py +25 -0
- streamlit/proto/SessionStatus_pb2.pyi +64 -0
- streamlit/proto/Skeleton_pb2.py +27 -0
- streamlit/proto/Skeleton_pb2.pyi +75 -0
- streamlit/proto/Slider_pb2.py +30 -0
- streamlit/proto/Slider_pb2.pyi +161 -0
- streamlit/proto/Snow_pb2.py +25 -0
- streamlit/proto/Snow_pb2.pyi +48 -0
- streamlit/proto/Space_pb2.py +25 -0
- streamlit/proto/Space_pb2.pyi +48 -0
- streamlit/proto/Spinner_pb2.py +25 -0
- streamlit/proto/Spinner_pb2.pyi +56 -0
- streamlit/proto/Table_pb2.py +28 -0
- streamlit/proto/Table_pb2.pyi +83 -0
- streamlit/proto/TextAlignmentConfig_pb2.py +27 -0
- streamlit/proto/TextAlignmentConfig_pb2.pyi +69 -0
- streamlit/proto/TextArea_pb2.py +26 -0
- streamlit/proto/TextArea_pb2.pyi +97 -0
- streamlit/proto/TextInput_pb2.py +28 -0
- streamlit/proto/TextInput_pb2.pyi +124 -0
- streamlit/proto/Text_pb2.py +25 -0
- streamlit/proto/Text_pb2.pyi +53 -0
- streamlit/proto/TimeInput_pb2.py +26 -0
- streamlit/proto/TimeInput_pb2.pyi +86 -0
- streamlit/proto/Toast_pb2.py +25 -0
- streamlit/proto/Toast_pb2.pyi +64 -0
- streamlit/proto/Transient_pb2.py +26 -0
- streamlit/proto/Transient_pb2.pyi +53 -0
- streamlit/proto/VegaLiteChart_pb2.py +27 -0
- streamlit/proto/VegaLiteChart_pb2.pyi +92 -0
- streamlit/proto/Video_pb2.py +30 -0
- streamlit/proto/Video_pb2.pyi +129 -0
- streamlit/proto/WidgetStates_pb2.py +31 -0
- streamlit/proto/WidgetStates_pb2.pyi +157 -0
- streamlit/proto/WidthConfig_pb2.py +25 -0
- streamlit/proto/WidthConfig_pb2.pyi +61 -0
- streamlit/proto/__init__.py +15 -0
- streamlit/proto/openmetrics_data_model_pb2.py +58 -0
- streamlit/proto/openmetrics_data_model_pb2.pyi +558 -0
- streamlit/py.typed +0 -0
- streamlit/runtime/__init__.py +50 -0
- streamlit/runtime/app_session.py +1302 -0
- streamlit/runtime/caching/__init__.py +118 -0
- streamlit/runtime/caching/cache_data_api.py +775 -0
- streamlit/runtime/caching/cache_errors.py +143 -0
- streamlit/runtime/caching/cache_resource_api.py +756 -0
- streamlit/runtime/caching/cache_type.py +33 -0
- streamlit/runtime/caching/cache_utils.py +601 -0
- streamlit/runtime/caching/cached_message_replay.py +290 -0
- streamlit/runtime/caching/hashing.py +655 -0
- streamlit/runtime/caching/legacy_cache_api.py +170 -0
- streamlit/runtime/caching/storage/__init__.py +29 -0
- streamlit/runtime/caching/storage/cache_storage_protocol.py +236 -0
- streamlit/runtime/caching/storage/dummy_cache_storage.py +60 -0
- streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +159 -0
- streamlit/runtime/caching/storage/local_disk_cache_storage.py +223 -0
- streamlit/runtime/caching/ttl_cleanup_cache.py +85 -0
- streamlit/runtime/connection_factory.py +498 -0
- streamlit/runtime/context.py +449 -0
- streamlit/runtime/context_util.py +49 -0
- streamlit/runtime/credentials.py +355 -0
- streamlit/runtime/download_data_util.py +53 -0
- streamlit/runtime/forward_msg_cache.py +101 -0
- streamlit/runtime/forward_msg_queue.py +263 -0
- streamlit/runtime/fragment.py +441 -0
- streamlit/runtime/media_file_manager.py +409 -0
- streamlit/runtime/media_file_storage.py +143 -0
- streamlit/runtime/memory_media_file_storage.py +201 -0
- streamlit/runtime/memory_session_storage.py +77 -0
- streamlit/runtime/memory_uploaded_file_manager.py +149 -0
- streamlit/runtime/metrics_util.py +612 -0
- streamlit/runtime/pages_manager.py +160 -0
- streamlit/runtime/runtime.py +775 -0
- streamlit/runtime/runtime_util.py +108 -0
- streamlit/runtime/script_data.py +46 -0
- streamlit/runtime/scriptrunner/__init__.py +38 -0
- streamlit/runtime/scriptrunner/exec_code.py +167 -0
- streamlit/runtime/scriptrunner/magic.py +277 -0
- streamlit/runtime/scriptrunner/magic_funcs.py +32 -0
- streamlit/runtime/scriptrunner/script_cache.py +89 -0
- streamlit/runtime/scriptrunner/script_runner.py +805 -0
- streamlit/runtime/scriptrunner_utils/__init__.py +19 -0
- streamlit/runtime/scriptrunner_utils/exceptions.py +44 -0
- streamlit/runtime/scriptrunner_utils/script_requests.py +311 -0
- streamlit/runtime/scriptrunner_utils/script_run_context.py +277 -0
- streamlit/runtime/secrets.py +533 -0
- streamlit/runtime/session_manager.py +430 -0
- streamlit/runtime/state/__init__.py +47 -0
- streamlit/runtime/state/common.py +256 -0
- streamlit/runtime/state/presentation.py +85 -0
- streamlit/runtime/state/query_params.py +767 -0
- streamlit/runtime/state/query_params_proxy.py +222 -0
- streamlit/runtime/state/safe_session_state.py +146 -0
- streamlit/runtime/state/session_state.py +1299 -0
- streamlit/runtime/state/session_state_proxy.py +153 -0
- streamlit/runtime/state/widgets.py +197 -0
- streamlit/runtime/stats.py +356 -0
- streamlit/runtime/theme_util.py +148 -0
- streamlit/runtime/uploaded_file_manager.py +152 -0
- streamlit/runtime/websocket_session_manager.py +301 -0
- streamlit/source_util.py +97 -0
- streamlit/starlette.py +34 -0
- streamlit/string_util.py +264 -0
- streamlit/temporary_directory.py +67 -0
- streamlit/testing/__init__.py +13 -0
- streamlit/testing/v1/__init__.py +17 -0
- streamlit/testing/v1/app_test.py +1089 -0
- streamlit/testing/v1/element_tree.py +2272 -0
- streamlit/testing/v1/local_script_runner.py +176 -0
- streamlit/testing/v1/util.py +61 -0
- streamlit/time_util.py +73 -0
- streamlit/type_util.py +480 -0
- streamlit/url_util.py +120 -0
- streamlit/user_info.py +698 -0
- streamlit/util.py +108 -0
- streamlit/vendor/__init__.py +0 -0
- streamlit/vendor/pympler/__init__.py +0 -0
- streamlit/vendor/pympler/asizeof.py +2870 -0
- streamlit/version.py +18 -0
- streamlit/watcher/__init__.py +28 -0
- streamlit/watcher/event_based_path_watcher.py +500 -0
- streamlit/watcher/folder_black_list.py +82 -0
- streamlit/watcher/local_sources_watcher.py +297 -0
- streamlit/watcher/path_watcher.py +244 -0
- streamlit/watcher/polling_path_watcher.py +138 -0
- streamlit/watcher/util.py +223 -0
- streamlit/web/__init__.py +13 -0
- streamlit/web/bootstrap.py +463 -0
- streamlit/web/cache_storage_manager_config.py +38 -0
- streamlit/web/cli.py +465 -0
- streamlit/web/server/__init__.py +30 -0
- streamlit/web/server/app_discovery.py +422 -0
- streamlit/web/server/app_static_file_handler.py +102 -0
- streamlit/web/server/authlib_tornado_integration.py +125 -0
- streamlit/web/server/bidi_component_request_handler.py +193 -0
- streamlit/web/server/browser_websocket_handler.py +341 -0
- streamlit/web/server/component_file_utils.py +105 -0
- streamlit/web/server/component_request_handler.py +107 -0
- streamlit/web/server/media_file_handler.py +148 -0
- streamlit/web/server/oauth_authlib_routes.py +314 -0
- streamlit/web/server/oidc_mixin.py +138 -0
- streamlit/web/server/routes.py +257 -0
- streamlit/web/server/server.py +555 -0
- streamlit/web/server/server_util.py +235 -0
- streamlit/web/server/starlette/__init__.py +23 -0
- streamlit/web/server/starlette/starlette_app.py +541 -0
- streamlit/web/server/starlette/starlette_app_utils.py +306 -0
- streamlit/web/server/starlette/starlette_auth_routes.py +584 -0
- streamlit/web/server/starlette/starlette_gzip_middleware.py +121 -0
- streamlit/web/server/starlette/starlette_path_security_middleware.py +97 -0
- streamlit/web/server/starlette/starlette_routes.py +884 -0
- streamlit/web/server/starlette/starlette_server.py +496 -0
- streamlit/web/server/starlette/starlette_server_config.py +55 -0
- streamlit/web/server/starlette/starlette_static_routes.py +181 -0
- streamlit/web/server/starlette/starlette_websocket.py +560 -0
- streamlit/web/server/stats_request_handler.py +116 -0
- streamlit/web/server/upload_file_request_handler.py +158 -0
- streamlit/web/server/websocket_headers.py +56 -0
- streamlit_data_editor_plus-0.1.0.dist-info/METADATA +76 -0
- streamlit_data_editor_plus-0.1.0.dist-info/RECORD +456 -0
- streamlit_data_editor_plus-0.1.0.dist-info/WHEEL +5 -0
- streamlit_data_editor_plus-0.1.0.dist-info/entry_points.txt +2 -0
- streamlit_data_editor_plus-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
|
|
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 itertools
|
|
18
|
+
from typing import TYPE_CHECKING, Final, NamedTuple, Protocol, runtime_checkable
|
|
19
|
+
|
|
20
|
+
CACHE_MEMORY_FAMILY: Final = "cache_memory_bytes"
|
|
21
|
+
SESSION_EVENTS_FAMILY: Final = "session_events_total"
|
|
22
|
+
SESSION_DURATION_FAMILY: Final = "session_duration_seconds_total"
|
|
23
|
+
ACTIVE_SESSIONS_FAMILY: Final = "active_sessions"
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from collections.abc import Mapping, Sequence
|
|
27
|
+
|
|
28
|
+
from streamlit.proto.openmetrics_data_model_pb2 import (
|
|
29
|
+
Metric as MetricProto,
|
|
30
|
+
)
|
|
31
|
+
from streamlit.proto.openmetrics_data_model_pb2 import (
|
|
32
|
+
MetricType,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@runtime_checkable
|
|
37
|
+
class Stat(Protocol):
|
|
38
|
+
"""Protocol for a stat that can be serialized to OpenMetrics format.
|
|
39
|
+
|
|
40
|
+
All stats must have these fields to identify the metric family they belong to
|
|
41
|
+
and provide metadata for OpenMetrics serialization.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def family_name(self) -> str:
|
|
46
|
+
"""The name of the metric family (e.g. 'cache_memory_bytes')."""
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def type(self) -> str:
|
|
50
|
+
"""The OpenMetrics type (e.g. 'gauge', 'counter')."""
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def unit(self) -> str:
|
|
54
|
+
"""The unit of the metric (e.g. 'bytes')."""
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def help(self) -> str:
|
|
58
|
+
"""A description of the metric."""
|
|
59
|
+
|
|
60
|
+
def to_metric_str(self) -> str:
|
|
61
|
+
"""Convert this stat to an OpenMetrics-formatted string."""
|
|
62
|
+
|
|
63
|
+
def marshall_metric_proto(self, metric: MetricProto) -> None:
|
|
64
|
+
"""Fill an OpenMetrics `Metric` protobuf object."""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# TODO(vdonato): Could we use GaugeStat below and get rid of this class?
|
|
68
|
+
# We'd have to make some minor changes to use the other class, but overall the
|
|
69
|
+
# changes should be relatively minor.
|
|
70
|
+
class CacheStat(NamedTuple):
|
|
71
|
+
"""Describes a single cache entry.
|
|
72
|
+
|
|
73
|
+
Properties
|
|
74
|
+
----------
|
|
75
|
+
category_name : str
|
|
76
|
+
A human-readable name for the cache "category" that the entry belongs
|
|
77
|
+
to - e.g. "st.memo", "session_state", etc.
|
|
78
|
+
cache_name : str
|
|
79
|
+
A human-readable name for cache instance that the entry belongs to.
|
|
80
|
+
For "st.memo" and other function decorator caches, this might be the
|
|
81
|
+
name of the cached function. If the cache category doesn't have
|
|
82
|
+
multiple separate cache instances, this can just be the empty string.
|
|
83
|
+
byte_length : int
|
|
84
|
+
The entry's memory footprint in bytes.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
category_name: str
|
|
88
|
+
cache_name: str
|
|
89
|
+
byte_length: int
|
|
90
|
+
|
|
91
|
+
# Stat Protocol fields with default values for cache metrics
|
|
92
|
+
@property
|
|
93
|
+
def family_name(self) -> str:
|
|
94
|
+
return CACHE_MEMORY_FAMILY
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def type(self) -> str:
|
|
98
|
+
return "gauge"
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def unit(self) -> str:
|
|
102
|
+
return "bytes"
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def help(self) -> str:
|
|
106
|
+
return "Total memory consumed by a cache."
|
|
107
|
+
|
|
108
|
+
def to_metric_str(self) -> str:
|
|
109
|
+
return f'{self.family_name}{{cache_type="{self.category_name}",cache="{self.cache_name}"}} {self.byte_length}'
|
|
110
|
+
|
|
111
|
+
def marshall_metric_proto(self, metric: MetricProto) -> None:
|
|
112
|
+
"""Fill an OpenMetrics `Metric` protobuf object."""
|
|
113
|
+
label = metric.labels.add()
|
|
114
|
+
label.name = "cache_type"
|
|
115
|
+
label.value = self.category_name
|
|
116
|
+
|
|
117
|
+
label = metric.labels.add()
|
|
118
|
+
label.name = "cache"
|
|
119
|
+
label.value = self.cache_name
|
|
120
|
+
|
|
121
|
+
metric_point = metric.metric_points.add()
|
|
122
|
+
metric_point.gauge_value.int_value = self.byte_length
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def group_cache_stats(stats: list[CacheStat]) -> list[CacheStat]:
|
|
126
|
+
"""Group a list of CacheStats by category_name and cache_name and sum byte_length."""
|
|
127
|
+
|
|
128
|
+
def key_function(individual_stat: CacheStat) -> tuple[str, str]:
|
|
129
|
+
return individual_stat.category_name, individual_stat.cache_name
|
|
130
|
+
|
|
131
|
+
result: list[CacheStat] = []
|
|
132
|
+
|
|
133
|
+
sorted_stats = sorted(stats, key=key_function)
|
|
134
|
+
grouped_stats = itertools.groupby(sorted_stats, key=key_function)
|
|
135
|
+
|
|
136
|
+
for (category_name, cache_name), single_group_stats in grouped_stats:
|
|
137
|
+
result.append(
|
|
138
|
+
CacheStat(
|
|
139
|
+
category_name=category_name,
|
|
140
|
+
cache_name=cache_name,
|
|
141
|
+
byte_length=sum(item.byte_length for item in single_group_stats),
|
|
142
|
+
)
|
|
143
|
+
)
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class CounterStat(NamedTuple):
|
|
148
|
+
"""A counter stat.
|
|
149
|
+
|
|
150
|
+
Properties
|
|
151
|
+
----------
|
|
152
|
+
family_name : str
|
|
153
|
+
The name of the metric family (e.g. 'session_events_total').
|
|
154
|
+
value : int
|
|
155
|
+
The current count value.
|
|
156
|
+
labels : dict[str, str] | None
|
|
157
|
+
Labels to identify this specific counter (e.g. {"type": "connection"}).
|
|
158
|
+
unit : str
|
|
159
|
+
The unit of the metric (e.g. '' for unitless).
|
|
160
|
+
help : str
|
|
161
|
+
A description of the metric.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
family_name: str
|
|
165
|
+
value: int
|
|
166
|
+
labels: dict[str, str] | None = None
|
|
167
|
+
unit: str = ""
|
|
168
|
+
help: str = ""
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def type(self) -> str:
|
|
172
|
+
return "counter"
|
|
173
|
+
|
|
174
|
+
def to_metric_str(self) -> str:
|
|
175
|
+
if self.labels:
|
|
176
|
+
labels_str = ",".join(f'{k}="{v}"' for k, v in sorted(self.labels.items()))
|
|
177
|
+
return f"{self.family_name}{{{labels_str}}} {self.value}"
|
|
178
|
+
return f"{self.family_name} {self.value}"
|
|
179
|
+
|
|
180
|
+
def marshall_metric_proto(self, metric: MetricProto) -> None:
|
|
181
|
+
"""Fill an OpenMetrics `Metric` protobuf object."""
|
|
182
|
+
if self.labels:
|
|
183
|
+
for name, value in sorted(self.labels.items()):
|
|
184
|
+
label = metric.labels.add()
|
|
185
|
+
label.name = name
|
|
186
|
+
label.value = value
|
|
187
|
+
|
|
188
|
+
metric_point = metric.metric_points.add()
|
|
189
|
+
metric_point.counter_value.int_value = self.value
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class GaugeStat(NamedTuple):
|
|
193
|
+
"""A gauge stat.
|
|
194
|
+
|
|
195
|
+
Properties
|
|
196
|
+
----------
|
|
197
|
+
family_name : str
|
|
198
|
+
The name of the metric family (e.g. 'active_sessions').
|
|
199
|
+
value : int
|
|
200
|
+
The current gauge value.
|
|
201
|
+
labels : dict[str, str] | None
|
|
202
|
+
Optional labels to identify this specific gauge.
|
|
203
|
+
unit : str
|
|
204
|
+
The unit of the metric (e.g. '' for unitless).
|
|
205
|
+
help : str
|
|
206
|
+
A description of the metric.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
family_name: str
|
|
210
|
+
value: int
|
|
211
|
+
labels: dict[str, str] | None = None
|
|
212
|
+
unit: str = ""
|
|
213
|
+
help: str = ""
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def type(self) -> str:
|
|
217
|
+
return "gauge"
|
|
218
|
+
|
|
219
|
+
def to_metric_str(self) -> str:
|
|
220
|
+
if self.labels:
|
|
221
|
+
labels_str = ",".join(f'{k}="{v}"' for k, v in sorted(self.labels.items()))
|
|
222
|
+
return f"{self.family_name}{{{labels_str}}} {self.value}"
|
|
223
|
+
return f"{self.family_name} {self.value}"
|
|
224
|
+
|
|
225
|
+
def marshall_metric_proto(self, metric: MetricProto) -> None:
|
|
226
|
+
"""Fill an OpenMetrics `Metric` protobuf object."""
|
|
227
|
+
if self.labels:
|
|
228
|
+
for name, value in sorted(self.labels.items()):
|
|
229
|
+
label = metric.labels.add()
|
|
230
|
+
label.name = name
|
|
231
|
+
label.value = value
|
|
232
|
+
|
|
233
|
+
metric_point = metric.metric_points.add()
|
|
234
|
+
metric_point.gauge_value.int_value = self.value
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def metric_type_string_to_proto(type_string: str) -> MetricType.ValueType:
|
|
238
|
+
"""Convert a metric type string to its corresponding proto enum value."""
|
|
239
|
+
from streamlit.proto.openmetrics_data_model_pb2 import (
|
|
240
|
+
COUNTER,
|
|
241
|
+
GAUGE,
|
|
242
|
+
GAUGE_HISTOGRAM,
|
|
243
|
+
HISTOGRAM,
|
|
244
|
+
INFO,
|
|
245
|
+
STATE_SET,
|
|
246
|
+
SUMMARY,
|
|
247
|
+
UNKNOWN,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
type_map = {
|
|
251
|
+
"gauge": GAUGE,
|
|
252
|
+
"counter": COUNTER,
|
|
253
|
+
"state_set": STATE_SET,
|
|
254
|
+
"info": INFO,
|
|
255
|
+
"histogram": HISTOGRAM,
|
|
256
|
+
"gauge_histogram": GAUGE_HISTOGRAM,
|
|
257
|
+
"summary": SUMMARY,
|
|
258
|
+
}
|
|
259
|
+
return type_map.get(type_string, UNKNOWN)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
@runtime_checkable
|
|
263
|
+
class StatsProvider(Protocol):
|
|
264
|
+
@property
|
|
265
|
+
def stats_families(self) -> Sequence[str]:
|
|
266
|
+
"""The metric family names that this provider supports.
|
|
267
|
+
|
|
268
|
+
The StatsManager uses this property to determine which providers to call
|
|
269
|
+
when specific metric families are requested.
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
def get_stats(
|
|
273
|
+
self, family_names: Sequence[str] | None = None
|
|
274
|
+
) -> Mapping[str, Sequence[Stat]]:
|
|
275
|
+
"""Return stats for the specified metric families.
|
|
276
|
+
|
|
277
|
+
Parameters
|
|
278
|
+
----------
|
|
279
|
+
family_names : Sequence[str] | None
|
|
280
|
+
If provided, only stats for these metric families should be computed
|
|
281
|
+
and returned. If None, stats for all families this provider supports
|
|
282
|
+
should be returned. Providers should check this parameter and skip
|
|
283
|
+
computing expensive stats for families that aren't requested.
|
|
284
|
+
|
|
285
|
+
Returns
|
|
286
|
+
-------
|
|
287
|
+
Mapping[str, Sequence[Stat]]
|
|
288
|
+
A mapping from metric family names to sequences of Stat objects.
|
|
289
|
+
"""
|
|
290
|
+
raise NotImplementedError
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class StatsManager:
|
|
294
|
+
def __init__(self) -> None:
|
|
295
|
+
self._providers_by_family: dict[str, list[StatsProvider]] = {}
|
|
296
|
+
|
|
297
|
+
def register_provider(self, provider: StatsProvider) -> None:
|
|
298
|
+
"""Register a StatsProvider with the manager.
|
|
299
|
+
|
|
300
|
+
This function is not thread-safe. Call it immediately after creation.
|
|
301
|
+
|
|
302
|
+
Parameters
|
|
303
|
+
----------
|
|
304
|
+
provider : StatsProvider
|
|
305
|
+
The stats provider to register. The provider's `stats_families`
|
|
306
|
+
property determines which metric families it will be called for.
|
|
307
|
+
"""
|
|
308
|
+
for family in provider.stats_families:
|
|
309
|
+
if family not in self._providers_by_family:
|
|
310
|
+
self._providers_by_family[family] = []
|
|
311
|
+
self._providers_by_family[family].append(provider)
|
|
312
|
+
|
|
313
|
+
def get_stats(
|
|
314
|
+
self, family_names: Sequence[str] | None = None
|
|
315
|
+
) -> Mapping[str, Sequence[Stat]]:
|
|
316
|
+
"""Return registered stats grouped by metric family name.
|
|
317
|
+
|
|
318
|
+
Parameters
|
|
319
|
+
----------
|
|
320
|
+
family_names : Sequence[str] | None
|
|
321
|
+
If provided, only stats for these metric families will be returned.
|
|
322
|
+
If None, stats for all registered families are returned.
|
|
323
|
+
|
|
324
|
+
Returns
|
|
325
|
+
-------
|
|
326
|
+
Mapping[str, Sequence[Stat]]
|
|
327
|
+
A mapping from metric family names to sequences of Stat objects
|
|
328
|
+
from all providers.
|
|
329
|
+
"""
|
|
330
|
+
result: dict[str, Sequence[Stat]] = {}
|
|
331
|
+
|
|
332
|
+
families_to_query = family_names or list(self._providers_by_family.keys())
|
|
333
|
+
|
|
334
|
+
# Track which providers we've already queried to avoid duplicates.
|
|
335
|
+
# The same provider may be registered for multiple families, and we call
|
|
336
|
+
# `provider.get_stats(family_names)` below to fetch all stat families for
|
|
337
|
+
# a given stats provider at once.
|
|
338
|
+
queried_providers: set[int] = set()
|
|
339
|
+
|
|
340
|
+
for family in families_to_query:
|
|
341
|
+
for provider in self._providers_by_family.get(family, []):
|
|
342
|
+
provider_id = id(provider)
|
|
343
|
+
if provider_id in queried_providers:
|
|
344
|
+
continue
|
|
345
|
+
queried_providers.add(provider_id)
|
|
346
|
+
|
|
347
|
+
provider_stats = provider.get_stats(family_names)
|
|
348
|
+
for fname, stats in provider_stats.items():
|
|
349
|
+
if fname not in result:
|
|
350
|
+
result[fname] = []
|
|
351
|
+
# Use list() to convert Sequence to list for concatenation.
|
|
352
|
+
# This is needed for type covariance: providers return
|
|
353
|
+
# Mapping[str, Sequence[Stat]] but we build a dict of lists.
|
|
354
|
+
result[fname] = list(result[fname]) + list(stats)
|
|
355
|
+
|
|
356
|
+
return result
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
|
|
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
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
from streamlit.errors import StreamlitAPIException
|
|
21
|
+
from streamlit.url_util import is_url
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from streamlit.proto.NewSession_pb2 import CustomThemeConfig
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _parse_font_config(
|
|
28
|
+
font_config: str | None,
|
|
29
|
+
property_name: str,
|
|
30
|
+
) -> tuple[str, str | None]:
|
|
31
|
+
"""Parse a single font configuration string.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
font_config: The font configuration string (e.g., "Inter" or "Inter:https://...")
|
|
35
|
+
property_name: The property name for error messages ("font", "codeFont", "headingFont")
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
A tuple of (font_name, source_url). source_url is None if not provided or not valid.
|
|
40
|
+
"""
|
|
41
|
+
if not font_config:
|
|
42
|
+
return "", None
|
|
43
|
+
|
|
44
|
+
# Strip leading/trailing whitespace from the config
|
|
45
|
+
font_config = font_config.strip()
|
|
46
|
+
|
|
47
|
+
if ":" not in font_config:
|
|
48
|
+
# No colon found, treat the entire string as the font name
|
|
49
|
+
return font_config, None
|
|
50
|
+
|
|
51
|
+
# Note: it is possible there are multiple colons in the string, so we need to split on the first colon.
|
|
52
|
+
font_name, source_url = font_config.split(":", 1)
|
|
53
|
+
# Strip whitespace from both font name and source
|
|
54
|
+
font_name = font_name.strip()
|
|
55
|
+
source_url = source_url.strip()
|
|
56
|
+
|
|
57
|
+
# Check that the href does not contain multiple fonts, so we confirm that "family="
|
|
58
|
+
# only shows up once in the source string (structure applies to Google Fonts only)
|
|
59
|
+
family_occurrences = source_url.count("family=")
|
|
60
|
+
if family_occurrences > 1:
|
|
61
|
+
raise StreamlitAPIException(
|
|
62
|
+
f"The source URL specified in the {property_name} property of config.toml contains multiple fonts. "
|
|
63
|
+
"Please specify only one font in the source URL."
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
is_valid_url = is_url(source_url)
|
|
67
|
+
|
|
68
|
+
# If the source is a valid URL (http/https) but no font name is provided, throw an exception
|
|
69
|
+
if is_valid_url and not font_name:
|
|
70
|
+
raise StreamlitAPIException(
|
|
71
|
+
f"A font family name is required when specifying a source URL "
|
|
72
|
+
f"for the {property_name} property in config.toml."
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
if is_valid_url:
|
|
76
|
+
return font_name, source_url
|
|
77
|
+
|
|
78
|
+
return font_name, None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _get_font_source_config_name(property_name: str, section: str) -> str:
|
|
82
|
+
"""Get the config name for font sources based on property and section. This is used on the FE
|
|
83
|
+
as the id for the font source link in the html head.
|
|
84
|
+
"""
|
|
85
|
+
if section == "theme":
|
|
86
|
+
return property_name
|
|
87
|
+
return f"{property_name}-sidebar"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def parse_fonts_with_source(
|
|
91
|
+
msg: CustomThemeConfig,
|
|
92
|
+
body_font_config: str | None,
|
|
93
|
+
code_font_config: str | None,
|
|
94
|
+
heading_font_config: str | None,
|
|
95
|
+
section: str,
|
|
96
|
+
) -> CustomThemeConfig:
|
|
97
|
+
"""Populate the CustomThemeConfig message with the font, codeFont, and headingFont fields set,
|
|
98
|
+
as well as the font_sources field to be added to the html head.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
msg: CustomThemeConfig message to be populated.
|
|
102
|
+
body_font_config: A string with just the font name (e.g., "Inter") or in the format
|
|
103
|
+
"<font_family_name_here>:<source_url_here>".
|
|
104
|
+
code_font_config: A string with just the font name (e.g., "Roboto Mono") or in the format
|
|
105
|
+
"<code_font_family_name_here>:<source_url_here>".
|
|
106
|
+
heading_font_config: A string with just the font name (e.g., "Inter Bold") or in the format
|
|
107
|
+
"<heading_font_family_name_here>:<source_url_here>".
|
|
108
|
+
section: The section of the config.toml file to parse the fonts from.
|
|
109
|
+
|
|
110
|
+
Examples
|
|
111
|
+
--------
|
|
112
|
+
body_font_config: "Inter" (just font name)
|
|
113
|
+
code_font_config: "Tagesschrift:https://fonts.googleapis.com/css2?family=Tagesschrift&display=swap" (with source)
|
|
114
|
+
heading_font_config: "playwrite-cc-za:https://use.typekit.net/xxs7euo.css"
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
Updated CustomThemeConfig message with the font, codeFont, and headingFont fields set.
|
|
119
|
+
Also sets sources in font_sources field to be added to the html (only when source URLs are provided).
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
# Parse body font config
|
|
123
|
+
body_font_name, body_font_source = _parse_font_config(body_font_config, "font")
|
|
124
|
+
if body_font_name:
|
|
125
|
+
msg.body_font = body_font_name
|
|
126
|
+
if body_font_source:
|
|
127
|
+
config_name = _get_font_source_config_name("font", section)
|
|
128
|
+
msg.font_sources.add(config_name=config_name, source_url=body_font_source)
|
|
129
|
+
|
|
130
|
+
# Parse code font config
|
|
131
|
+
code_font_name, code_font_source = _parse_font_config(code_font_config, "codeFont")
|
|
132
|
+
if code_font_name:
|
|
133
|
+
msg.code_font = code_font_name
|
|
134
|
+
if code_font_source:
|
|
135
|
+
config_name = _get_font_source_config_name("codeFont", section)
|
|
136
|
+
msg.font_sources.add(config_name=config_name, source_url=code_font_source)
|
|
137
|
+
|
|
138
|
+
# Parse heading font config
|
|
139
|
+
heading_font_name, heading_font_source = _parse_font_config(
|
|
140
|
+
heading_font_config, "headingFont"
|
|
141
|
+
)
|
|
142
|
+
if heading_font_name:
|
|
143
|
+
msg.heading_font = heading_font_name
|
|
144
|
+
if heading_font_source:
|
|
145
|
+
config_name = _get_font_source_config_name("headingFont", section)
|
|
146
|
+
msg.font_sources.add(config_name=config_name, source_url=heading_font_source)
|
|
147
|
+
|
|
148
|
+
return msg
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
|
|
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 io
|
|
18
|
+
from abc import abstractmethod
|
|
19
|
+
from typing import TYPE_CHECKING, NamedTuple, Protocol
|
|
20
|
+
|
|
21
|
+
from streamlit import util
|
|
22
|
+
from streamlit.runtime.stats import StatsProvider
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from collections.abc import Sequence
|
|
26
|
+
|
|
27
|
+
from streamlit.proto.Common_pb2 import FileURLs as FileURLsProto
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class UploadedFileRec(NamedTuple):
|
|
31
|
+
"""Metadata and raw bytes for an uploaded file. Immutable."""
|
|
32
|
+
|
|
33
|
+
file_id: str
|
|
34
|
+
name: str
|
|
35
|
+
type: str
|
|
36
|
+
data: bytes
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class UploadFileUrlInfo(NamedTuple):
|
|
40
|
+
"""Information we provide for single file in get_upload_urls."""
|
|
41
|
+
|
|
42
|
+
file_id: str
|
|
43
|
+
upload_url: str
|
|
44
|
+
delete_url: str
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class DeletedFile(NamedTuple):
|
|
48
|
+
"""Represents a deleted file in deserialized values for st.file_uploader and
|
|
49
|
+
st.camera_input.
|
|
50
|
+
|
|
51
|
+
Return this from st.file_uploader and st.camera_input deserialize (so they can
|
|
52
|
+
be used in session_state), when widget value contains file record that is missing
|
|
53
|
+
from the storage.
|
|
54
|
+
DeleteFile instances filtered out before return final value to the user in script,
|
|
55
|
+
or before sending to frontend.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
file_id: str
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class UploadedFile(io.BytesIO):
|
|
62
|
+
"""A mutable uploaded file.
|
|
63
|
+
|
|
64
|
+
This class extends BytesIO, which has copy-on-write semantics when
|
|
65
|
+
initialized with `bytes`.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(self, record: UploadedFileRec, file_urls: FileURLsProto) -> None:
|
|
69
|
+
# BytesIO's copy-on-write semantics doesn't seem to be mentioned in
|
|
70
|
+
# the Python docs - possibly because it's a CPython-only optimization
|
|
71
|
+
# and not guaranteed to be in other Python runtimes. But it's detailed
|
|
72
|
+
# here: https://hg.python.org/cpython/rev/79a5fbe2c78f
|
|
73
|
+
super().__init__(record.data)
|
|
74
|
+
self.file_id = record.file_id
|
|
75
|
+
self.name = record.name
|
|
76
|
+
self.type = record.type
|
|
77
|
+
self.size = len(record.data)
|
|
78
|
+
self._file_urls = file_urls
|
|
79
|
+
|
|
80
|
+
def __eq__(self, other: object) -> bool:
|
|
81
|
+
if not isinstance(other, UploadedFile):
|
|
82
|
+
return NotImplemented
|
|
83
|
+
return self.file_id == other.file_id
|
|
84
|
+
|
|
85
|
+
def __hash__(self) -> int:
|
|
86
|
+
return hash(self.file_id)
|
|
87
|
+
|
|
88
|
+
def __repr__(self) -> str:
|
|
89
|
+
return util.repr_(self)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class UploadedFileManager(StatsProvider, Protocol):
|
|
93
|
+
"""UploadedFileManager protocol, that should be implemented by the concrete
|
|
94
|
+
uploaded file managers.
|
|
95
|
+
|
|
96
|
+
It is responsible for:
|
|
97
|
+
- retrieving files by session_id and file_id for st.file_uploader and
|
|
98
|
+
st.camera_input
|
|
99
|
+
- cleaning up uploaded files associated with session on session end
|
|
100
|
+
|
|
101
|
+
It should be created during Runtime initialization.
|
|
102
|
+
|
|
103
|
+
Optionally UploadedFileManager could be responsible for issuing URLs which will be
|
|
104
|
+
used by frontend to upload files to.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
@abstractmethod
|
|
108
|
+
def get_files(
|
|
109
|
+
self, session_id: str, file_ids: Sequence[str]
|
|
110
|
+
) -> list[UploadedFileRec]:
|
|
111
|
+
"""Return a list of UploadedFileRec for a given sequence of file_ids.
|
|
112
|
+
|
|
113
|
+
Parameters
|
|
114
|
+
----------
|
|
115
|
+
session_id
|
|
116
|
+
The ID of the session that owns the files.
|
|
117
|
+
file_ids
|
|
118
|
+
The sequence of ids associated with files to retrieve.
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
List[UploadedFileRec]
|
|
123
|
+
A list of URL UploadedFileRec instances, each instance contains information
|
|
124
|
+
about uploaded file.
|
|
125
|
+
"""
|
|
126
|
+
raise NotImplementedError
|
|
127
|
+
|
|
128
|
+
@abstractmethod
|
|
129
|
+
def remove_session_files(self, session_id: str) -> None:
|
|
130
|
+
"""Remove all files associated with a given session."""
|
|
131
|
+
raise NotImplementedError
|
|
132
|
+
|
|
133
|
+
def get_upload_urls(
|
|
134
|
+
self, session_id: str, file_names: Sequence[str]
|
|
135
|
+
) -> list[UploadFileUrlInfo]:
|
|
136
|
+
"""Return a list of UploadFileUrlInfo for a given sequence of file_names.
|
|
137
|
+
Optional to implement, issuing of URLs could be done by other service.
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
session_id
|
|
142
|
+
The ID of the session that request URLs.
|
|
143
|
+
file_names
|
|
144
|
+
The sequence of file names for which URLs are requested
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
List[UploadFileUrlInfo]
|
|
149
|
+
A list of UploadFileUrlInfo instances, each instance contains information
|
|
150
|
+
about uploaded file URLs.
|
|
151
|
+
"""
|
|
152
|
+
raise NotImplementedError
|