streamlit 1.49.1__py3-none-any.whl → 1.51.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 +4 -1
- streamlit/column_config.py +2 -0
- streamlit/commands/navigation.py +7 -7
- streamlit/commands/page_config.py +4 -6
- streamlit/components/v1/custom_component.py +17 -42
- streamlit/components/v2/__init__.py +458 -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 +386 -0
- streamlit/components/v2/bidi_component/serialization.py +265 -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 +431 -0
- streamlit/components/v2/component_manifest_handler.py +122 -0
- streamlit/components/v2/component_path_utils.py +245 -0
- streamlit/components/v2/component_registry.py +409 -0
- streamlit/components/v2/get_bidi_component_manager.py +51 -0
- streamlit/components/v2/manifest_scanner.py +615 -0
- streamlit/components/v2/presentation.py +198 -0
- streamlit/components/v2/types.py +324 -0
- streamlit/config.py +741 -32
- streamlit/config_option.py +4 -1
- streamlit/config_util.py +650 -1
- streamlit/connections/base_connection.py +4 -2
- streamlit/dataframe_util.py +18 -10
- streamlit/delta_generator.py +8 -7
- streamlit/delta_generator_singletons.py +3 -1
- streamlit/deprecation_util.py +17 -6
- streamlit/elements/arrow.py +90 -42
- streamlit/elements/deck_gl_json_chart.py +98 -39
- streamlit/elements/dialog_decorator.py +2 -1
- streamlit/elements/exception.py +3 -1
- streamlit/elements/form.py +6 -6
- streamlit/elements/graphviz_chart.py +24 -9
- streamlit/elements/heading.py +3 -5
- streamlit/elements/iframe.py +0 -2
- streamlit/elements/image.py +12 -13
- streamlit/elements/layouts.py +89 -22
- streamlit/elements/lib/built_in_chart_utils.py +95 -31
- streamlit/elements/lib/color_util.py +8 -18
- streamlit/elements/lib/column_config_utils.py +9 -8
- streamlit/elements/lib/column_types.py +595 -148
- streamlit/elements/lib/dialog.py +3 -2
- streamlit/elements/lib/image_utils.py +3 -5
- streamlit/elements/lib/layout_utils.py +50 -13
- streamlit/elements/lib/mutable_status_container.py +2 -2
- streamlit/elements/lib/options_selector_utils.py +2 -2
- streamlit/elements/lib/pandas_styler_utils.py +30 -14
- streamlit/elements/lib/utils.py +21 -9
- streamlit/elements/map.py +81 -40
- streamlit/elements/media.py +7 -7
- streamlit/elements/metric.py +11 -35
- streamlit/elements/pdf.py +2 -4
- streamlit/elements/plotly_chart.py +142 -26
- streamlit/elements/progress.py +2 -4
- streamlit/elements/pyplot.py +6 -6
- streamlit/elements/space.py +113 -0
- streamlit/elements/vega_charts.py +400 -143
- streamlit/elements/widgets/audio_input.py +52 -4
- streamlit/elements/widgets/button.py +29 -29
- streamlit/elements/widgets/button_group.py +33 -6
- streamlit/elements/widgets/camera_input.py +3 -4
- streamlit/elements/widgets/chat.py +7 -0
- streamlit/elements/widgets/checkbox.py +1 -0
- streamlit/elements/widgets/color_picker.py +1 -0
- streamlit/elements/widgets/data_editor.py +34 -29
- streamlit/elements/widgets/file_uploader.py +6 -10
- streamlit/elements/widgets/multiselect.py +14 -3
- streamlit/elements/widgets/number_input.py +5 -4
- streamlit/elements/widgets/radio.py +10 -2
- streamlit/elements/widgets/select_slider.py +8 -4
- streamlit/elements/widgets/selectbox.py +9 -2
- streamlit/elements/widgets/slider.py +38 -41
- streamlit/elements/widgets/text_widgets.py +6 -0
- streamlit/elements/widgets/time_widgets.py +15 -12
- streamlit/elements/write.py +28 -23
- streamlit/emojis.py +1 -1
- streamlit/errors.py +115 -0
- streamlit/git_util.py +65 -43
- streamlit/hello/hello.py +8 -0
- streamlit/hello/utils.py +2 -1
- streamlit/material_icon_names.py +1 -1
- streamlit/navigation/page.py +4 -1
- streamlit/proto/ArrowData_pb2.py +27 -0
- streamlit/proto/ArrowData_pb2.pyi +46 -0
- streamlit/proto/Arrow_pb2.py +10 -8
- streamlit/proto/Arrow_pb2.pyi +31 -2
- streamlit/proto/AudioInput_pb2.py +2 -2
- streamlit/proto/AudioInput_pb2.pyi +6 -2
- streamlit/proto/BidiComponent_pb2.py +34 -0
- streamlit/proto/BidiComponent_pb2.pyi +153 -0
- streamlit/proto/Block_pb2.py +11 -11
- streamlit/proto/Block_pb2.pyi +9 -1
- streamlit/proto/DeckGlJsonChart_pb2.py +10 -4
- streamlit/proto/DeckGlJsonChart_pb2.pyi +9 -3
- streamlit/proto/Element_pb2.py +5 -3
- streamlit/proto/Element_pb2.pyi +14 -4
- streamlit/proto/HeightConfig_pb2.py +2 -2
- streamlit/proto/HeightConfig_pb2.pyi +6 -3
- streamlit/proto/NewSession_pb2.py +18 -16
- streamlit/proto/NewSession_pb2.pyi +158 -6
- streamlit/proto/PlotlyChart_pb2.py +8 -6
- streamlit/proto/PlotlyChart_pb2.pyi +3 -1
- streamlit/proto/Space_pb2.py +27 -0
- streamlit/proto/Space_pb2.pyi +42 -0
- streamlit/proto/WidgetStates_pb2.py +2 -2
- streamlit/proto/WidgetStates_pb2.pyi +13 -3
- streamlit/proto/WidthConfig_pb2.py +2 -2
- streamlit/proto/WidthConfig_pb2.pyi +6 -3
- streamlit/runtime/app_session.py +45 -6
- streamlit/runtime/caching/cache_data_api.py +4 -4
- streamlit/runtime/caching/cache_errors.py +4 -1
- streamlit/runtime/caching/cache_resource_api.py +3 -2
- streamlit/runtime/caching/cache_utils.py +2 -1
- streamlit/runtime/caching/cached_message_replay.py +3 -3
- streamlit/runtime/caching/hashing.py +3 -4
- streamlit/runtime/caching/legacy_cache_api.py +2 -1
- streamlit/runtime/connection_factory.py +1 -3
- streamlit/runtime/forward_msg_queue.py +4 -1
- streamlit/runtime/fragment.py +2 -1
- streamlit/runtime/memory_media_file_storage.py +1 -1
- streamlit/runtime/metrics_util.py +6 -2
- streamlit/runtime/runtime.py +14 -0
- streamlit/runtime/scriptrunner/exec_code.py +2 -1
- streamlit/runtime/scriptrunner/script_runner.py +2 -2
- streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -6
- streamlit/runtime/secrets.py +2 -4
- streamlit/runtime/session_manager.py +3 -1
- streamlit/runtime/state/common.py +30 -5
- streamlit/runtime/state/presentation.py +85 -0
- streamlit/runtime/state/safe_session_state.py +2 -2
- streamlit/runtime/state/session_state.py +220 -16
- streamlit/runtime/state/widgets.py +19 -3
- streamlit/runtime/theme_util.py +148 -0
- streamlit/runtime/websocket_session_manager.py +3 -1
- streamlit/source_util.py +2 -2
- streamlit/static/index.html +2 -2
- streamlit/static/manifest.json +244 -227
- streamlit/static/static/css/{index.C8X8rNzw.css → index.BpABIXK9.css} +1 -1
- streamlit/static/static/css/index.DgR7E2CV.css +1 -0
- streamlit/static/static/js/{ErrorOutline.esm.DcGrhbBP.js → ErrorOutline.esm.YoJdlW1p.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.DgBvV6Pq.js → FileDownload.esm.Ddx8VEYy.js} +1 -1
- streamlit/static/static/js/{FileHelper.M6AAaeuA.js → FileHelper.90EtOmj9.js} +1 -1
- streamlit/static/static/js/{FormClearHelper.DHh1GFzm.js → FormClearHelper.BB1Km6eP.js} +1 -1
- streamlit/static/static/js/InputInstructions.jhH15PqV.js +1 -0
- streamlit/static/static/js/{Particles.DDVT-6Qc.js → Particles.DUsputn1.js} +1 -1
- streamlit/static/static/js/{ProgressBar.BEY0cXXV.js → ProgressBar.DLY8H6nE.js} +2 -2
- streamlit/static/static/js/Toolbar.D8nHCkuz.js +1 -0
- streamlit/static/static/js/{base-input.CK3UVGp1.js → base-input.CJGiNqed.js} +3 -3
- streamlit/static/static/js/{checkbox.D8W881TL.js → checkbox.Cpdd482O.js} +1 -1
- streamlit/static/static/js/{createSuper.B6W-Dh9S.js → createSuper.CuQIogbW.js} +1 -1
- streamlit/static/static/js/data-grid-overlay-editor.2Ufgxc6y.js +1 -0
- streamlit/static/static/js/{downloader.DiKpuU_S.js → downloader.CN0K7xlu.js} +1 -1
- streamlit/static/static/js/{es6.B8zRNPZ-.js → es6.BJcsVXQ0.js} +2 -2
- streamlit/static/static/js/{iframeResizer.contentWindow.DIewJmmh.js → iframeResizer.contentWindow.XzUvQqcZ.js} +1 -1
- streamlit/static/static/js/index.B1ZQh4P1.js +1 -0
- streamlit/static/static/js/index.BKstZk0M.js +27 -0
- streamlit/static/static/js/{index.Bte_9Lyq.js → index.BMcFsUee.js} +1 -1
- streamlit/static/static/js/{index.qhs54UAB.js → index.BR-IdcTb.js} +1 -1
- streamlit/static/static/js/{index.CejBxbg1.js → index.B_dWA3vd.js} +1 -1
- streamlit/static/static/js/{index.D5naqx-J.js → index.BgnZEMVh.js} +1 -1
- streamlit/static/static/js/{index.C7fRKRs4.js → index.BohqXifI.js} +1 -1
- streamlit/static/static/js/{index.cnnXF7xQ.js → index.Br5nxKNj.js} +1 -1
- streamlit/static/static/js/index.BrIKVbNc.js +3 -0
- streamlit/static/static/js/index.BtWUPzle.js +1 -0
- streamlit/static/static/js/index.C0RLraek.js +1 -0
- streamlit/static/static/js/{index.CP5TD2z1.js → index.CAIjskgG.js} +1 -1
- streamlit/static/static/js/{index.CD8HuT3N.js → index.CAj-7vWz.js} +135 -162
- streamlit/static/static/js/{index.DtYN2x4k.js → index.CMtEit2O.js} +1 -1
- streamlit/static/static/js/index.CkRlykEE.js +12 -0
- streamlit/static/static/js/{index.Ts_0SdB9.js → index.CmN3FXfI.js} +2 -2
- streamlit/static/static/js/{index.BnEpvLEz.js → index.CwbFI1_-.js} +1 -1
- streamlit/static/static/js/{index.CcJf6BCU.js → index.CxIUUfab.js} +27 -27
- streamlit/static/static/js/index.D2KPNy7e.js +1 -0
- streamlit/static/static/js/{index.Ch7MBCx0.js → index.D3GPA5k4.js} +47 -47
- streamlit/static/static/js/{index.ho6NIXGl.js → index.DGAh7DMq.js} +1 -1
- streamlit/static/static/js/index.DKb_NvmG.js +197 -0
- streamlit/static/static/js/{index.CvYYtxD_.js → index.DMqgUYKq.js} +1 -1
- streamlit/static/static/js/{index.zecpGxtj.js → index.DOFlg3dS.js} +1 -1
- streamlit/static/static/js/{index.B9mjBcgE.js → index.DPUXkcQL.js} +1 -1
- streamlit/static/static/js/index.DX1xY89g.js +1 -0
- streamlit/static/static/js/index.DYATBCsq.js +2 -0
- streamlit/static/static/js/{index.D2-atlaQ.js → index.DaSmGJ76.js} +3 -3
- streamlit/static/static/js/index.Dd7bMeLP.js +1 -0
- streamlit/static/static/js/{index.4eF4NxG2.js → index.DjmmgI5U.js} +1 -1
- streamlit/static/static/js/index.Dq56CyM2.js +1 -0
- streamlit/static/static/js/index.DuiXaS5_.js +7 -0
- streamlit/static/static/js/index.DvFidMLe.js +2 -0
- streamlit/static/static/js/{index.452cqrrL.js → index.DwkhC5Pc.js} +1 -1
- streamlit/static/static/js/{index.Dk4C7X3i.js → index.Q-3sFn1v.js} +1 -1
- streamlit/static/static/js/{index.CjXWwH-y.js → index.QJ5QO9sJ.js} +1 -1
- streamlit/static/static/js/{index.B6U8LQo3.js → index.VwTaeety.js} +1 -1
- streamlit/static/static/js/index.YOqQbeX8.js +1 -0
- streamlit/static/static/js/{input.nzVJphXi.js → input.D4MN_FzN.js} +1 -1
- streamlit/static/static/js/{memory.CjCgTQz3.js → memory.DrZjtdGT.js} +1 -1
- streamlit/static/static/js/{number-overlay-editor.DaRFzZEO.js → number-overlay-editor.DRwAw1In.js} +1 -1
- streamlit/static/static/js/{possibleConstructorReturn.DgiPnZ9N.js → possibleConstructorReturn.exeeJQEP.js} +1 -1
- streamlit/static/static/js/record.B-tDciZb.js +1 -0
- streamlit/static/static/js/{sandbox.mithfq7Z.js → sandbox.ClO3IuUr.js} +1 -1
- streamlit/static/static/js/{timepicker.Dbl5KFh6.js → timepicker.DAhu-vcF.js} +4 -4
- streamlit/static/static/js/{toConsumableArray.D-Dx88BQ.js → toConsumableArray.DNbljYEC.js} +1 -1
- streamlit/static/static/js/{uniqueId.Bh26R_3S.js → uniqueId.oG4Gvj1v.js} +1 -1
- streamlit/static/static/js/{useBasicWidgetState.DeK-QJpD.js → useBasicWidgetState.D6sOH6oI.js} +1 -1
- streamlit/static/static/js/{useTextInputAutoExpand.4iAdLWD-.js → useTextInputAutoExpand.4u3_GcuN.js} +2 -2
- streamlit/static/static/js/{useUpdateUiValue.CmT7_nJN.js → useUpdateUiValue.F2R3eTeR.js} +1 -1
- streamlit/static/static/js/wavesurfer.esm.vI8Eid4k.js +73 -0
- streamlit/static/static/js/withFullScreenWrapper.zothJIsI.js +1 -0
- streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
- streamlit/string_util.py +56 -1
- streamlit/testing/v1/app_test.py +2 -2
- streamlit/testing/v1/element_tree.py +23 -9
- streamlit/testing/v1/util.py +2 -2
- streamlit/type_util.py +3 -4
- streamlit/url_util.py +1 -3
- streamlit/user_info.py +1 -2
- streamlit/util.py +3 -1
- streamlit/watcher/event_based_path_watcher.py +23 -12
- streamlit/watcher/local_sources_watcher.py +11 -1
- streamlit/watcher/path_watcher.py +9 -6
- streamlit/watcher/polling_path_watcher.py +4 -1
- streamlit/watcher/util.py +2 -2
- streamlit/web/bootstrap.py +0 -31
- streamlit/web/cli.py +51 -22
- streamlit/web/server/bidi_component_request_handler.py +193 -0
- streamlit/web/server/component_file_utils.py +97 -0
- streamlit/web/server/component_request_handler.py +8 -21
- streamlit/web/server/oidc_mixin.py +3 -1
- streamlit/web/server/routes.py +18 -5
- streamlit/web/server/server.py +10 -0
- streamlit/web/server/server_util.py +3 -1
- streamlit/web/server/upload_file_request_handler.py +3 -1
- {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/METADATA +4 -5
- {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/RECORD +238 -209
- streamlit/static/static/css/index.COe1010n.css +0 -1
- streamlit/static/static/js/Hooks.DGu1od_L.js +0 -1
- streamlit/static/static/js/InputInstructions.z6sVgyYt.js +0 -1
- streamlit/static/static/js/Toolbar.DSnK1fUh.js +0 -1
- streamlit/static/static/js/data-grid-overlay-editor.DRTHOydk.js +0 -1
- streamlit/static/static/js/index.BXYmrqnf.js +0 -1
- streamlit/static/static/js/index.B_8AnktO.js +0 -1
- streamlit/static/static/js/index.Bl7zGQSh.js +0 -7
- streamlit/static/static/js/index.BnJIOYn9.js +0 -73
- streamlit/static/static/js/index.C1HcTl5K.js +0 -1
- streamlit/static/static/js/index.C7lSmSOP.js +0 -1
- streamlit/static/static/js/index.C_tmcx4B.js +0 -1
- streamlit/static/static/js/index.D3K5nOu9.js +0 -197
- streamlit/static/static/js/index.DkKT3LUI.js +0 -1
- streamlit/static/static/js/index.MTPPBDHk.js +0 -2
- streamlit/static/static/js/index.pqW9AMJD.js +0 -3
- streamlit/static/static/js/index.urHgTgMQ.js +0 -12
- streamlit/static/static/js/index.wzkv_11M.js +0 -1
- streamlit/static/static/js/index.yF5AncHY.js +0 -1
- streamlit/static/static/js/withFullScreenWrapper.DLp1ENGm.js +0 -1
- streamlit/static/static/media/MaterialSymbols-Rounded.CBxVaFdk.woff2 +0 -0
- {streamlit-1.49.1.data → streamlit-1.51.0.data}/scripts/streamlit.cmd +0 -0
- {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/WHEEL +0 -0
- {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/entry_points.txt +0 -0
- {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/top_level.txt +0 -0
streamlit/errors.py
CHANGED
|
@@ -41,6 +41,17 @@ class CustomComponentError(Error):
|
|
|
41
41
|
pass
|
|
42
42
|
|
|
43
43
|
|
|
44
|
+
class StreamlitComponentRegistryError(Error):
|
|
45
|
+
"""Exceptions raised while discovering or registering Streamlit components.
|
|
46
|
+
|
|
47
|
+
These errors occur during Streamlit startup when scanning installed
|
|
48
|
+
distributions for component metadata and registering them with the component
|
|
49
|
+
registry.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
|
|
44
55
|
class DeprecationError(Error):
|
|
45
56
|
pass
|
|
46
57
|
|
|
@@ -428,6 +439,67 @@ class StreamlitPageNotFoundError(LocalizableStreamlitException):
|
|
|
428
439
|
)
|
|
429
440
|
|
|
430
441
|
|
|
442
|
+
# Bidirectional Components
|
|
443
|
+
class BidiComponentInvalidIdError(LocalizableStreamlitException):
|
|
444
|
+
"""Exception raised when an invalid ID component is provided."""
|
|
445
|
+
|
|
446
|
+
def __init__(self, part: str, delimiter: str) -> None:
|
|
447
|
+
super().__init__(
|
|
448
|
+
"The `{part}` of a bidirectional component's ID must not contain "
|
|
449
|
+
"the delimiter sequence `{delimiter}`.",
|
|
450
|
+
part=part,
|
|
451
|
+
delimiter=delimiter,
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
class BidiComponentMissingContentError(LocalizableStreamlitException):
|
|
456
|
+
"""Exception raised when a component is missing required content."""
|
|
457
|
+
|
|
458
|
+
def __init__(self, component_name: str) -> None:
|
|
459
|
+
super().__init__(
|
|
460
|
+
"Component `{component_name}` must have either JavaScript content "
|
|
461
|
+
"(`js_content` or `js_url`) or HTML content (`html_content`), or both. "
|
|
462
|
+
"Please ensure the component definition includes at least one of these.",
|
|
463
|
+
component_name=component_name,
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
class BidiComponentInvalidCallbackNameError(LocalizableStreamlitException):
|
|
468
|
+
"""Exception raised when a callback with an invalid name is provided."""
|
|
469
|
+
|
|
470
|
+
def __init__(self, callback_name: str) -> None:
|
|
471
|
+
super().__init__(
|
|
472
|
+
"The callback name `'{callback_name}'` is not allowed. "
|
|
473
|
+
"Callback names must follow the pattern `on_{{event_name}}_change` "
|
|
474
|
+
"where `event_name` is not empty.",
|
|
475
|
+
callback_name=callback_name,
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
class BidiComponentInvalidDefaultKeyError(LocalizableStreamlitException):
|
|
480
|
+
"""Exception raised when an invalid key is provided in the default dict."""
|
|
481
|
+
|
|
482
|
+
def __init__(self, state_key: str, available_keys: list[str]) -> None:
|
|
483
|
+
super().__init__(
|
|
484
|
+
"Key `'{state_key}'` in `default` is not a valid state name. "
|
|
485
|
+
"Valid state names are those with corresponding `on_{{state_name}}_change` "
|
|
486
|
+
"callbacks. Available state names: `{available_keys}`",
|
|
487
|
+
state_key=state_key,
|
|
488
|
+
available_keys=available_keys or "none",
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
class BidiComponentUnserializableDataError(LocalizableStreamlitException):
|
|
493
|
+
"""Exception raised when data provided to a bidirectional component cannot be serialized."""
|
|
494
|
+
|
|
495
|
+
def __init__(self) -> None:
|
|
496
|
+
super().__init__(
|
|
497
|
+
"The `data` provided to the bidirectional component could not be serialized. "
|
|
498
|
+
"Please ensure the data is JSON-serializable, or is a supported data structure "
|
|
499
|
+
"like a pandas DataFrame."
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
|
|
431
503
|
# policies
|
|
432
504
|
class StreamlitFragmentWidgetsNotAllowedOutsideError(LocalizableStreamlitException):
|
|
433
505
|
"""Exception raised when the fragment attempts to write to an element outside of its container."""
|
|
@@ -519,6 +591,17 @@ class StreamlitInvalidHeightError(LocalizableStreamlitException):
|
|
|
519
591
|
)
|
|
520
592
|
|
|
521
593
|
|
|
594
|
+
class StreamlitInvalidSizeError(LocalizableStreamlitException):
|
|
595
|
+
"""Exception raised when an invalid size value is provided."""
|
|
596
|
+
|
|
597
|
+
def __init__(self, size: Any) -> None:
|
|
598
|
+
super().__init__(
|
|
599
|
+
"Invalid size value: {size}. Size must be either an integer (pixels), "
|
|
600
|
+
"'stretch', 'small', 'medium', or 'large'.",
|
|
601
|
+
size=repr(size),
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
|
|
522
605
|
class StreamlitValueError(LocalizableStreamlitException):
|
|
523
606
|
"""Exception raised when a value is not valid for a parameter."""
|
|
524
607
|
|
|
@@ -528,3 +611,35 @@ class StreamlitValueError(LocalizableStreamlitException):
|
|
|
528
611
|
parameter=parameter,
|
|
529
612
|
valid_values=", ".join(valid_values),
|
|
530
613
|
)
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
# config
|
|
617
|
+
class StreamlitInvalidThemeError(LocalizableStreamlitException):
|
|
618
|
+
"""Exception raised for general theme errors."""
|
|
619
|
+
|
|
620
|
+
def __init__(self, message: str) -> None:
|
|
621
|
+
super().__init__(
|
|
622
|
+
message,
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
class StreamlitInvalidThemeOptionError(LocalizableStreamlitException):
|
|
627
|
+
"""Exception raised when an invalid theme config option is provided."""
|
|
628
|
+
|
|
629
|
+
def __init__(self, message: str) -> None:
|
|
630
|
+
super().__init__(
|
|
631
|
+
message,
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
class StreamlitInvalidThemeSectionError(LocalizableStreamlitException):
|
|
636
|
+
"""Exception raised when an invalid theme section is provided."""
|
|
637
|
+
|
|
638
|
+
def __init__(self, option_name: str, file_path_or_url: str = "config.toml") -> None:
|
|
639
|
+
super().__init__(
|
|
640
|
+
"Invalid theme section: `{option_name}` found in {file_path_or_url}. "
|
|
641
|
+
"Valid sections are: `theme`, `theme.light`, `theme.dark`, `theme.sidebar`, `theme.light.sidebar`, "
|
|
642
|
+
"and `theme.dark.sidebar`.",
|
|
643
|
+
option_name=option_name,
|
|
644
|
+
file_path_or_url=file_path_or_url,
|
|
645
|
+
)
|
streamlit/git_util.py
CHANGED
|
@@ -16,21 +16,50 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
import os
|
|
18
18
|
import re
|
|
19
|
-
from typing import TYPE_CHECKING, cast
|
|
19
|
+
from typing import TYPE_CHECKING, Final, cast
|
|
20
20
|
|
|
21
21
|
from streamlit import util
|
|
22
|
+
from streamlit.logger import get_logger
|
|
22
23
|
|
|
23
24
|
if TYPE_CHECKING:
|
|
24
25
|
from git import Commit, Remote, RemoteReference, Repo
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
_LOGGER: Final = get_logger(__name__)
|
|
28
|
+
|
|
29
|
+
# Github repo extractor: match owner/repo for https/ssh/scp forms, with optional
|
|
30
|
+
# userinfo/port/trailing slash. This is just to extract the repo name, not validate the URL.
|
|
31
|
+
_GITHUB_URL_PATTERN: Final = re.compile(
|
|
32
|
+
r"github\.com(?::\d+)?[/:]([^/]+)/([^/]+?)(?:\.git)?/?$"
|
|
33
|
+
)
|
|
29
34
|
|
|
30
35
|
# We don't support git < 2.7, because we can't get repo info without
|
|
31
36
|
# talking to the remote server, which results in the user being prompted
|
|
32
37
|
# for credentials.
|
|
33
|
-
|
|
38
|
+
_MIN_GIT_VERSION: Final = (2, 7, 0)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _extract_github_repo_from_url(url: str) -> str | None:
|
|
42
|
+
"""Extract the ``owner/repo`` from a GitHub remote URL.
|
|
43
|
+
|
|
44
|
+
This supports HTTPS and SSH URL forms including optional user info, port,
|
|
45
|
+
trailing slash, and ``.git`` suffix. Validation of the scheme is not
|
|
46
|
+
performed; we only extract if the URL contains ``github.com`` and ends with
|
|
47
|
+
a path of the shape ``owner/repo``.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
url
|
|
52
|
+
The remote URL string.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
str | None
|
|
57
|
+
The extracted ``owner/repo`` if found; otherwise ``None``.
|
|
58
|
+
"""
|
|
59
|
+
match = _GITHUB_URL_PATTERN.search(url.strip())
|
|
60
|
+
if match is None:
|
|
61
|
+
return None
|
|
62
|
+
return f"{match.group(1)}/{match.group(2)}"
|
|
34
63
|
|
|
35
64
|
|
|
36
65
|
class GitRepo:
|
|
@@ -40,6 +69,7 @@ class GitRepo:
|
|
|
40
69
|
# If we have a valid repo, git_version will be a tuple
|
|
41
70
|
# of 3+ ints: (major, minor, patch, possible_additional_patch_number)
|
|
42
71
|
self.git_version: tuple[int, ...] | None = None
|
|
72
|
+
self.module: str = ""
|
|
43
73
|
|
|
44
74
|
try:
|
|
45
75
|
import git
|
|
@@ -47,26 +77,31 @@ class GitRepo:
|
|
|
47
77
|
self.repo = git.Repo(path, search_parent_directories=True)
|
|
48
78
|
self.git_version = self.repo.git.version_info
|
|
49
79
|
|
|
50
|
-
if self.git_version is not None and self.git_version >=
|
|
80
|
+
if self.git_version is not None and self.git_version >= _MIN_GIT_VERSION:
|
|
51
81
|
git_root = self.repo.git.rev_parse("--show-toplevel")
|
|
52
82
|
self.module = os.path.relpath(path, git_root)
|
|
53
83
|
except Exception:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
84
|
+
_LOGGER.debug(
|
|
85
|
+
"Did not find a git repo at %s. This is expected if this isn't a git repo, but could "
|
|
86
|
+
"also fail for other reasons: "
|
|
87
|
+
"1) git binary or GitPython not installed "
|
|
88
|
+
"2) No .git folder "
|
|
89
|
+
"3) Corrupted .git folder "
|
|
90
|
+
"4) Path is invalid.",
|
|
91
|
+
path,
|
|
92
|
+
exc_info=True,
|
|
93
|
+
)
|
|
59
94
|
self.repo = None
|
|
60
95
|
|
|
61
96
|
def __repr__(self) -> str:
|
|
62
97
|
return util.repr_(self)
|
|
63
98
|
|
|
64
99
|
def is_valid(self) -> bool:
|
|
65
|
-
"""True if there's a git repo here, and git.version >=
|
|
100
|
+
"""True if there's a git repo here, and git.version >= _MIN_GIT_VERSION."""
|
|
66
101
|
return (
|
|
67
102
|
self.repo is not None
|
|
68
103
|
and self.git_version is not None
|
|
69
|
-
and self.git_version >=
|
|
104
|
+
and self.git_version >= _MIN_GIT_VERSION
|
|
70
105
|
)
|
|
71
106
|
|
|
72
107
|
@property
|
|
@@ -129,50 +164,37 @@ class GitRepo:
|
|
|
129
164
|
remote_name, *branch = tracking_branch.name.split("/")
|
|
130
165
|
branch_name = "/".join(branch)
|
|
131
166
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return
|
|
137
|
-
|
|
138
|
-
remote_info = self.get_tracking_branch_remote()
|
|
139
|
-
if remote_info is None:
|
|
140
|
-
return False
|
|
141
|
-
|
|
142
|
-
remote, _branch = remote_info
|
|
143
|
-
|
|
144
|
-
for url in remote.urls:
|
|
145
|
-
if (
|
|
146
|
-
re.match(GITHUB_HTTP_URL, url) is not None
|
|
147
|
-
or re.match(GITHUB_SSH_URL, url) is not None
|
|
148
|
-
):
|
|
149
|
-
return True
|
|
150
|
-
|
|
151
|
-
return False
|
|
167
|
+
try:
|
|
168
|
+
return self.repo.remote(remote_name), branch_name
|
|
169
|
+
except Exception:
|
|
170
|
+
_LOGGER.debug("Failed to resolve remote %s", remote_name, exc_info=True)
|
|
171
|
+
return None
|
|
152
172
|
|
|
153
173
|
def get_repo_info(self) -> tuple[str, str, str] | None:
|
|
154
174
|
if not self.is_valid():
|
|
175
|
+
_LOGGER.debug(
|
|
176
|
+
"No valid git information found. Git version: %s", self.git_version
|
|
177
|
+
)
|
|
155
178
|
return None
|
|
156
179
|
|
|
157
180
|
remote_info = self.get_tracking_branch_remote()
|
|
158
181
|
if remote_info is None:
|
|
182
|
+
_LOGGER.debug("No tracking remote branch found for the git repo.")
|
|
159
183
|
return None
|
|
160
184
|
|
|
161
185
|
remote, branch = remote_info
|
|
162
|
-
|
|
186
|
+
remote_urls = list(remote.urls)
|
|
163
187
|
repo = None
|
|
164
|
-
for url in
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if https_matches is not None:
|
|
168
|
-
repo = f"{https_matches.group(2)}/{https_matches.group(3)}"
|
|
169
|
-
break
|
|
170
|
-
|
|
171
|
-
if ssh_matches is not None:
|
|
172
|
-
repo = f"{ssh_matches.group(1)}/{ssh_matches.group(2)}"
|
|
188
|
+
for url in remote_urls:
|
|
189
|
+
repo = _extract_github_repo_from_url(url)
|
|
190
|
+
if repo is not None:
|
|
173
191
|
break
|
|
174
192
|
|
|
175
193
|
if repo is None:
|
|
194
|
+
_LOGGER.debug(
|
|
195
|
+
"Unable to determine repo name from configured remote URLs. URLs: %s",
|
|
196
|
+
remote_urls,
|
|
197
|
+
)
|
|
176
198
|
return None
|
|
177
199
|
|
|
178
200
|
return repo, branch, self.module
|
streamlit/hello/hello.py
CHANGED
|
@@ -36,3 +36,11 @@ st.write(
|
|
|
36
36
|
- Explore a [New York City rideshare dataset](https://github.com/streamlit/demo-uber-nyc-pickups)
|
|
37
37
|
"""
|
|
38
38
|
)
|
|
39
|
+
|
|
40
|
+
# Preload Python modules that take a while to compile in a new venv.
|
|
41
|
+
# Otherwise, when users switch to another page, it seems that Streamlit
|
|
42
|
+
# is slow, when in reality this is just an artifact of loading/compiling
|
|
43
|
+
# large modules from zero.
|
|
44
|
+
with st.spinner("Preloading Python modules for other pages..."):
|
|
45
|
+
import numpy # noqa: ICN001 F401
|
|
46
|
+
import pandas # noqa: ICN001 F401
|