streamlit 1.45.1__py3-none-any.whl → 1.46.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- streamlit/__init__.py +5 -1
- streamlit/auth_util.py +12 -12
- streamlit/cli_util.py +4 -3
- streamlit/column_config.py +11 -9
- streamlit/commands/echo.py +6 -4
- streamlit/commands/execution_control.py +33 -32
- streamlit/commands/experimental_query_params.py +2 -2
- streamlit/commands/logo.py +9 -4
- streamlit/commands/navigation.py +61 -18
- streamlit/commands/page_config.py +57 -47
- streamlit/components/types/base_custom_component.py +7 -7
- streamlit/components/v1/component_registry.py +7 -3
- streamlit/components/v1/components.py +1 -1
- streamlit/components/v1/custom_component.py +8 -8
- streamlit/config.py +289 -144
- streamlit/config_option.py +19 -15
- streamlit/config_util.py +29 -23
- streamlit/connections/__init__.py +2 -2
- streamlit/connections/base_connection.py +5 -5
- streamlit/connections/snowflake_connection.py +13 -11
- streamlit/connections/snowpark_connection.py +3 -3
- streamlit/connections/sql_connection.py +20 -18
- streamlit/connections/util.py +2 -2
- streamlit/cursor.py +6 -6
- streamlit/dataframe_util.py +52 -52
- streamlit/delta_generator.py +46 -48
- streamlit/delta_generator_singletons.py +3 -3
- streamlit/deprecation_util.py +6 -6
- streamlit/elements/alert.py +37 -29
- streamlit/elements/arrow.py +40 -22
- streamlit/elements/code.py +46 -13
- streamlit/elements/deck_gl_json_chart.py +38 -27
- streamlit/elements/dialog_decorator.py +3 -4
- streamlit/elements/doc_string.py +64 -58
- streamlit/elements/exception.py +23 -27
- streamlit/elements/form.py +41 -0
- streamlit/elements/graphviz_chart.py +1 -1
- streamlit/elements/heading.py +60 -9
- streamlit/elements/html.py +3 -4
- streamlit/elements/image.py +8 -9
- streamlit/elements/json.py +21 -2
- streamlit/elements/layouts.py +120 -31
- streamlit/elements/lib/built_in_chart_utils.py +96 -73
- streamlit/elements/lib/color_util.py +3 -3
- streamlit/elements/lib/column_config_utils.py +2 -4
- streamlit/elements/lib/column_types.py +14 -8
- streamlit/elements/lib/dialog.py +9 -5
- streamlit/elements/lib/image_utils.py +39 -40
- streamlit/elements/lib/js_number.py +4 -4
- streamlit/elements/lib/layout_utils.py +65 -1
- streamlit/elements/lib/mutable_status_container.py +14 -3
- streamlit/elements/lib/options_selector_utils.py +22 -12
- streamlit/elements/lib/pandas_styler_utils.py +25 -21
- streamlit/elements/lib/policies.py +6 -5
- streamlit/elements/lib/streamlit_plotly_theme.py +54 -53
- streamlit/elements/lib/subtitle_utils.py +6 -9
- streamlit/elements/lib/utils.py +20 -5
- streamlit/elements/map.py +32 -56
- streamlit/elements/markdown.py +101 -12
- streamlit/elements/media.py +78 -21
- streamlit/elements/metric.py +32 -16
- streamlit/elements/plotly_chart.py +15 -15
- streamlit/elements/progress.py +33 -15
- streamlit/elements/spinner.py +31 -6
- streamlit/elements/text.py +21 -1
- streamlit/elements/toast.py +1 -2
- streamlit/elements/vega_charts.py +54 -23
- streamlit/elements/widgets/audio_input.py +24 -7
- streamlit/elements/widgets/button.py +26 -19
- streamlit/elements/widgets/button_group.py +10 -15
- streamlit/elements/widgets/camera_input.py +27 -7
- streamlit/elements/widgets/chat.py +91 -38
- streamlit/elements/widgets/checkbox.py +45 -4
- streamlit/elements/widgets/color_picker.py +40 -17
- streamlit/elements/widgets/data_editor.py +76 -37
- streamlit/elements/widgets/file_uploader.py +42 -13
- streamlit/elements/widgets/multiselect.py +7 -10
- streamlit/elements/widgets/number_input.py +123 -47
- streamlit/elements/widgets/radio.py +59 -13
- streamlit/elements/widgets/select_slider.py +35 -30
- streamlit/elements/widgets/selectbox.py +56 -9
- streamlit/elements/widgets/slider.py +190 -99
- streamlit/elements/widgets/text_widgets.py +54 -8
- streamlit/elements/widgets/time_widgets.py +53 -14
- streamlit/elements/write.py +5 -8
- streamlit/env_util.py +2 -7
- streamlit/error_util.py +16 -9
- streamlit/errors.py +69 -48
- streamlit/external/langchain/streamlit_callback_handler.py +10 -5
- streamlit/file_util.py +27 -10
- streamlit/git_util.py +29 -24
- streamlit/hello/animation_demo.py +9 -9
- streamlit/hello/dataframe_demo.py +5 -5
- streamlit/hello/hello.py +1 -0
- streamlit/hello/mapping_demo.py +7 -8
- streamlit/hello/plotting_demo.py +3 -3
- streamlit/hello/streamlit_app.py +28 -26
- streamlit/hello/utils.py +2 -1
- streamlit/logger.py +10 -11
- streamlit/navigation/page.py +11 -8
- streamlit/proto/Audio_pb2.py +4 -3
- streamlit/proto/Audio_pb2.pyi +8 -1
- streamlit/proto/Block_pb2.py +38 -29
- streamlit/proto/Block_pb2.pyi +72 -4
- streamlit/proto/ClientState_pb2.py +4 -4
- streamlit/proto/ClientState_pb2.pyi +7 -2
- streamlit/proto/Code_pb2.py +4 -2
- streamlit/proto/Code_pb2.pyi +1 -0
- streamlit/proto/DataFrame_pb2.pyi +1 -1
- streamlit/proto/DeckGlJsonChart_pb2.pyi +1 -1
- streamlit/proto/Element_pb2.py +5 -3
- streamlit/proto/Element_pb2.pyi +20 -3
- streamlit/proto/GapSize_pb2.py +29 -0
- streamlit/proto/GapSize_pb2.pyi +70 -0
- streamlit/proto/HeightConfig_pb2.py +27 -0
- streamlit/proto/HeightConfig_pb2.pyi +48 -0
- streamlit/proto/NamedDataSet_pb2.pyi +1 -1
- streamlit/proto/Navigation_pb2.py +3 -3
- streamlit/proto/Navigation_pb2.pyi +4 -0
- streamlit/proto/NewSession_pb2.py +18 -16
- streamlit/proto/NewSession_pb2.pyi +29 -3
- streamlit/proto/PageConfig_pb2.py +7 -7
- streamlit/proto/PageConfig_pb2.pyi +21 -1
- streamlit/proto/Video_pb2.py +8 -7
- streamlit/proto/Video_pb2.pyi +8 -1
- streamlit/proto/WidthConfig_pb2.py +2 -2
- streamlit/proto/WidthConfig_pb2.pyi +15 -1
- streamlit/runtime/__init__.py +1 -1
- streamlit/runtime/app_session.py +53 -40
- streamlit/runtime/caching/__init__.py +9 -9
- streamlit/runtime/caching/cache_data_api.py +36 -30
- streamlit/runtime/caching/cache_errors.py +4 -4
- streamlit/runtime/caching/cache_resource_api.py +8 -8
- streamlit/runtime/caching/cache_utils.py +15 -14
- streamlit/runtime/caching/cached_message_replay.py +14 -8
- streamlit/runtime/caching/hashing.py +91 -97
- streamlit/runtime/caching/legacy_cache_api.py +2 -2
- streamlit/runtime/caching/storage/cache_storage_protocol.py +1 -1
- streamlit/runtime/caching/storage/dummy_cache_storage.py +1 -1
- streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +12 -14
- streamlit/runtime/caching/storage/local_disk_cache_storage.py +6 -6
- streamlit/runtime/connection_factory.py +36 -36
- streamlit/runtime/context.py +58 -9
- streamlit/runtime/credentials.py +29 -40
- streamlit/runtime/forward_msg_queue.py +11 -11
- streamlit/runtime/fragment.py +7 -7
- streamlit/runtime/media_file_manager.py +3 -4
- streamlit/runtime/memory_media_file_storage.py +6 -5
- streamlit/runtime/memory_uploaded_file_manager.py +2 -2
- streamlit/runtime/metrics_util.py +11 -12
- streamlit/runtime/pages_manager.py +4 -6
- streamlit/runtime/runtime.py +8 -6
- streamlit/runtime/runtime_util.py +7 -6
- streamlit/runtime/scriptrunner/__init__.py +4 -4
- streamlit/runtime/scriptrunner/exec_code.py +12 -5
- streamlit/runtime/scriptrunner/magic.py +16 -12
- streamlit/runtime/scriptrunner/script_cache.py +1 -1
- streamlit/runtime/scriptrunner/script_runner.py +53 -29
- streamlit/runtime/scriptrunner_utils/exceptions.py +1 -1
- streamlit/runtime/scriptrunner_utils/script_requests.py +7 -4
- streamlit/runtime/scriptrunner_utils/script_run_context.py +10 -23
- streamlit/runtime/secrets.py +40 -35
- streamlit/runtime/session_manager.py +2 -1
- streamlit/runtime/state/__init__.py +5 -5
- streamlit/runtime/state/common.py +2 -2
- streamlit/runtime/state/query_params.py +13 -15
- streamlit/runtime/state/query_params_proxy.py +17 -13
- streamlit/runtime/state/safe_session_state.py +2 -2
- streamlit/runtime/state/session_state.py +52 -34
- streamlit/runtime/stats.py +2 -2
- streamlit/runtime/uploaded_file_manager.py +1 -1
- streamlit/runtime/websocket_session_manager.py +10 -6
- streamlit/source_util.py +8 -6
- streamlit/static/index.html +3 -17
- streamlit/static/manifest.json +1180 -0
- streamlit/static/static/css/{index.DqDwtg6_.css → index.CJVRHjQZ.css} +1 -1
- streamlit/static/static/js/{ErrorOutline.esm.DU9IrB3M.js → ErrorOutline.esm.DitPpe1Y.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.P9rKwKo8.js → FileDownload.esm.AI3watX9.js} +1 -1
- streamlit/static/static/js/{FileHelper.D7RMkx0e.js → FileHelper.kt7mhnu8.js} +5 -5
- streamlit/static/static/js/{FormClearHelper.B67tgll0.js → FormClearHelper.D1M9GM_c.js} +1 -1
- streamlit/static/static/js/{Hooks.ncTJktu9.js → Hooks.BGwHKeUc.js} +1 -1
- streamlit/static/static/js/{InputInstructions.D-Y8geDN.js → InputInstructions.DaZ89mzH.js} +1 -1
- streamlit/static/static/js/{ProgressBar.B-kexwwD.js → ProgressBar.C0zPMe-p.js} +2 -2
- streamlit/static/static/js/{RenderInPortalIfExists.BgaoZgep.js → RenderInPortalIfExists.Ox8gQvdz.js} +1 -1
- streamlit/static/static/js/Toolbar.KhlcEc0K.js +1 -0
- streamlit/static/static/js/UploadFileInfo.0DCkpDDf.js +6 -0
- streamlit/static/static/js/{base-input.BoAa1U94.js → base-input.BJ4qsfSq.js} +4 -4
- streamlit/static/static/js/{checkbox.Z6iSfe5F.js → checkbox.DSDh78Xz.js} +2 -2
- streamlit/static/static/js/{createSuper.B4oGDYRm.js → createSuper.wQ9SIXEJ.js} +1 -1
- streamlit/static/static/js/{data-grid-overlay-editor.msYws2Ou.js → data-grid-overlay-editor.DvbdPJ15.js} +1 -1
- streamlit/static/static/js/{downloader.kc14n2Hv.js → downloader.CD9rzih5.js} +1 -1
- streamlit/static/static/js/{es6.CxQz807-.js → es6.48Q9Qjgb.js} +2 -2
- streamlit/static/static/js/{iframeResizer.contentWindow.B19u0ONI.js → iframeResizer.contentWindow.CKdem3Bn.js} +1 -1
- streamlit/static/static/js/{index.LaIasviC.js → index.6md5Qhod.js} +1 -1
- streamlit/static/static/js/index.7hy6AeJ1.js +1 -0
- streamlit/static/static/js/index.B4CGJiBW.js +1 -0
- streamlit/static/static/js/index.B8oW0ZTD.js +1 -0
- streamlit/static/static/js/index.BU6RnlHI.js +73 -0
- streamlit/static/static/js/index.BUq9Wcf8.js +197 -0
- streamlit/static/static/js/{index.BFz9U2y0.js → index.BXXo-Yoj.js} +1 -1
- streamlit/static/static/js/index.Bae9H0OS.js +1 -0
- streamlit/static/static/js/{index.-5ruC9At.js → index.BhTl2Uyb.js} +1 -1
- streamlit/static/static/js/{index.BpILzHf_.js → index.BiSaCB1o.js} +20 -20
- streamlit/static/static/js/{index.xNQq3Ei5.js → index.BulSAJ9z.js} +1 -1
- streamlit/static/static/js/{index.9V1KdxfP.js → index.Bv-EuTKR.js} +1 -1
- streamlit/static/static/js/index.BvMLYCHi.js +1 -0
- streamlit/static/static/js/index.C1NIn1Y2.js +783 -0
- streamlit/static/static/js/index.CP-fthOJ.js +2 -0
- streamlit/static/static/js/{index.BoigZiu7.js → index.CS9guO3p.js} +1 -1
- streamlit/static/static/js/index.CYTBHth8.js +1 -0
- streamlit/static/static/js/{index.CmTAF0dM.js → index.CcJufcuD.js} +1 -1
- streamlit/static/static/js/index.CnENU1yn.js +1 -0
- streamlit/static/static/js/index.Cns13qBb.js +1 -0
- streamlit/static/static/js/index.Ct_xXq7w.js +1 -0
- streamlit/static/static/js/{index.BqfdT8-Q.js → index.CxGSemHL.js} +1 -1
- streamlit/static/static/js/index.D5S0ldVb.js +1 -0
- streamlit/static/static/js/index.D72B_ksb.js +2 -0
- streamlit/static/static/js/index.DI4yZ27M.js +1 -0
- streamlit/static/static/js/index.DN51vLxR.js +1 -0
- streamlit/static/static/js/index.DRtq5dka.js +1 -0
- streamlit/static/static/js/{index.BHXxWdde.js → index.DX-oiXlb.js} +1 -1
- streamlit/static/static/js/index.DlFE4_Aq.js +12 -0
- streamlit/static/static/js/{index.BHGGDa8K.js → index.J7BJwXOi.js} +2 -2
- streamlit/static/static/js/index.Jg38kJPP.js +1 -0
- streamlit/static/static/js/index.JhIO6abf.js +3 -0
- streamlit/static/static/js/{index.DeB9iKFW.js → index.NkRcWwc5.js} +255 -255
- streamlit/static/static/js/{index.BGga-hcS.js → index.prekPLrm.js} +25 -25
- streamlit/static/static/js/{index.BRXmLIsC.js → index.wyzngKUE.js} +1 -1
- streamlit/static/static/js/index.xW7mVdI8.js +1 -0
- streamlit/static/static/js/index.yk07dYGx.js +1 -0
- streamlit/static/static/js/{input.DsCfafm0.js → input.CxKZ5Wrc.js} +2 -2
- streamlit/static/static/js/{memory.nY_lMTtu.js → memory.DeZ9VUvl.js} +1 -1
- streamlit/static/static/js/{mergeWith.B_7zmsM4.js → mergeWith.CVkhrWUb.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.CSeVhHRU.js → number-overlay-editor.Bpkm3nTq.js} +1 -1
- streamlit/static/static/js/{possibleConstructorReturn.nNhsvgRd.js → possibleConstructorReturn.CIDCId52.js} +1 -1
- streamlit/static/static/js/{sandbox.Cgm3iuL6.js → sandbox.TrkMaokR.js} +1 -1
- streamlit/static/static/js/{textarea.BR8rlyih.js → textarea.QKjxR64N.js} +2 -2
- streamlit/static/static/js/{timepicker.w4XhAenH.js → timepicker.DJYmE1dK.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.CgkEPBwD.js → toConsumableArray.BZoworE-.js} +1 -1
- streamlit/static/static/js/{uniqueId.j-1rlNNH.js → uniqueId.O0UbJ2Bu.js} +1 -1
- streamlit/static/static/js/{useBasicWidgetState.zXY9CjFS.js → useBasicWidgetState.Ci89jaH5.js} +1 -1
- streamlit/static/static/js/useOnInputChange.Cxh6ExEn.js +1 -0
- streamlit/static/static/js/{withFullScreenWrapper.Ov13692o.js → withFullScreenWrapper.iW37lS8Z.js} +1 -1
- streamlit/static/static/media/SourceCodeVF-Italic.ttf.Ba1oaZG1.woff2 +0 -0
- streamlit/static/static/media/SourceCodeVF-Upright.ttf.BjWn63N-.woff2 +0 -0
- streamlit/static/static/media/SourceSansVF-Italic.ttf.Bt9VkdQ3.woff2 +0 -0
- streamlit/static/static/media/SourceSansVF-Upright.ttf.BsWL4Kly.woff2 +0 -0
- streamlit/static/static/media/SourceSerifVariable-Italic.ttf.CVdzAtxO.woff2 +0 -0
- streamlit/static/static/media/SourceSerifVariable-Roman.ttf.mdpVL9bi.woff2 +0 -0
- streamlit/string_util.py +14 -19
- streamlit/temporary_directory.py +13 -4
- streamlit/testing/v1/app_test.py +15 -10
- streamlit/testing/v1/element_tree.py +157 -178
- streamlit/testing/v1/local_script_runner.py +11 -15
- streamlit/testing/v1/util.py +11 -4
- streamlit/type_util.py +8 -12
- streamlit/url_util.py +1 -1
- streamlit/user_info.py +6 -5
- streamlit/util.py +25 -1
- streamlit/vendor/pympler/asizeof.py +3 -2
- streamlit/watcher/event_based_path_watcher.py +21 -2
- streamlit/watcher/folder_black_list.py +2 -2
- streamlit/watcher/local_sources_watcher.py +64 -18
- streamlit/watcher/path_watcher.py +6 -10
- streamlit/watcher/polling_path_watcher.py +8 -7
- streamlit/watcher/util.py +7 -6
- streamlit/web/bootstrap.py +16 -14
- streamlit/web/cli.py +52 -45
- streamlit/web/server/__init__.py +7 -3
- streamlit/web/server/app_static_file_handler.py +1 -1
- streamlit/web/server/authlib_tornado_integration.py +9 -4
- streamlit/web/server/browser_websocket_handler.py +8 -2
- streamlit/web/server/component_request_handler.py +14 -10
- streamlit/web/server/media_file_handler.py +14 -7
- streamlit/web/server/oauth_authlib_routes.py +41 -9
- streamlit/web/server/oidc_mixin.py +35 -17
- streamlit/web/server/routes.py +32 -22
- streamlit/web/server/server.py +13 -24
- streamlit/web/server/server_util.py +43 -9
- streamlit/web/server/stats_request_handler.py +7 -5
- streamlit/web/server/upload_file_request_handler.py +22 -19
- streamlit/web/server/websocket_headers.py +1 -1
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/METADATA +4 -4
- streamlit-1.46.1.dist-info/RECORD +559 -0
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/WHEEL +1 -1
- streamlit/elements/lib/event_utils.py +0 -39
- streamlit/static/static/js/Toolbar.D9RUZv9G.js +0 -1
- streamlit/static/static/js/UploadFileInfo.C-jY39rj.js +0 -1
- streamlit/static/static/js/index.8jhZBWF2.js +0 -3
- streamlit/static/static/js/index.BCx3C6e_.js +0 -1
- streamlit/static/static/js/index.BRuTz_S4.js +0 -1
- streamlit/static/static/js/index.Bcru_ti-.js +0 -1
- streamlit/static/static/js/index.Bl1FMJRd.js +0 -1
- streamlit/static/static/js/index.C1z8KpLA.js +0 -779
- streamlit/static/static/js/index.C32I2PUe.js +0 -2
- streamlit/static/static/js/index.C5GnDRB7.js +0 -1
- streamlit/static/static/js/index.CG4qPaaW.js +0 -2
- streamlit/static/static/js/index.C_msmT1u.js +0 -1
- streamlit/static/static/js/index.CbeNTdd6.js +0 -1
- streamlit/static/static/js/index.CnGQVJcw.js +0 -12
- streamlit/static/static/js/index.CopVVq4l.js +0 -1
- streamlit/static/static/js/index.CtXupx4d.js +0 -197
- streamlit/static/static/js/index.DGmCchO7.js +0 -1
- streamlit/static/static/js/index.DH6zBk0e.js +0 -1
- streamlit/static/static/js/index.DHVlVWsm.js +0 -1
- streamlit/static/static/js/index.DRKIVBoi.js +0 -1
- streamlit/static/static/js/index.DUd-lFXx.js +0 -73
- streamlit/static/static/js/index.D_uRBA4B.js +0 -1
- streamlit/static/static/js/index.QHNfgPJd.js +0 -1
- streamlit/static/static/js/index.a-RJocYL.js +0 -1
- streamlit/static/static/js/index.cvz4B1gy.js +0 -1
- streamlit/static/static/js/index.t--hEgTQ.js +0 -6
- streamlit/static/static/js/useOnInputChange.z04u96A8.js +0 -1
- streamlit/static/static/media/SourceCodePro-Bold.CFEfr7-q.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-BoldItalic.C-LkFXxa.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-Italic.CxFOx7N-.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-Regular.CBOlD63d.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-SemiBold.CFHwW3Wd.woff2 +0 -0
- streamlit/static/static/media/SourceCodePro-SemiBoldItalic.Cg2yRu82.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Bold.-6c9oR8J.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-BoldItalic.DmM_grLY.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Italic.I1ipWe7Q.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-Regular.DZLUzqI4.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-SemiBold.sKQIyTMz.woff2 +0 -0
- streamlit/static/static/media/SourceSansPro-SemiBoldItalic.C0wP0icr.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Bold.8TUnKj4x.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-BoldItalic.CBVO7Ve7.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Italic.DkFgL2HZ.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-Regular.CNJNET2S.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-SemiBold.CHyh9GC5.woff2 +0 -0
- streamlit/static/static/media/SourceSerifPro-SemiBoldItalic.CBtz8sWN.woff2 +0 -0
- streamlit-1.45.1.dist-info/RECORD +0 -568
- {streamlit-1.45.1.data → streamlit-1.46.1.data}/scripts/streamlit.cmd +0 -0
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/entry_points.txt +0 -0
- {streamlit-1.45.1.dist-info → streamlit-1.46.1.dist-info}/top_level.txt +0 -0
|
@@ -97,12 +97,12 @@ def _validate_image_format_string(
|
|
|
97
97
|
- For all other strings, return "PNG" if the image has an alpha channel,
|
|
98
98
|
"GIF" if the image is a GIF, and "JPEG" otherwise.
|
|
99
99
|
"""
|
|
100
|
-
|
|
101
|
-
if
|
|
102
|
-
return cast("ImageFormat",
|
|
100
|
+
img_format = format.upper()
|
|
101
|
+
if img_format in {"JPEG", "PNG"}:
|
|
102
|
+
return cast("ImageFormat", img_format)
|
|
103
103
|
|
|
104
104
|
# We are forgiving on the spelling of JPEG
|
|
105
|
-
if
|
|
105
|
+
if img_format == "JPG":
|
|
106
106
|
return "JPEG"
|
|
107
107
|
|
|
108
108
|
pil_image: PILImage
|
|
@@ -122,7 +122,7 @@ def _validate_image_format_string(
|
|
|
122
122
|
return "JPEG"
|
|
123
123
|
|
|
124
124
|
|
|
125
|
-
def
|
|
125
|
+
def _pil_to_bytes(
|
|
126
126
|
image: PILImage,
|
|
127
127
|
format: ImageFormat = "JPEG",
|
|
128
128
|
quality: int = 100,
|
|
@@ -139,7 +139,7 @@ def _PIL_to_bytes(
|
|
|
139
139
|
return tmp.getvalue()
|
|
140
140
|
|
|
141
141
|
|
|
142
|
-
def
|
|
142
|
+
def _bytesio_to_bytes(data: io.BytesIO) -> bytes:
|
|
143
143
|
data.seek(0)
|
|
144
144
|
return data.getvalue()
|
|
145
145
|
|
|
@@ -149,9 +149,9 @@ def _np_array_to_bytes(array: npt.NDArray[Any], output_format: str = "JPEG") ->
|
|
|
149
149
|
from PIL import Image
|
|
150
150
|
|
|
151
151
|
img = Image.fromarray(array.astype(np.uint8))
|
|
152
|
-
|
|
152
|
+
img_format = _validate_image_format_string(img, output_format)
|
|
153
153
|
|
|
154
|
-
return
|
|
154
|
+
return _pil_to_bytes(img, img_format)
|
|
155
155
|
|
|
156
156
|
|
|
157
157
|
def _verify_np_shape(array: npt.NDArray[Any]) -> npt.NDArray[Any]:
|
|
@@ -160,8 +160,7 @@ def _verify_np_shape(array: npt.NDArray[Any]) -> npt.NDArray[Any]:
|
|
|
160
160
|
raise StreamlitAPIException("Numpy shape has to be of length 2 or 3.")
|
|
161
161
|
if len(shape) == 3 and shape[-1] not in (1, 3, 4):
|
|
162
162
|
raise StreamlitAPIException(
|
|
163
|
-
"Channel can only be 1, 3, or 4 got
|
|
164
|
-
% (shape[-1], str(shape))
|
|
163
|
+
f"Channel can only be 1, 3, or 4 got {shape[-1]}. Shape is {shape}"
|
|
165
164
|
)
|
|
166
165
|
|
|
167
166
|
# If there's only one channel, convert is to x, y
|
|
@@ -199,11 +198,11 @@ def _ensure_image_size_and_format(
|
|
|
199
198
|
# versions. The types don't seem to reflect this, though, hence the type: ignore
|
|
200
199
|
# below.
|
|
201
200
|
pil_image = pil_image.resize((width, new_height), resample=Image.BILINEAR) # type: ignore[attr-defined]
|
|
202
|
-
return
|
|
201
|
+
return _pil_to_bytes(pil_image, format=image_format, quality=90)
|
|
203
202
|
|
|
204
203
|
if pil_image.format != image_format:
|
|
205
204
|
# We need to reformat the image.
|
|
206
|
-
return
|
|
205
|
+
return _pil_to_bytes(pil_image, format=image_format, quality=90)
|
|
207
206
|
|
|
208
207
|
# No resizing or reformatting necessary - return the original bytes.
|
|
209
208
|
return image_data
|
|
@@ -216,16 +215,13 @@ def _clip_image(image: npt.NDArray[Any], clamp: bool) -> npt.NDArray[Any]:
|
|
|
216
215
|
if issubclass(image.dtype.type, np.floating):
|
|
217
216
|
if clamp:
|
|
218
217
|
data = np.clip(image, 0, 1.0)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
raise RuntimeError("Data is outside [0.0, 1.0] and clamp is not set.")
|
|
218
|
+
elif np.amin(image) < 0.0 or np.amax(image) > 1.0:
|
|
219
|
+
raise RuntimeError("Data is outside [0.0, 1.0] and clamp is not set.")
|
|
222
220
|
data = data * 255
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if np.amin(image) < 0 or np.amax(image) > 255:
|
|
228
|
-
raise RuntimeError("Data is outside [0, 255] and clamp is not set.")
|
|
221
|
+
elif clamp:
|
|
222
|
+
data = np.clip(image, 0, 255)
|
|
223
|
+
elif np.amin(image) < 0 or np.amax(image) > 255:
|
|
224
|
+
raise RuntimeError("Data is outside [0, 255] and clamp is not set.")
|
|
229
225
|
return data
|
|
230
226
|
|
|
231
227
|
|
|
@@ -301,14 +297,14 @@ def image_to_url(
|
|
|
301
297
|
|
|
302
298
|
# PIL Images
|
|
303
299
|
elif isinstance(image, (ImageFile.ImageFile, Image.Image)):
|
|
304
|
-
|
|
305
|
-
image_data =
|
|
300
|
+
img_format = _validate_image_format_string(image, output_format)
|
|
301
|
+
image_data = _pil_to_bytes(image, img_format)
|
|
306
302
|
|
|
307
303
|
# BytesIO
|
|
308
304
|
# Note: This doesn't support SVG. We could convert to png (cairosvg.svg2png)
|
|
309
305
|
# or just decode BytesIO to string and handle that way.
|
|
310
306
|
elif isinstance(image, io.BytesIO):
|
|
311
|
-
image_data =
|
|
307
|
+
image_data = _bytesio_to_bytes(image)
|
|
312
308
|
|
|
313
309
|
# Numpy Arrays (ie opencv)
|
|
314
310
|
elif isinstance(image, np.ndarray):
|
|
@@ -338,9 +334,8 @@ def image_to_url(
|
|
|
338
334
|
url = runtime.get_instance().media_file_mgr.add(image_data, mimetype, image_id)
|
|
339
335
|
caching.save_media_data(image_data, mimetype, image_id)
|
|
340
336
|
return url
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
return ""
|
|
337
|
+
# When running in "raw mode", we can't access the MediaFileManager.
|
|
338
|
+
return ""
|
|
344
339
|
|
|
345
340
|
|
|
346
341
|
def _4d_to_list_3d(array: npt.NDArray[Any]) -> list[npt.NDArray[Any]]:
|
|
@@ -363,7 +358,7 @@ def marshall_images(
|
|
|
363
358
|
Parameters
|
|
364
359
|
----------
|
|
365
360
|
coordinates
|
|
366
|
-
A string
|
|
361
|
+
A string identifying the images' location in the frontend.
|
|
367
362
|
image
|
|
368
363
|
The image or images to include in the ImageListProto.
|
|
369
364
|
caption
|
|
@@ -420,25 +415,29 @@ def marshall_images(
|
|
|
420
415
|
else:
|
|
421
416
|
captions = [str(caption)]
|
|
422
417
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
418
|
+
if not isinstance(captions, list):
|
|
419
|
+
raise StreamlitAPIException(
|
|
420
|
+
"If image is a list then caption should be a list as well."
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
if len(captions) != len(images):
|
|
424
|
+
raise StreamlitAPIException(
|
|
425
|
+
f"Cannot pair {len(captions)} captions with {len(images)} images."
|
|
426
|
+
)
|
|
430
427
|
|
|
431
428
|
proto_imgs.width = int(width)
|
|
432
429
|
# Each image in an image list needs to be kept track of at its own coordinates.
|
|
433
|
-
for coord_suffix, (
|
|
430
|
+
for coord_suffix, (single_image, single_caption) in enumerate(
|
|
431
|
+
zip(images, captions)
|
|
432
|
+
):
|
|
434
433
|
proto_img = proto_imgs.imgs.add()
|
|
435
|
-
if
|
|
436
|
-
proto_img.caption = str(
|
|
434
|
+
if single_caption is not None:
|
|
435
|
+
proto_img.caption = str(single_caption)
|
|
437
436
|
|
|
438
437
|
# We use the index of the image in the input image list to identify this image inside
|
|
439
438
|
# MediaFileManager. For this, we just add the index to the image's "coordinates".
|
|
440
|
-
image_id = "
|
|
439
|
+
image_id = f"{coordinates}-{coord_suffix}"
|
|
441
440
|
|
|
442
441
|
proto_img.url = image_to_url(
|
|
443
|
-
|
|
442
|
+
single_image, width, clamp, channels, output_format, image_id
|
|
444
443
|
)
|
|
@@ -17,7 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
import numbers
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
class JSNumberBoundsException(Exception):
|
|
20
|
+
class JSNumberBoundsException(Exception): # noqa: N818
|
|
21
21
|
pass
|
|
22
22
|
|
|
23
23
|
|
|
@@ -67,7 +67,7 @@ class JSNumber:
|
|
|
67
67
|
raise JSNumberBoundsException(
|
|
68
68
|
f"{value_name} ({value}) must be >= -((1 << 53) - 1)"
|
|
69
69
|
)
|
|
70
|
-
|
|
70
|
+
if value > cls.MAX_SAFE_INTEGER:
|
|
71
71
|
raise JSNumberBoundsException(
|
|
72
72
|
f"{value_name} ({value}) must be <= (1 << 53) - 1"
|
|
73
73
|
)
|
|
@@ -95,11 +95,11 @@ class JSNumber:
|
|
|
95
95
|
|
|
96
96
|
if not isinstance(value, (numbers.Integral, float)):
|
|
97
97
|
raise JSNumberBoundsException(f"{value_name} ({value}) is not a float")
|
|
98
|
-
|
|
98
|
+
if value < cls.MIN_NEGATIVE_VALUE:
|
|
99
99
|
raise JSNumberBoundsException(
|
|
100
100
|
f"{value_name} ({value}) must be >= -1.797e+308"
|
|
101
101
|
)
|
|
102
|
-
|
|
102
|
+
if value > cls.MAX_VALUE:
|
|
103
103
|
raise JSNumberBoundsException(
|
|
104
104
|
f"{value_name} ({value}) must be <= 1.797e+308"
|
|
105
105
|
)
|
|
@@ -11,15 +11,27 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
from __future__ import annotations
|
|
14
15
|
|
|
16
|
+
from dataclasses import dataclass
|
|
15
17
|
from typing import Literal, Union
|
|
16
18
|
|
|
17
19
|
from typing_extensions import TypeAlias
|
|
18
20
|
|
|
19
|
-
from streamlit.errors import StreamlitInvalidWidthError
|
|
21
|
+
from streamlit.errors import StreamlitInvalidHeightError, StreamlitInvalidWidthError
|
|
22
|
+
from streamlit.proto.HeightConfig_pb2 import HeightConfig
|
|
23
|
+
from streamlit.proto.WidthConfig_pb2 import WidthConfig
|
|
20
24
|
|
|
21
25
|
WidthWithoutContent: TypeAlias = Union[int, Literal["stretch"]]
|
|
22
26
|
Width: TypeAlias = Union[int, Literal["stretch", "content"]]
|
|
27
|
+
HeightWithoutContent: TypeAlias = Union[int, Literal["stretch"]]
|
|
28
|
+
Height: TypeAlias = Union[int, Literal["stretch", "content"]]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class LayoutConfig:
|
|
33
|
+
width: Width | None = None
|
|
34
|
+
height: Height | None = None
|
|
23
35
|
|
|
24
36
|
|
|
25
37
|
def validate_width(width: Width, allow_content: bool = False) -> None:
|
|
@@ -49,3 +61,55 @@ def validate_width(width: Width, allow_content: bool = False) -> None:
|
|
|
49
61
|
raise StreamlitInvalidWidthError(width, allow_content)
|
|
50
62
|
elif width <= 0:
|
|
51
63
|
raise StreamlitInvalidWidthError(width, allow_content)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def validate_height(height: Height, allow_content: bool = False) -> None:
|
|
67
|
+
"""Validate the height parameter.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
height : Any
|
|
72
|
+
The height value to validate.
|
|
73
|
+
allow_content : bool
|
|
74
|
+
Whether to allow "content" as a valid height value.
|
|
75
|
+
|
|
76
|
+
Raises
|
|
77
|
+
------
|
|
78
|
+
StreamlitInvalidHeightError
|
|
79
|
+
If the height value is invalid.
|
|
80
|
+
"""
|
|
81
|
+
if not isinstance(height, (int, str)):
|
|
82
|
+
raise StreamlitInvalidHeightError(height, allow_content)
|
|
83
|
+
|
|
84
|
+
if isinstance(height, str):
|
|
85
|
+
valid_strings = ["stretch"]
|
|
86
|
+
if allow_content:
|
|
87
|
+
valid_strings.append("content")
|
|
88
|
+
|
|
89
|
+
if height not in valid_strings:
|
|
90
|
+
raise StreamlitInvalidHeightError(height, allow_content)
|
|
91
|
+
|
|
92
|
+
elif height <= 0:
|
|
93
|
+
raise StreamlitInvalidHeightError(height, allow_content)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_width_config(width: Width) -> WidthConfig:
|
|
97
|
+
width_config = WidthConfig()
|
|
98
|
+
if isinstance(width, int):
|
|
99
|
+
width_config.pixel_width = width
|
|
100
|
+
elif width == "content":
|
|
101
|
+
width_config.use_content = True
|
|
102
|
+
else:
|
|
103
|
+
width_config.use_stretch = True
|
|
104
|
+
return width_config
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def get_height_config(height: Height) -> HeightConfig:
|
|
108
|
+
height_config = HeightConfig()
|
|
109
|
+
if isinstance(height, int):
|
|
110
|
+
height_config.pixel_height = height
|
|
111
|
+
elif height == "content":
|
|
112
|
+
height_config.use_content = True
|
|
113
|
+
else:
|
|
114
|
+
height_config.use_stretch = True
|
|
115
|
+
return height_config
|
|
@@ -20,6 +20,11 @@ from typing import TYPE_CHECKING, Literal, cast
|
|
|
20
20
|
from typing_extensions import Self, TypeAlias
|
|
21
21
|
|
|
22
22
|
from streamlit.delta_generator import DeltaGenerator
|
|
23
|
+
from streamlit.elements.lib.layout_utils import (
|
|
24
|
+
WidthWithoutContent,
|
|
25
|
+
get_width_config,
|
|
26
|
+
validate_width,
|
|
27
|
+
)
|
|
23
28
|
from streamlit.errors import StreamlitAPIException
|
|
24
29
|
from streamlit.proto.Block_pb2 import Block as BlockProto
|
|
25
30
|
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
|
|
@@ -40,6 +45,7 @@ class StatusContainer(DeltaGenerator):
|
|
|
40
45
|
label: str,
|
|
41
46
|
expanded: bool = False,
|
|
42
47
|
state: States = "running",
|
|
48
|
+
width: WidthWithoutContent = "stretch",
|
|
43
49
|
) -> StatusContainer:
|
|
44
50
|
expandable_proto = BlockProto.Expandable()
|
|
45
51
|
expandable_proto.expanded = expanded
|
|
@@ -60,6 +66,9 @@ class StatusContainer(DeltaGenerator):
|
|
|
60
66
|
block_proto.allow_empty = True
|
|
61
67
|
block_proto.expandable.CopyFrom(expandable_proto)
|
|
62
68
|
|
|
69
|
+
validate_width(width=width)
|
|
70
|
+
block_proto.width_config.CopyFrom(get_width_config(width))
|
|
71
|
+
|
|
63
72
|
delta_path: list[int] = (
|
|
64
73
|
parent._active_dg._cursor.delta_path if parent._active_dg._cursor else []
|
|
65
74
|
)
|
|
@@ -88,7 +97,7 @@ class StatusContainer(DeltaGenerator):
|
|
|
88
97
|
cursor: Cursor | None,
|
|
89
98
|
parent: DeltaGenerator | None,
|
|
90
99
|
block_type: str | None,
|
|
91
|
-
):
|
|
100
|
+
) -> None:
|
|
92
101
|
super().__init__(root_container, cursor, parent, block_type)
|
|
93
102
|
|
|
94
103
|
# Initialized in `_create()`:
|
|
@@ -122,8 +131,10 @@ class StatusContainer(DeltaGenerator):
|
|
|
122
131
|
The new state of the status container. This mainly changes the
|
|
123
132
|
icon. If None, the state is not changed.
|
|
124
133
|
"""
|
|
125
|
-
|
|
126
|
-
|
|
134
|
+
if self._current_proto is None or self._delta_path is None:
|
|
135
|
+
raise RuntimeError(
|
|
136
|
+
"StatusContainer is not correctly initialized. This should never happen."
|
|
137
|
+
)
|
|
127
138
|
|
|
128
139
|
msg = ForwardMsg()
|
|
129
140
|
msg.metadata.delta_path[:] = self._delta_path
|
|
@@ -54,10 +54,13 @@ def index_(iterable: Iterable[_Value], x: _Value) -> int:
|
|
|
54
54
|
for i, value in enumerate(iterable):
|
|
55
55
|
if x == value:
|
|
56
56
|
return i
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
if (
|
|
58
|
+
isinstance(value, float)
|
|
59
|
+
and isinstance(x, float)
|
|
60
|
+
and abs(x - value) < _FLOAT_EQUALITY_EPSILON
|
|
61
|
+
):
|
|
62
|
+
return i
|
|
63
|
+
raise ValueError(f"{x} is not in iterable")
|
|
61
64
|
|
|
62
65
|
|
|
63
66
|
def check_and_convert_to_indices(
|
|
@@ -89,8 +92,7 @@ def get_default_indices(
|
|
|
89
92
|
indexable_options: Sequence[T], default: Sequence[Any] | Any | None = None
|
|
90
93
|
) -> list[int]:
|
|
91
94
|
default_indices = check_and_convert_to_indices(indexable_options, default)
|
|
92
|
-
|
|
93
|
-
return default_indices
|
|
95
|
+
return default_indices if default_indices is not None else []
|
|
94
96
|
|
|
95
97
|
|
|
96
98
|
E1 = TypeVar("E1", bound=Enum)
|
|
@@ -102,16 +104,16 @@ _ALLOWED_ENUM_COERCION_CONFIG_SETTINGS = ("off", "nameOnly", "nameAndValue")
|
|
|
102
104
|
def _coerce_enum(from_enum_value: E1, to_enum_class: type[E2]) -> E1 | E2:
|
|
103
105
|
"""Attempt to coerce an Enum value to another EnumMeta.
|
|
104
106
|
|
|
105
|
-
An Enum value of EnumMeta E1 is considered
|
|
107
|
+
An Enum value of EnumMeta E1 is considered coercible to EnumType E2
|
|
106
108
|
if the EnumMeta __qualname__ match and the names of their members
|
|
107
109
|
match as well. (This is configurable in streamlist configs)
|
|
108
110
|
"""
|
|
109
111
|
if not isinstance(from_enum_value, Enum):
|
|
110
|
-
raise ValueError(
|
|
112
|
+
raise ValueError( # noqa: TRY004
|
|
111
113
|
f"Expected an Enum in the first argument. Got {type(from_enum_value)}"
|
|
112
114
|
)
|
|
113
115
|
if not isinstance(to_enum_class, EnumMeta):
|
|
114
|
-
raise ValueError(
|
|
116
|
+
raise ValueError( # noqa: TRY004
|
|
115
117
|
f"Expected an EnumMeta/Type in the second argument. Got {type(to_enum_class)}"
|
|
116
118
|
)
|
|
117
119
|
if isinstance(from_enum_value, to_enum_class):
|
|
@@ -146,7 +148,7 @@ def _coerce_enum(from_enum_value: E1, to_enum_class: type[E2]) -> E1 | E2:
|
|
|
146
148
|
_LOGGER.debug("Failed to coerce %s to class %s", from_enum_value, to_enum_class)
|
|
147
149
|
return from_enum_value # do not attempt to coerce
|
|
148
150
|
|
|
149
|
-
# At this point we think the Enum is
|
|
151
|
+
# At this point we think the Enum is coercible, and we know
|
|
150
152
|
# E1 and E2 have the same member names. We convert from E1 to E2 using _name_
|
|
151
153
|
# (since user Enum subclasses can override the .name property in 3.11)
|
|
152
154
|
_LOGGER.debug("Coerced %s to class %s", from_enum_value, to_enum_class)
|
|
@@ -183,7 +185,11 @@ def maybe_coerce_enum(
|
|
|
183
185
|
) -> RegisterWidgetResult[T]: ...
|
|
184
186
|
|
|
185
187
|
|
|
186
|
-
def maybe_coerce_enum(
|
|
188
|
+
def maybe_coerce_enum(
|
|
189
|
+
register_widget_result: RegisterWidgetResult[Any],
|
|
190
|
+
options: OptionSequence[Any],
|
|
191
|
+
opt_sequence: Sequence[Any],
|
|
192
|
+
) -> RegisterWidgetResult[Any]:
|
|
187
193
|
"""Maybe Coerce a RegisterWidgetResult with an Enum member value to
|
|
188
194
|
RegisterWidgetResult[option] if option is an EnumType, otherwise just return
|
|
189
195
|
the original RegisterWidgetResult.
|
|
@@ -225,7 +231,11 @@ def maybe_coerce_enum_sequence(
|
|
|
225
231
|
) -> RegisterWidgetResult[tuple[T, T]]: ...
|
|
226
232
|
|
|
227
233
|
|
|
228
|
-
def maybe_coerce_enum_sequence(
|
|
234
|
+
def maybe_coerce_enum_sequence(
|
|
235
|
+
register_widget_result: RegisterWidgetResult[list[Any] | tuple[Any, ...]],
|
|
236
|
+
options: OptionSequence[Any],
|
|
237
|
+
opt_sequence: Sequence[Any],
|
|
238
|
+
) -> RegisterWidgetResult[list[Any] | tuple[Any, ...]]:
|
|
229
239
|
"""Maybe Coerce a RegisterWidgetResult with a sequence of Enum members as value
|
|
230
240
|
to RegisterWidgetResult[Sequence[option]] if option is an EnumType, otherwise just
|
|
231
241
|
return the original RegisterWidgetResult.
|
|
@@ -26,6 +26,8 @@ if TYPE_CHECKING:
|
|
|
26
26
|
|
|
27
27
|
from streamlit.proto.Arrow_pb2 import Arrow as ArrowProto
|
|
28
28
|
|
|
29
|
+
from enum import Enum
|
|
30
|
+
|
|
29
31
|
|
|
30
32
|
def marshall_styler(proto: ArrowProto, styler: Styler, default_uuid: str) -> None:
|
|
31
33
|
"""Marshall pandas.Styler into an Arrow proto.
|
|
@@ -196,27 +198,24 @@ def _pandas_style_to_css(
|
|
|
196
198
|
|
|
197
199
|
# In pandas >= 1.1.0
|
|
198
200
|
# translated_style["cellstyle"] has the following shape:
|
|
199
|
-
# [
|
|
200
|
-
# {
|
|
201
|
-
# "props": [("color", " black"), ("background-color", "orange"), ("", "")],
|
|
202
|
-
# "selectors": ["row0_col0"]
|
|
203
|
-
# }
|
|
204
|
-
# ...
|
|
205
|
-
# ]
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
selectors.append(table_selector + separator + cell_selector)
|
|
201
|
+
# > [
|
|
202
|
+
# > {
|
|
203
|
+
# > "props": [("color", " black"), ("background-color", "orange"), ("", "")],
|
|
204
|
+
# > "selectors": ["row0_col0"]
|
|
205
|
+
# > }
|
|
206
|
+
# > ...
|
|
207
|
+
# > ]
|
|
208
|
+
cell_selectors = (
|
|
209
|
+
[style["selector"]] if style_type == "table_styles" else style["selectors"]
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
selectors = [
|
|
213
|
+
table_selector + separator + cell_selector for cell_selector in cell_selectors
|
|
214
|
+
]
|
|
214
215
|
selector = ", ".join(selectors)
|
|
215
216
|
|
|
216
217
|
declaration_block = "; ".join(declarations)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return rule_set
|
|
218
|
+
return selector + " { " + declaration_block + " }"
|
|
220
219
|
|
|
221
220
|
|
|
222
221
|
def _marshall_display_values(
|
|
@@ -266,9 +265,14 @@ def _use_display_values(df: DataFrame, styles: Mapping[str, Any]) -> DataFrame:
|
|
|
266
265
|
rows = styles["body"]
|
|
267
266
|
for row in rows:
|
|
268
267
|
for cell in row:
|
|
269
|
-
if "id" in cell:
|
|
270
|
-
|
|
271
|
-
|
|
268
|
+
if "id" in cell and (match := cell_selector_regex.match(cell["id"])):
|
|
269
|
+
r, c = map(int, match.groups())
|
|
270
|
+
# Check if the display value is an Enum type. Enum values need to be
|
|
271
|
+
# converted to their `.value` attribute to ensure proper serialization
|
|
272
|
+
# and display logic.
|
|
273
|
+
if isinstance(cell["display_value"], Enum):
|
|
274
|
+
new_df.iloc[r, c] = str(cell["display_value"].value)
|
|
275
|
+
else:
|
|
272
276
|
new_df.iloc[r, c] = str(cell["display_value"])
|
|
273
277
|
|
|
274
278
|
return new_df
|
|
@@ -97,7 +97,7 @@ def check_session_state_rules(
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
class CachedWidgetWarning(StreamlitAPIWarning):
|
|
100
|
-
def __init__(self):
|
|
100
|
+
def __init__(self) -> None:
|
|
101
101
|
super().__init__(
|
|
102
102
|
"""
|
|
103
103
|
Your script uses a widget command in a cached function
|
|
@@ -126,7 +126,7 @@ def check_cache_replay_rules() -> None:
|
|
|
126
126
|
exception(CachedWidgetWarning())
|
|
127
127
|
|
|
128
128
|
|
|
129
|
-
def check_fragment_path_policy(dg: DeltaGenerator):
|
|
129
|
+
def check_fragment_path_policy(dg: DeltaGenerator) -> None:
|
|
130
130
|
"""Ensures that the current widget is not written outside of the
|
|
131
131
|
fragment's delta path.
|
|
132
132
|
|
|
@@ -168,7 +168,7 @@ def check_widget_policies(
|
|
|
168
168
|
default_value: Sequence[Any] | Any | None = None,
|
|
169
169
|
writes_allowed: bool = True,
|
|
170
170
|
enable_check_callback_rules: bool = True,
|
|
171
|
-
):
|
|
171
|
+
) -> None:
|
|
172
172
|
"""Check all widget policies for the given DeltaGenerator."""
|
|
173
173
|
check_fragment_path_policy(dg)
|
|
174
174
|
check_cache_replay_rules()
|
|
@@ -179,13 +179,14 @@ def check_widget_policies(
|
|
|
179
179
|
)
|
|
180
180
|
|
|
181
181
|
|
|
182
|
-
def maybe_raise_label_warnings(label: str | None, label_visibility: str | None):
|
|
182
|
+
def maybe_raise_label_warnings(label: str | None, label_visibility: str | None) -> None:
|
|
183
183
|
if not label:
|
|
184
184
|
_LOGGER.warning(
|
|
185
185
|
"`label` got an empty value. This is discouraged for accessibility "
|
|
186
186
|
"reasons and may be disallowed in the future by raising an exception. "
|
|
187
187
|
"Please provide a non-empty label and hide it with label_visibility "
|
|
188
|
-
"if needed."
|
|
188
|
+
"if needed.",
|
|
189
|
+
stack_info=True,
|
|
189
190
|
)
|
|
190
191
|
if label_visibility not in ("visible", "hidden", "collapsed"):
|
|
191
192
|
raise errors.StreamlitAPIException(
|
|
@@ -15,6 +15,60 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import contextlib
|
|
18
|
+
from typing import Final
|
|
19
|
+
|
|
20
|
+
# This is the streamlit theme for plotly where we pass in a template.data
|
|
21
|
+
# and a template.layout.
|
|
22
|
+
# Template.data is for changing specific graph properties in a general aspect
|
|
23
|
+
# such as Contour plots or Waterfall plots.
|
|
24
|
+
# Template.layout is for changing things such as the x axis and fonts and other
|
|
25
|
+
# general layout properties for general graphs.
|
|
26
|
+
# We pass in temporary colors to the frontend and the frontend will replace
|
|
27
|
+
# those colors because we want to change colors based on the background color.
|
|
28
|
+
# Start at #0000001 because developers may be likely to use #000000
|
|
29
|
+
CATEGORY_0: Final = "#000001"
|
|
30
|
+
CATEGORY_1: Final = "#000002"
|
|
31
|
+
CATEGORY_2: Final = "#000003"
|
|
32
|
+
CATEGORY_3: Final = "#000004"
|
|
33
|
+
CATEGORY_4: Final = "#000005"
|
|
34
|
+
CATEGORY_5: Final = "#000006"
|
|
35
|
+
CATEGORY_6: Final = "#000007"
|
|
36
|
+
CATEGORY_7: Final = "#000008"
|
|
37
|
+
CATEGORY_8: Final = "#000009"
|
|
38
|
+
CATEGORY_9: Final = "#000010"
|
|
39
|
+
|
|
40
|
+
SEQUENTIAL_0: Final = "#000011"
|
|
41
|
+
SEQUENTIAL_1: Final = "#000012"
|
|
42
|
+
SEQUENTIAL_2: Final = "#000013"
|
|
43
|
+
SEQUENTIAL_3: Final = "#000014"
|
|
44
|
+
SEQUENTIAL_4: Final = "#000015"
|
|
45
|
+
SEQUENTIAL_5: Final = "#000016"
|
|
46
|
+
SEQUENTIAL_6: Final = "#000017"
|
|
47
|
+
SEQUENTIAL_7: Final = "#000018"
|
|
48
|
+
SEQUENTIAL_8: Final = "#000019"
|
|
49
|
+
SEQUENTIAL_9: Final = "#000020"
|
|
50
|
+
|
|
51
|
+
DIVERGING_0: Final = "#000021"
|
|
52
|
+
DIVERGING_1: Final = "#000022"
|
|
53
|
+
DIVERGING_2: Final = "#000023"
|
|
54
|
+
DIVERGING_3: Final = "#000024"
|
|
55
|
+
DIVERGING_4: Final = "#000025"
|
|
56
|
+
DIVERGING_5: Final = "#000026"
|
|
57
|
+
DIVERGING_6: Final = "#000027"
|
|
58
|
+
DIVERGING_7: Final = "#000028"
|
|
59
|
+
DIVERGING_8: Final = "#000029"
|
|
60
|
+
DIVERGING_9: Final = "#000030"
|
|
61
|
+
DIVERGING_10: Final = "#000031"
|
|
62
|
+
|
|
63
|
+
INCREASING: Final = "#000032"
|
|
64
|
+
DECREASING: Final = "#000033"
|
|
65
|
+
TOTAL: Final = "#000034"
|
|
66
|
+
|
|
67
|
+
GRAY_70: Final = "#000036"
|
|
68
|
+
GRAY_90: Final = "#000037"
|
|
69
|
+
BG_COLOR: Final = "#000038"
|
|
70
|
+
FADED_TEXT_05: Final = "#000039"
|
|
71
|
+
BG_MIX: Final = "#000040"
|
|
18
72
|
|
|
19
73
|
|
|
20
74
|
def configure_streamlit_plotly_theme() -> None:
|
|
@@ -27,59 +81,6 @@ def configure_streamlit_plotly_theme() -> None:
|
|
|
27
81
|
import plotly.graph_objects as go
|
|
28
82
|
import plotly.io as pio
|
|
29
83
|
|
|
30
|
-
# This is the streamlit theme for plotly where we pass in a template.data
|
|
31
|
-
# and a template.layout.
|
|
32
|
-
# Template.data is for changing specific graph properties in a general aspect
|
|
33
|
-
# such as Contour plots or Waterfall plots.
|
|
34
|
-
# Template.layout is for changing things such as the x axis and fonts and other
|
|
35
|
-
# general layout properties for general graphs.
|
|
36
|
-
# We pass in temporary colors to the frontend and the frontend will replace
|
|
37
|
-
# those colors because we want to change colors based on the background color.
|
|
38
|
-
# Start at #0000001 because developers may be likely to use #000000
|
|
39
|
-
CATEGORY_0 = "#000001"
|
|
40
|
-
CATEGORY_1 = "#000002"
|
|
41
|
-
CATEGORY_2 = "#000003"
|
|
42
|
-
CATEGORY_3 = "#000004"
|
|
43
|
-
CATEGORY_4 = "#000005"
|
|
44
|
-
CATEGORY_5 = "#000006"
|
|
45
|
-
CATEGORY_6 = "#000007"
|
|
46
|
-
CATEGORY_7 = "#000008"
|
|
47
|
-
CATEGORY_8 = "#000009"
|
|
48
|
-
CATEGORY_9 = "#000010"
|
|
49
|
-
|
|
50
|
-
SEQUENTIAL_0 = "#000011"
|
|
51
|
-
SEQUENTIAL_1 = "#000012"
|
|
52
|
-
SEQUENTIAL_2 = "#000013"
|
|
53
|
-
SEQUENTIAL_3 = "#000014"
|
|
54
|
-
SEQUENTIAL_4 = "#000015"
|
|
55
|
-
SEQUENTIAL_5 = "#000016"
|
|
56
|
-
SEQUENTIAL_6 = "#000017"
|
|
57
|
-
SEQUENTIAL_7 = "#000018"
|
|
58
|
-
SEQUENTIAL_8 = "#000019"
|
|
59
|
-
SEQUENTIAL_9 = "#000020"
|
|
60
|
-
|
|
61
|
-
DIVERGING_0 = "#000021"
|
|
62
|
-
DIVERGING_1 = "#000022"
|
|
63
|
-
DIVERGING_2 = "#000023"
|
|
64
|
-
DIVERGING_3 = "#000024"
|
|
65
|
-
DIVERGING_4 = "#000025"
|
|
66
|
-
DIVERGING_5 = "#000026"
|
|
67
|
-
DIVERGING_6 = "#000027"
|
|
68
|
-
DIVERGING_7 = "#000028"
|
|
69
|
-
DIVERGING_8 = "#000029"
|
|
70
|
-
DIVERGING_9 = "#000030"
|
|
71
|
-
DIVERGING_10 = "#000031"
|
|
72
|
-
|
|
73
|
-
INCREASING = "#000032"
|
|
74
|
-
DECREASING = "#000033"
|
|
75
|
-
TOTAL = "#000034"
|
|
76
|
-
|
|
77
|
-
GRAY_70 = "#000036"
|
|
78
|
-
GRAY_90 = "#000037"
|
|
79
|
-
BG_COLOR = "#000038"
|
|
80
|
-
FADED_TEXT_05 = "#000039"
|
|
81
|
-
BG_MIX = "#000040"
|
|
82
|
-
|
|
83
84
|
# Plotly represents continuous colorscale through an array of pairs.
|
|
84
85
|
# The pair's first index is the starting point and the next pair's first index is the end point.
|
|
85
86
|
# The pair's second index is the starting color and the next pair's second index is the end color.
|