fix(workflow): stop losing widget input on Streamlit < 1.50 - #31
Merged
Conversation
`_input_widget_impl` fed the persisted parameter back into every widget as
its initial-value argument (`value=` / `default=` / `index=`). On Streamlit
< 1.50 that argument is hashed into the widget's element id, so the id
changed on every interaction; the following interaction then arrived under
the now-stale id and was silently discarded.
The visible effect was in the mzML file selector: selecting six files kept
only three, because every second click was dropped.
Verified against the real `StreamlitUI._input_widget_impl` and
`ParameterManager` on streamlit 1.49.1, the pinned version:
before: 6 clicked -> 3 stick ['A.mzML', 'C.mzML', 'E.mzML']
after: 6 clicked -> 6 stick
Streamlit ignores the initial-value argument once a keyed widget already
has an entry in session state, so seeding on first render only is
behaviour-preserving: `apply_preset()` and `clear_parameter_session_state()`
already delete the session keys when they want params.json to take effect
again. Regression-tested for text, number (int and float), checkbox,
selectbox, slider and multiselect - first-render seeding, reload from
params.json and value type are all unchanged, on both 1.49.1 and 1.53.1.
Also sorts the `select_input_file` options: `path.iterdir()` is unordered,
so both the displayed order and (on < 1.50) the element id varied between
restarts.
Streamlit >= 1.50 stopped hashing `default` into the element id and was
already unaffected; this fix is version-independent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Qn3mLqr7zBr7rgCokx6ku
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
`build-openms` started failing on every branch with:
cmake - cmake not installed. The package was not found with the source(s) listed.
Version was specified as '3.31.1'.
Chocolatey delisted that exact patch: its package listing feed now returns
3.31.6, 3.31.10, 3.31.11 and 3.31.12 for the 3.31 series, but not 3.31.1.
Nothing in this repo changed - the last green run was 2026-08-29.
Moves to 3.31.12, the newest patch in the same minor series, deliberately
staying off cmake 4.x: 4.0 dropped compatibility with
`cmake_minimum_required(VERSION < 3.5)`, which the OpenMS build still relies on.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Qn3mLqr7zBr7rgCokx6ku
…ly bind
The module swapped `sys.modules['streamlit']` for a MagicMock, imported
ParameterManager, restored the real streamlit, and only then dropped the cached
`src.workflow` modules. That ordering is wrong: a module binds `st` once, at
import time, so if any earlier-collected test had already imported
`src.workflow.ParameterManager` against the real streamlit, the import here was
just a cache hit and the mock never took effect.
The result was a test that passed alone and failed in a full run - the six
`TestSaveParametersWithInstanceName` cases asserted against
`mock_streamlit.session_state` while ParameterManager was reading the real one.
Drops the cached modules *before* the import so the mock binds, and again
afterwards so later test files re-import against the real streamlit.
pytest tests/test_results_helpers.py tests/test_tool_instance_name.py
before: 6 failed, 6 passed after: 12 passed
pytest tests/test_workflow_manager_stop.py tests/test_tool_instance_name.py
before: 6 failed, 5 passed after: 11 passed
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Qn3mLqr7zBr7rgCokx6ku
The template sync in #30 restored the template's own `test_gui.py` and two tests aimed at example pages quantms-web deleted long ago, so the `continuous-integration` job has been red on main since 2026-08-29: 34 failed, 89 passed, 4 errors 28 of those failures and all 4 errors were FileNotFoundError for pages that do not exist here - content/documentation.py, content/simple_workflow.py, content/run_subprocess.py, content/topp_workflow_*.py, content/file_upload.py, content/raw_data_viewer.py, content/run_example_workflow.py and content/download_section.py. Rewrites test_gui.py to smoke-test the pages app.py actually registers, the same approach f43b0ad took the last time a sync reintroduced these files, and deletes tests/test_run_subprocess.py and tests/test_simple_workflow.py. Only workflow_fileupload, workflow_configure and workflow_run load standalone; the other 14 call st.page_link and need the navigation context that exists only when app.py runs (loading them directly raises KeyError: 'url_pathname'), so they stay covered indirectly by test_app_loads. Adds test_registered_pages_exist, which parses app.py and asserts every registered page exists on disk - a direct guard against the next sync reintroducing this class of breakage. pytest test_gui.py tests/ before: 34 failed, 89 passed, 4 errors after: 100 passed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Qn3mLqr7zBr7rgCokx6ku
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Selecting multiple mzML files in the workflow configure page silently loses
some of them: select six files, only three stick — every second click is
discarded, and the file visibly pops back out of the box.
Root cause
StreamlitUI._input_widget_implfeeds the persisted parameter back into everywidget as its initial-value argument:
On Streamlit < 1.50 that argument is hashed into the widget's element id
(
compute_and_register_element_id(..., default=default_values, ...)). So eachinteraction changed
default→ changed the element id → the browser's nextinteraction arrived filed under the previous id, the lookup fell through to
the prior run's value, and that interaction was silently dropped.
Streamlit 1.50.0 changed exactly this, with the comment "Treat the provided
key as the main identity. Only include changes to the options, accept_new_options,
and max_selections in the identity computation as those can invalidate the current
selection." —
defaultwas removed from the id. So ≥ 1.50 was never affected.This is not multiselect-specific. On 1.43.0 every widget type hashes its
current value into the id (
text_widgets/checkbox/slider/number_inputhash
value=,selectboxhashesindex=), so the fix is applied uniformly.Fix
Seed a widget only on its first render. Streamlit already ignores the
initial-value argument once a keyed widget has an entry in session state, so
this is behaviour-preserving — it just stops the id from churning:
This is consistent with how the codebase already works:
apply_preset()deletes the affected session keys ("so widgets re-initialize fresh") and
clear_parameter_session_state()exists for the same purpose. Reloading fromparams.jsonstill works because those paths clear session state first.Also sorts the
select_input_fileoptions —path.iterdir()is unordered, soboth the displayed order and (on < 1.50) the element id varied between restarts.
Verification
Driven against the real
StreamlitUI._input_widget_impland the realParameterManager, on streamlit 1.49.1 (the pinned version):Regression-tested across
text,number(int and float),checkbox,selectbox,sliderandmultiselect— first-render seeding, reload fromparams.json, and persisted value type all unchanged, on both 1.49.1 and1.53.1.
Test suite shows no change: failures/errors are byte-identical before and
after the patch (they are pre-existing, from missing example data).
streamlit-templatequantms-webNote on the pin
requirements.txtpinsstreamlit==1.49.1, which is on the affected side ofthe 1.50 boundary — so this bug is live on
maintoday. This fix isversion-independent and does not require bumping the pin, but bumping to
>=1.50would be worthwhile separately as defence in depth.🤖 Generated with Claude Code
https://claude.ai/code/session_016Qn3mLqr7zBr7rgCokx6ku