-
Notifications
You must be signed in to change notification settings - Fork 4k
[fix] Cache layout_config data and use during replay #12183
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
Conversation
✅ PR preview is ready!
|
🎉 Snyk checks have passed. No issues have been found so far.✅ security/snyk check is complete. No issues have been found. (View Details) ✅ license/snyk check is complete. No issues have been found. (View Details) |
|
|
||
| @st.cache_data | ||
| def cache_code_with_layout(): | ||
| st.code( |
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 debated covering more elements (especially since this is how this gap slipped by originally), but I think it would be excessive. I chose st.code because it has height and width.
| expect(image_element).to_have_attribute("src", image_src or "") | ||
|
|
||
|
|
||
| def test_cached_code_replay(app: Page, assert_snapshot: ImageCompareFunction): |
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.
Adding this with st.code because 1) It has both height and width 2) It doesn't have width/height on it's inner proto like st.video and st.audio.
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 PR fixes a caching issue where layout configurations (width/height) for Streamlit elements were not being preserved during cache replay. Previously, only the inner element proto was cached, causing cached elements to lose their layout styling when replayed.
Key changes:
- Enhanced the caching system to store and replay layout configuration data alongside element protobuf data
- Updated cache replay functionality to apply layout configurations during element reconstruction
- Added comprehensive test coverage for both
@st.cache_dataand@st.cache_resourcedecorators
Reviewed Changes
Copilot reviewed 7 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
cached_message_replay.py |
Added layout_config field to ElementMsgData and updated replay logic to apply layout configurations |
__init__.py |
Updated save_element_message function signature to accept layout_config parameter |
delta_generator.py |
Modified _enqueue method to pass layout_config to caching system |
cache_data_api_test.py |
Added unit tests for layout config preservation during cache replay for @st.cache_data |
cache_resource_api_test.py |
Added unit tests for layout config preservation during cache replay for @st.cache_resource |
st_cache_data.py |
Added cached code element with width/height for e2e testing |
st_cache_data_test.py |
Added e2e test verifying visual consistency of cached elements with layout configs |
| actual_height = element.height_config.pixel_height | ||
| expected_msg = f"Expected {description.lower()} height {expected_height}, got {actual_height}" | ||
| assert actual_height == expected_height, expected_msg | ||
|
|
Copilot
AI
Aug 12, 2025
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.
The _assert_layout_config helper method is duplicated between cache_data_api_test.py and cache_resource_api_test.py with identical implementation. Consider extracting this to a shared test utility module to avoid code duplication.
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.
Might do this. I didn't already because we don't already have a test_utils file for this area and I wasn't sure it completely necessary for just these two tests.
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.
Yeah, I think we could refactor it to shared parameterized replay tests. But also fine to leave it as is.
| code_element = app.get_by_test_id("stCode").first | ||
| expect(code_element).to_be_visible() | ||
|
|
||
| # Test dimensions with snapshots since the width/height is set on the element container. | ||
| assert_snapshot(code_element, name="st_cache_data-st_code_before_caching") | ||
|
|
||
| click_checkbox(app, "Show code") | ||
| expect(code_element).not_to_be_attached() | ||
|
|
||
| click_checkbox(app, "Show code") | ||
| expect(code_element).to_be_visible() | ||
| assert_snapshot(code_element, name="st_cache_data-st_code_after_caching") |
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.
nit: since this test is just about ensuring that width & height are correct, I think we can just do a to_have_css("width", expected_width) here instead of snapshot testing (which is more expansive and easier to miss when updating lots of snapshots).
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.
The stCode element doesn't have the CSS styles, it's on the Element Container. Maybe adding some test utility to get the associated element container is a good idea to reduce some snapshot testing.
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.
Another option would be to get the bounding box, e.g.:
streamlit/e2e_playwright/shared/vega_utils.py
Lines 18 to 26 in 0d8dfa4
| def assert_vega_chart_height(vega_chart: Locator, expected_height: int): | |
| vega_graphics_doc = vega_chart.locator("[role='graphics-document']") | |
| bbox = vega_graphics_doc.bounding_box() | |
| assert bbox is not None | |
| assert round(bbox["height"]) == expected_height | |
| def assert_vega_chart_width(vega_chart: Locator, expected_width: int): |
lukasmasuch
left a comment
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.
LGTM 👍
Describe your changes
While working on width for
st.imageI discovered that since we only cache the inner element proto (e.g. Image.proto, Code.proto), when an element with width/height added in the new style on Element.proto is cached it does not replay with the correct width/height.This PR caches the layout_config as well so that it can be replayed as well.
GitHub Issue Link (if applicable)
Testing Plan
Contribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.