Skip to content

Conversation

@kmcgrady
Copy link
Collaborator

@kmcgrady kmcgrady commented Oct 20, 2025

Describe your changes

Refactored the spinner function to be a mixin class method instead of a standalone function. This change follows the pattern used for other Streamlit elements, making the codebase more consistent.

Key changes:

  • Created a SpinnerMixin class in elements/spinner.py
  • Added the mixin to the DeltaGenerator class
  • Updated imports in __init__.py to expose the spinner function from _main instead of directly from the elements module
  • Updated references to the spinner function in cache_utils.py and tests

GitHub Issue Link (if applicable)

Testing Plan

  • No additional tests needed as this is a refactoring that preserves existing functionality
  • All existing spinner tests have been updated to use the new implementation and continue to pass
  • The functionality remains identical, just the implementation structure has changed

Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

@snyk-io
Copy link
Contributor

snyk-io bot commented Oct 20, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 20, 2025

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-12829/streamlit-1.51.0-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts
🕹️ Preview app pr-12829.streamlit.app (☁️ Deploy here if not accessible)

@github-actions
Copy link
Contributor

github-actions bot commented Oct 20, 2025

📉 Frontend coverage change detected

The frontend unit test (vitest) coverage has decreased by 0.0000%

  • Current PR: 89.2300% (51657 lines, 5561 missed)
  • Latest develop: 89.2300% (51657 lines, 5561 missed)

✅ Coverage change is within normal range.

📊 View detailed coverage comparison

@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from 1af2b5d to cd702ac Compare October 24, 2025 15:05
@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch from fd2949a to a08f533 Compare October 24, 2025 15:05
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch 2 times, most recently from d65e147 to db19d8c Compare October 24, 2025 16:56
@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch from 25fb3a2 to ab774d5 Compare October 24, 2025 16:56
@github-actions
Copy link
Contributor

github-actions bot commented Oct 24, 2025

📈 Python coverage change detected

The Python unit test coverage has increased by 0.0003%

  • Current PR: 92.8627% (20610 statements, 1471 missed)
  • Latest develop: 92.8623% (20609 statements, 1471 missed)

✅ Coverage change is within normal range.

Coverage by files
Name Stmts Miss Cover
streamlit/__init__.py 142 0 100%
streamlit/__main__.py 3 3 0%
streamlit/auth_util.py 100 25 75%
streamlit/cli_util.py 39 6 85%
streamlit/column_config.py 3 0 100%
streamlit/commands/__init__.py 0 0 100%
streamlit/commands/echo.py 54 11 80%
streamlit/commands/execution_control.py 70 10 86%
streamlit/commands/experimental_query_params.py 40 2 95%
streamlit/commands/logo.py 41 6 85%
streamlit/commands/navigation.py 106 2 98%
streamlit/commands/page_config.py 101 4 96%
streamlit/components/__init__.py 0 0 100%
streamlit/components/lib/__init__.py 0 0 100%
streamlit/components/lib/local_component_registry.py 35 2 94%
streamlit/components/types/__init__.py 0 0 100%
streamlit/components/types/base_component_registry.py 14 0 100%
streamlit/components/types/base_custom_component.py 49 6 88%
streamlit/components/v1/__init__.py 5 0 100%
streamlit/components/v1/component_arrow.py 33 8 76%
streamlit/components/v1/component_registry.py 41 3 93%
streamlit/components/v1/components.py 4 4 0%
streamlit/components/v1/custom_component.py 85 7 92%
streamlit/components/v2/__init__.py 24 0 100%
streamlit/components/v2/bidi_component/__init__.py 4 0 100%
streamlit/components/v2/bidi_component/constants.py 5 0 100%
streamlit/components/v2/bidi_component/main.py 152 17 89%
streamlit/components/v2/bidi_component/serialization.py 81 2 98%
streamlit/components/v2/bidi_component/state.py 13 0 100%
streamlit/components/v2/component_definition_resolver.py 30 0 100%
streamlit/components/v2/component_file_watcher.py 117 9 92%
streamlit/components/v2/component_manager.py 97 13 87%
streamlit/components/v2/component_manifest_handler.py 24 0 100%
streamlit/components/v2/component_path_utils.py 68 5 93%
streamlit/components/v2/component_registry.py 121 8 93%
streamlit/components/v2/get_bidi_component_manager.py 8 1 88%
streamlit/components/v2/manifest_scanner.py 224 25 89%
streamlit/components/v2/presentation.py 84 19 77%
streamlit/components/v2/types.py 8 8 0%
streamlit/config.py 412 12 97%
streamlit/config_option.py 79 3 96%
streamlit/config_util.py 288 7 98%
streamlit/connections/__init__.py 6 0 100%
streamlit/connections/base_connection.py 45 0 100%
streamlit/connections/snowflake_connection.py 60 13 78%
streamlit/connections/snowpark_connection.py 44 3 93%
streamlit/connections/sql_connection.py 56 6 89%
streamlit/connections/util.py 33 0 100%
streamlit/cursor.py 82 2 98%
streamlit/dataframe_util.py 501 47 91%
streamlit/delta_generator.py 209 6 97%
streamlit/delta_generator_singletons.py 70 4 94%
streamlit/deprecation_util.py 59 4 93%
streamlit/development.py 1 0 100%
streamlit/elements/__init__.py 0 0 100%
streamlit/elements/alert.py 60 0 100%
streamlit/elements/arrow.py 201 15 93%
streamlit/elements/balloons.py 10 0 100%
streamlit/elements/bokeh_chart.py 9 0 100%
streamlit/elements/code.py 20 1 95%
streamlit/elements/deck_gl_json_chart.py 104 10 90%
streamlit/elements/dialog_decorator.py 38 0 100%
streamlit/elements/doc_string.py 227 9 96%
streamlit/elements/empty.py 16 4 75%
streamlit/elements/exception.py 101 10 90%
streamlit/elements/form.py 54 2 96%
streamlit/elements/graphviz_chart.py 35 1 97%
streamlit/elements/heading.py 56 0 100%
streamlit/elements/html.py 49 0 100%
streamlit/elements/iframe.py 29 0 100%
streamlit/elements/image.py 32 0 100%
streamlit/elements/json.py 39 2 95%
streamlit/elements/layouts.py 140 3 98%
streamlit/elements/lib/__init__.py 0 0 100%
streamlit/elements/lib/built_in_chart_utils.py 390 26 93%
streamlit/elements/lib/color_util.py 100 4 96%
streamlit/elements/lib/column_config_utils.py 169 1 99%
streamlit/elements/lib/column_types.py 189 4 98%
streamlit/elements/lib/dialog.py 67 1 99%
streamlit/elements/lib/dicttools.py 39 2 95%
streamlit/elements/lib/file_uploader_utils.py 30 0 100%
streamlit/elements/lib/form_utils.py 26 0 100%
streamlit/elements/lib/image_utils.py 176 21 88%
streamlit/elements/lib/js_number.py 28 3 89%
streamlit/elements/lib/layout_utils.py 121 1 99%
streamlit/elements/lib/mutable_status_container.py 73 4 95%
streamlit/elements/lib/options_selector_utils.py 90 0 100%
streamlit/elements/lib/pandas_styler_utils.py 80 2 98%
streamlit/elements/lib/policies.py 56 1 98%
streamlit/elements/lib/shortcut_utils.py 42 2 95%
streamlit/elements/lib/streamlit_plotly_theme.py 49 0 100%
streamlit/elements/lib/subtitle_utils.py 76 13 83%
streamlit/elements/lib/utils.py 76 5 93%
streamlit/elements/map.py 110 1 99%
streamlit/elements/markdown.py 65 2 97%
streamlit/elements/media.py 181 8 96%
streamlit/elements/metric.py 104 0 100%
streamlit/elements/pdf.py 49 2 96%
streamlit/elements/plotly_chart.py 129 6 95%
streamlit/elements/progress.py 36 0 100%
streamlit/elements/pyplot.py 39 2 95%
streamlit/elements/snow.py 10 0 100%
streamlit/elements/space.py 12 0 100%
streamlit/elements/spinner.py 34 0 100%
streamlit/elements/text.py 16 0 100%
streamlit/elements/toast.py 26 0 100%
streamlit/elements/vega_charts.py 228 3 99%
streamlit/elements/widgets/__init__.py 0 0 100%
streamlit/elements/widgets/audio_input.py 68 10 85%
streamlit/elements/widgets/button.py 225 5 98%
streamlit/elements/widgets/button_group.py 171 1 99%
streamlit/elements/widgets/camera_input.py 62 10 84%
streamlit/elements/widgets/chat.py 233 58 75%
streamlit/elements/widgets/checkbox.py 52 0 100%
streamlit/elements/widgets/color_picker.py 59 2 97%
streamlit/elements/widgets/data_editor.py 246 14 94%
streamlit/elements/widgets/file_uploader.py 103 18 83%
streamlit/elements/widgets/multiselect.py 105 4 96%
streamlit/elements/widgets/number_input.py 143 5 97%
streamlit/elements/widgets/radio.py 83 5 94%
streamlit/elements/widgets/select_slider.py 97 0 100%
streamlit/elements/widgets/selectbox.py 91 2 98%
streamlit/elements/widgets/slider.py 241 8 97%
streamlit/elements/widgets/text_widgets.py 130 6 95%
streamlit/elements/widgets/time_widgets.py 390 19 95%
streamlit/elements/write.py 166 32 81%
streamlit/emojis.py 4 0 100%
streamlit/env_util.py 21 3 86%
streamlit/error_util.py 33 2 94%
streamlit/errors.py 194 25 87%
streamlit/external/__init__.py 0 0 100%
streamlit/external/langchain/__init__.py 2 0 100%
streamlit/external/langchain/streamlit_callback_handler.py 141 82 42%
streamlit/file_util.py 84 8 90%
streamlit/git_util.py 100 5 95%
streamlit/logger.py 54 0 100%
streamlit/material_icon_names.py 1 0 100%
streamlit/navigation/__init__.py 0 0 100%
streamlit/navigation/page.py 78 2 97%
streamlit/net_util.py 55 3 95%
streamlit/platform.py 10 1 90%
streamlit/runtime/__init__.py 8 0 100%
streamlit/runtime/app_session.py 460 91 80%
streamlit/runtime/caching/__init__.py 19 0 100%
streamlit/runtime/caching/cache_data_api.py 164 3 98%
streamlit/runtime/caching/cache_errors.py 45 4 91%
streamlit/runtime/caching/cache_resource_api.py 122 0 100%
streamlit/runtime/caching/cache_type.py 11 1 91%
streamlit/runtime/caching/cache_utils.py 165 9 95%
streamlit/runtime/caching/cached_message_replay.py 108 1 99%
streamlit/runtime/caching/hashing.py 311 25 92%
streamlit/runtime/caching/legacy_cache_api.py 14 0 100%
streamlit/runtime/caching/storage/__init__.py 2 0 100%
streamlit/runtime/caching/storage/cache_storage_protocol.py 31 2 94%
streamlit/runtime/caching/storage/dummy_cache_storage.py 21 0 100%
streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py 60 0 100%
streamlit/runtime/caching/storage/local_disk_cache_storage.py 86 4 95%
streamlit/runtime/connection_factory.py 85 9 89%
streamlit/runtime/context.py 140 0 100%
streamlit/runtime/context_util.py 18 0 100%
streamlit/runtime/credentials.py 139 4 97%
streamlit/runtime/download_data_util.py 27 0 100%
streamlit/runtime/forward_msg_cache.py 23 2 91%
streamlit/runtime/forward_msg_queue.py 63 4 94%
streamlit/runtime/fragment.py 112 2 98%
streamlit/runtime/media_file_manager.py 110 7 94%
streamlit/runtime/media_file_storage.py 15 0 100%
streamlit/runtime/memory_media_file_storage.py 68 0 100%
streamlit/runtime/memory_session_storage.py 15 0 100%
streamlit/runtime/memory_uploaded_file_manager.py 41 1 98%
streamlit/runtime/metrics_util.py 193 12 94%
streamlit/runtime/pages_manager.py 59 2 97%
streamlit/runtime/runtime.py 248 18 93%
streamlit/runtime/runtime_util.py 30 1 97%
streamlit/runtime/script_data.py 16 0 100%
streamlit/runtime/scriptrunner/__init__.py 5 0 100%
streamlit/runtime/scriptrunner/exec_code.py 49 5 90%
streamlit/runtime/scriptrunner/magic.py 83 1 99%
streamlit/runtime/scriptrunner/magic_funcs.py 10 1 90%
streamlit/runtime/scriptrunner/script_cache.py 27 0 100%
streamlit/runtime/scriptrunner/script_runner.py 230 27 88%
streamlit/runtime/scriptrunner_utils/__init__.py 0 0 100%
streamlit/runtime/scriptrunner_utils/exceptions.py 11 1 91%
streamlit/runtime/scriptrunner_utils/script_requests.py 106 5 95%
streamlit/runtime/scriptrunner_utils/script_run_context.py 135 2 99%
streamlit/runtime/secrets.py 242 25 90%
streamlit/runtime/session_manager.py 60 1 98%
streamlit/runtime/state/__init__.py 7 0 100%
streamlit/runtime/state/common.py 52 2 96%
streamlit/runtime/state/presentation.py 19 4 79%
streamlit/runtime/state/query_params.py 134 5 96%
streamlit/runtime/state/query_params_proxy.py 71 0 100%
streamlit/runtime/state/safe_session_state.py 77 9 88%
streamlit/runtime/state/session_state.py 433 29 93%
streamlit/runtime/state/session_state_proxy.py 62 8 87%
streamlit/runtime/state/widgets.py 15 1 93%
streamlit/runtime/stats.py 42 0 100%
streamlit/runtime/theme_util.py 46 1 98%
streamlit/runtime/uploaded_file_manager.py 39 3 92%
streamlit/runtime/websocket_session_manager.py 66 0 100%
streamlit/source_util.py 36 1 97%
streamlit/string_util.py 92 8 91%
streamlit/temporary_directory.py 18 1 94%
streamlit/testing/__init__.py 0 0 100%
streamlit/testing/v1/__init__.py 2 0 100%
streamlit/testing/v1/app_test.py 242 6 98%
streamlit/testing/v1/element_tree.py 1371 87 94%
streamlit/testing/v1/local_script_runner.py 71 2 97%
streamlit/testing/v1/util.py 17 0 100%
streamlit/time_util.py 28 1 96%
streamlit/type_util.py 138 12 91%
streamlit/url_util.py 39 5 87%
streamlit/user_info.py 87 8 91%
streamlit/util.py 38 1 97%
streamlit/version.py 3 0 100%
streamlit/watcher/__init__.py 3 0 100%
streamlit/watcher/event_based_path_watcher.py 181 24 87%
streamlit/watcher/folder_black_list.py 14 1 93%
streamlit/watcher/local_sources_watcher.py 127 9 93%
streamlit/watcher/path_watcher.py 43 3 93%
streamlit/watcher/polling_path_watcher.py 55 2 96%
streamlit/watcher/util.py 49 1 98%
streamlit/web/__init__.py 0 0 100%
streamlit/web/bootstrap.py 153 20 87%
streamlit/web/cache_storage_manager_config.py 5 0 100%
streamlit/web/cli.py 186 17 91%
streamlit/web/server/__init__.py 5 0 100%
streamlit/web/server/app_static_file_handler.py 29 3 90%
streamlit/web/server/authlib_tornado_integration.py 18 1 94%
streamlit/web/server/bidi_component_request_handler.py 65 8 88%
streamlit/web/server/browser_websocket_handler.py 115 31 73%
streamlit/web/server/component_file_utils.py 24 0 100%
streamlit/web/server/component_request_handler.py 55 4 93%
streamlit/web/server/media_file_handler.py 65 9 86%
streamlit/web/server/oauth_authlib_routes.py 118 18 85%
streamlit/web/server/oidc_mixin.py 44 0 100%
streamlit/web/server/routes.py 90 7 92%
streamlit/web/server/server.py 188 11 94%
streamlit/web/server/server_util.py 67 5 93%
streamlit/web/server/stats_request_handler.py 53 4 92%
streamlit/web/server/upload_file_request_handler.py 59 14 76%
streamlit/web/server/websocket_headers.py 19 1 95%
TOTAL 20610 1471 93%

📊 View detailed coverage comparison

@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from db19d8c to 3c58aef Compare October 24, 2025 17:47
@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch from ab774d5 to ce454a9 Compare October 24, 2025 17:47
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from 3c58aef to 5c773b0 Compare October 24, 2025 18:40
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch 3 times, most recently from 0879ec2 to 4f097c8 Compare November 4, 2025 00:50
@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch from 98489a8 to 9733c23 Compare November 4, 2025 00:50
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from 4f097c8 to fd93002 Compare November 4, 2025 01:45
@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch 2 times, most recently from 901f681 to a48d051 Compare November 4, 2025 02:00
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from fd93002 to 3f00766 Compare November 4, 2025 02:00
@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch from a48d051 to 652f605 Compare November 4, 2025 02:16
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from 3f00766 to 2df50ee Compare November 4, 2025 02:16
@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch from 652f605 to 79af71b Compare November 5, 2025 03:50
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from 2df50ee to 01f5182 Compare November 5, 2025 03:50
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from 01f5182 to de9041b Compare November 23, 2025 01:50
@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch from 79af71b to 4230417 Compare November 23, 2025 01:50
@github-actions
Copy link
Contributor

📈 Significant wheel size change detected

The wheel file size has increased by 11.37% (threshold: 0.25%)

  • Current PR: 9873.83 KB
  • Latest develop: 8865.57 KB

Please verify this change is expected.

# basically like auto-setting "show_spinner=False" on the @st.cache decorators
# on behalf of the user.
is_nested_cache_function = in_cached_function.get()
import streamlit as st
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe there is was some reason why its cleaner/better to use the delate generator singleton in these situations instead of importing the main st namespace within our commands, e.g.:

from streamlit.delta_generator_singletons import get_dg_singleton_instance

get_dg_singleton_instance().main_dg.spinner(...)
``

Copy link
Contributor

@sfc-gh-kmcgrady sfc-gh-kmcgrady Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I need to worry about the following:

with st.sidebar:
    @st.cache_data(....)
    def ...

This would put the spinner on the main area, right?

Or maybe I am getting confused with the Delta Generator. Let me test

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, tested and it works. I'll update.

# raised by Apache Spark if we do not collect dataframe before
# using `st.cache_data`.)
if is_unevaluated_data_object(computed_value):
from streamlit import type_util
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Whats the reason why this is moved to lazy-loading?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure anymore. I'll revert.

@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch from 4230417 to fc88b4d Compare December 1, 2025 15:28
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from de9041b to ba10df4 Compare December 1, 2025 15:28
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from ba10df4 to e4daf07 Compare December 1, 2025 15:47
@kmcgrady kmcgrady force-pushed the 10-19-implement_visittransientnode_on_rendernodevisitor branch 2 times, most recently from 3ba5eb9 to c7891e9 Compare December 1, 2025 16:55
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from e4daf07 to 44dff07 Compare December 1, 2025 16:55
Base automatically changed from 10-19-implement_visittransientnode_on_rendernodevisitor to develop December 1, 2025 17:38
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from 44dff07 to 04ad86f Compare December 1, 2025 17:39
_main: _DeltaGenerator = _dg_singleton._main_dg
sidebar: _DeltaGenerator = _dg_singleton._sidebar_dg
_event: _DeltaGenerator = _dg_singleton._event_dg
_bottom: _DeltaGenerator = _dg_singleton._bottom_dg
@kmcgrady kmcgrady force-pushed the 10-20-migrate_spinner_to_a_mixin branch from 04ad86f to 406d68b Compare December 1, 2025 18:23
@kmcgrady kmcgrady merged commit 1bfa80f into develop Dec 1, 2025
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:refactor PR contains code refactoring without behavior change impact:internal PR changes only affect internal code security-assessment-completed Security assessment has been completed for PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants