-
Notifications
You must be signed in to change notification settings - Fork 4k
Add deferred download button #12942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add deferred download button #12942
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ PR preview is ready!
|
📉 Frontend coverage change detectedThe frontend unit test (vitest) coverage has decreased by 0.0400%
💡 Consider adding more unit tests to maintain or improve coverage. |
3b2f517 to
f42ff07
Compare
07190a2 to
72da76d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request adds support for deferred file downloads in Streamlit download buttons. Instead of immediately generating download data when rendering the button, developers can now pass a callable that executes only when the user clicks the download button.
Key Changes:
- Added protobuf messages for deferred file request/response communication between frontend and backend
- Implemented deferred callable storage and execution in
MediaFileManager - Updated download button to accept callables and handle deferred execution flow
- Added frontend support for requesting deferred files and displaying loading/error states
- Created comprehensive unit and e2e tests
Reviewed Changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
proto/streamlit/proto/ForwardMsg.proto |
Added DeferredFileResponse message for server→client responses |
proto/streamlit/proto/BackMsg.proto |
Added DeferredFileRequest message for client→server requests |
proto/streamlit/proto/DownloadButton.proto |
Added fields for deferred file ID and deferred flag |
lib/streamlit/runtime/media_file_manager.py |
Implemented deferred callable storage, execution, and cleanup logic |
lib/streamlit/runtime/app_session.py |
Added handler for deferred file requests |
lib/streamlit/elements/widgets/button.py |
Updated download button to detect and register callables |
lib/tests/streamlit/runtime/media_file_manager_test.py |
Added comprehensive unit tests for deferred functionality |
lib/tests/streamlit/runtime/app_session_test.py |
Added tests for deferred request handling in AppSession |
lib/tests/streamlit/elements/download_button_test.py |
Added tests for callable detection in download buttons |
frontend/app/src/App.tsx |
Implemented request/response handling for deferred files |
frontend/app/src/components/AppView/AppView.tsx |
Passed through requestDeferredFile prop |
frontend/lib/src/components/core/Block/utils.ts |
Added requestDeferredFile to BaseBlockProps |
frontend/lib/src/components/core/Block/ElementNodeRenderer.tsx |
Passed requestDeferredFile to widgets |
frontend/lib/src/components/widgets/DownloadButton/DownloadButton.tsx |
Added loading state, error display, and deferred download handling |
frontend/lib/src/components/widgets/DownloadButton/DownloadButton.test.tsx |
Added comprehensive tests for deferred download scenarios |
e2e_playwright/st_download_button_deferred.py |
Test app demonstrating deferred download functionality |
e2e_playwright/st_download_button_deferred_test.py |
E2E tests for deferred downloads |
9e66c62 to
ed67194
Compare
085941c to
9661b50
Compare
9661b50 to
11b8957
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: We have a test utility renderWithContexts in frontend/lib/src/test_util.tsx that can be updated with the DownloadsContext and used in this test file to help manage the context value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, its okay if the metric is going down a bit as long as we have adequate coverage where it matters
| if (!isDeferred) { | ||
| // Since we use a hidden link to download, we can't use the onerror event | ||
| // to catch src url load errors. Catch with direct check instead. | ||
| void endpoints.checkSourceUrlResponse(downloadUrl, "Download Button") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: We escalate source load errors for metrics through checkSourceUrlResponse - I would think even if the download is deferred we should probably still check/report - will leave to your discretion whether it should happen here or in the error catch below
| export const StyledErrorMessage = styled.small(({ theme }) => ({ | ||
| color: theme.colors.redTextColor, | ||
| fontSize: theme.fontSizes.sm, | ||
| marginTop: theme.spacing.twoXS, | ||
| display: "block", | ||
| })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: did we test that this renders properly in the different button layout scenarios? (ex: when explicit width is specified on the button, "content", & "stretch")
3d3d0ea to
e3ed0a6
Compare
e3ed0a6 to
46413c5
Compare
Describe your changes
Adds support for callable functions in
st.download_buttonto enable deferred/lazy data generation. Data is now generated only when the user clicks the download button, not on every script run.API Addition:
Implementation:
DownloadButtonDataTypeto acceptCallable[[], DownloadButtonDataType]DeferredFileRequest(BackMsg) andDeferredFileResponse(ForwardMsg) messagesadd_deferred()registers callables,execute_deferred()runs them on-demandWhy it works:
GitHub issues
Closes #5053
Testing Plan
Unit Tests:
E2E Tests:
Manual Testing:
streamlit run demo_deferred_download.pyto verify interactive behaviorContribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.