Skip to content

support flag parameters without valuesAllow flags to work with only key names, omitting values.#391

Open
hjn0415a wants to merge 1 commit into
OpenMS:mainfrom
hjn0415a:feature/flag-parameter
Open

support flag parameters without valuesAllow flags to work with only key names, omitting values.#391
hjn0415a wants to merge 1 commit into
OpenMS:mainfrom
hjn0415a:feature/flag-parameter

Conversation

@hjn0415a
Copy link
Copy Markdown

@hjn0415a hjn0415a commented May 19, 2026

Changes

Tool instance-aware parameter lookup

  • Added optional tool_instance_name parameter to CommandExecutor.run_topp
  • Allows parameter lookup from params.json using instance-specific keys
  • Supports workflows containing multiple instances of the same TOPP tool

Boolean parameter handling

  • Added bool_param_paths_from_param_xml_ini() utility to parse boolean parameters from TOPP .ini files
  • Boolean parameters are now passed as valueless CLI flags (-flag) instead of -flag true
  • Added caching of bool parameter metadata in Streamlit session state

ParameterManager improvements

  • Added bool parameter tracking and merging from generated .ini files
  • create_ini() now automatically registers bool parameter metadata

Summary by CodeRabbit

  • New Features

    • Boolean parameters in workflow commands now use flag-based syntax for improved command clarity
    • Tool instances can now be explicitly named during execution for better traceability
  • Chores

    • Updated development environment configuration

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

The PR extends TOPP command generation to properly handle boolean parameters by extracting them from tool .ini XML files and emitting them as CLI flags (e.g., -key without values) instead of key-value pairs. ParameterManager introduces XML parsing and session-state caching; CommandExecutor integrates the cached boolean parameter set into run_topp argument generation. .gitignore is updated to exclude local virtual environments.

Changes

Boolean Parameter Support for TOPP Command Generation

Layer / File(s) Summary
Boolean parameter extraction and session caching
src/workflow/ParameterManager.py
bool_param_paths_from_param_xml_ini parses tool .ini XML to extract type="bool" parameter paths and normalizes them; session-state methods cache boolean parameter pairs; create_ini() merges boolean parameters whenever ini files are created or confirmed.
CommandExecutor boolean flag CLI generation
src/workflow/CommandExecutor.py
run_topp signature updated to accept tool_instance_name; method retrieves cached boolean parameter paths and treats them as on/off flags in CLI argument generation—emitting only -key for enabled booleans and omitting disabled ones.
Development environment config
.gitignore
Adds .venv/ to exclude local Python virtual environment directories.

Possibly related PRs

  • OpenMS/streamlit-template#311: Both PRs modify src/workflow/CommandExecutor.py's parameter emission logic for TOPP commands; PR #311 skips empty/falsy parameters while this PR introduces boolean-flag-specific handling.

Poem

🐰 A rabbit hops through XML trees,
Extracting booleans with such ease,
Flags now flutter without their crew—
just -key when the boolean is true!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding support for boolean flag parameters that work without values (as CLI flags only).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/workflow/CommandExecutor.py (1)

219-248: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

tool_instance_name parameter is declared but never used.

The parameter is documented as enabling lookup from params.json using instance-specific keys, but the method body always uses tool (line 296: if tool in params.keys()). This means the feature for supporting multiple instances of the same TOPP tool won't work as intended.

Likely fix: use tool_instance_name or tool when looking up parameters.

Additionally, static analysis flags two minor issues:

  • custom_params: dict = {} uses a mutable default (B006)
  • tool_instance_name: str = None should be str | None (RUF013)
Proposed fix
-    def run_topp(self, tool: str, input_output: dict, custom_params: dict = {}, tool_instance_name: str = None) -> bool:
+    def run_topp(self, tool: str, input_output: dict, custom_params: dict | None = None, tool_instance_name: str | None = None) -> bool:

And at the start of the method body:

        if custom_params is None:
            custom_params = {}
        param_key = tool_instance_name or tool

Then use param_key instead of tool when accessing params (e.g., line 296).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workflow/CommandExecutor.py` around lines 219 - 248, The run_topp method
currently ignores the tool_instance_name parameter and uses a mutable default
for custom_params and a non-PEP604 union type; fix by normalizing inputs at the
start of run_topp: treat custom_params safely (e.g., if custom_params is None
then set to an empty dict) and compute a lookup key like param_key =
tool_instance_name or tool, then use param_key wherever params are accessed
(e.g., replace checks like if tool in params.keys() with if param_key in
params.keys()); also update the function signature/type-hint to use a
non-mutable default (None) for custom_params and use the union type for
tool_instance_name (str | None).
🧹 Nitpick comments (2)
src/workflow/CommandExecutor.py (1)

298-307: 💤 Low value

Inconsistent handling of boolean parameters with empty string values.

When a boolean parameter has v == "":

  1. Line 299's condition k in topp_bool_flag_param_keys and v != "" is False
  2. It falls through to lines 308-315, which adds -{k} without a value

This means empty-string boolean params emit the flag (enabled behavior), while explicit "false" params are omitted. This may be intentional, but it's inconsistent and could confuse users.

Also, the comment on line 300 appears to have incorrect indentation relative to the code block it describes.

Suggested cleanup
                    if k in topp_bool_flag_param_keys and v != "":
-                    # CLI flag: include "-k" only when enabled
+                        # CLI flag: include "-k" only when enabled
                        if isinstance(v, str):
                            is_enabled = v.lower() == "true"
                        else:
                            is_enabled = bool(v)
                        if is_enabled:
                            command += [f"-{k}"]
                        continue
+                    elif k in topp_bool_flag_param_keys:
+                        # Empty string boolean param: skip entirely (treat as disabled)
+                        continue
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workflow/CommandExecutor.py` around lines 298 - 307, The boolean-flag
handling in CommandExecutor.py around the topp_bool_flag_param_keys check treats
v == "" inconsistently (empty string falls through and emits the flag while
"false" omits it); update the logic that processes topp_bool_flag_param_keys
(the branch that inspects k and v and computes is_enabled) to treat empty-string
values as disabled (i.e., parse v=="" same as false) so flags are only added
when is_enabled is True, and remove the fall-through that adds f"-{k}" for empty
strings; also fix the misplaced/indented comment so it sits directly above the
boolean-flag branch for clarity (referencing variables:
topp_bool_flag_param_keys, k, v, is_enabled, and command).
src/workflow/ParameterManager.py (1)

6-18: ⚡ Quick win

Consider using a hardened XML parser for improved security posture.

Line 17 uses xml.etree.ElementTree to parse .ini files. While these files are currently generated by internal TOPP tools (not untrusted user inputs), using defusedxml would be more robust against potential XXE vulnerabilities. However, note that defusedxml is not currently a project dependency and would need to be added.

-import xml.etree.ElementTree as ET
+from defusedxml import ElementTree as ET

This would require adding defusedxml to the project dependencies.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workflow/ParameterManager.py` around lines 6 - 18, The XML parsing in
bool_param_paths_from_param_xml_ini currently uses xml.etree.ElementTree which
can be vulnerable to XXE; switch to a hardened parser by adding defusedxml to
project dependencies and updating the import/usage to use defusedxml's
ElementTree (e.g. import ElementTree from defusedxml) and replace
ET.parse(ini_path).getroot() in bool_param_paths_from_param_xml_ini with the
defusedxml equivalent so parsing is safe; ensure dependency is added to your
packaging (requirements/pyproject) and run tests to confirm no behavioral
changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/workflow/ParameterManager.py`:
- Around line 90-94: The code currently unions new bool params into the session
set (using bool_pairs_session_key()) causing stale params to persist when a
tool's .ini removes flags; instead, compute the current set of bool pairs for
the given tool by calling bool_param_paths_from_param_xml_ini(ini_path, tool),
remove any existing entries in st.session_state[sk] that belong to this tool
(matching the first element of the tuple), then add the current tuples (tool,
short) or simply replace st.session_state[sk] entries for that tool with the new
ones; update the logic around bool_pairs_session_key(),
bool_param_paths_from_param_xml_ini, ini_path and tool to ensure removal of old
tool-specific entries before adding the fresh list.
- Around line 80-83: The get_bool_param_pairs method currently calls
st.session_state.get(...) which throws RuntimeError outside of a Streamlit
session; guard this call the same way as _merge_bool_params_from_ini does (e.g.,
check for an active session or catch RuntimeError) and return the default empty
set when no session exists; update get_bool_param_pairs to first verify
Streamlit session availability before accessing st.session_state.get using the
same check/pattern used in _merge_bool_params_from_ini so behavior is
consistent.

---

Outside diff comments:
In `@src/workflow/CommandExecutor.py`:
- Around line 219-248: The run_topp method currently ignores the
tool_instance_name parameter and uses a mutable default for custom_params and a
non-PEP604 union type; fix by normalizing inputs at the start of run_topp: treat
custom_params safely (e.g., if custom_params is None then set to an empty dict)
and compute a lookup key like param_key = tool_instance_name or tool, then use
param_key wherever params are accessed (e.g., replace checks like if tool in
params.keys() with if param_key in params.keys()); also update the function
signature/type-hint to use a non-mutable default (None) for custom_params and
use the union type for tool_instance_name (str | None).

---

Nitpick comments:
In `@src/workflow/CommandExecutor.py`:
- Around line 298-307: The boolean-flag handling in CommandExecutor.py around
the topp_bool_flag_param_keys check treats v == "" inconsistently (empty string
falls through and emits the flag while "false" omits it); update the logic that
processes topp_bool_flag_param_keys (the branch that inspects k and v and
computes is_enabled) to treat empty-string values as disabled (i.e., parse v==""
same as false) so flags are only added when is_enabled is True, and remove the
fall-through that adds f"-{k}" for empty strings; also fix the
misplaced/indented comment so it sits directly above the boolean-flag branch for
clarity (referencing variables: topp_bool_flag_param_keys, k, v, is_enabled, and
command).

In `@src/workflow/ParameterManager.py`:
- Around line 6-18: The XML parsing in bool_param_paths_from_param_xml_ini
currently uses xml.etree.ElementTree which can be vulnerable to XXE; switch to a
hardened parser by adding defusedxml to project dependencies and updating the
import/usage to use defusedxml's ElementTree (e.g. import ElementTree from
defusedxml) and replace ET.parse(ini_path).getroot() in
bool_param_paths_from_param_xml_ini with the defusedxml equivalent so parsing is
safe; ensure dependency is added to your packaging (requirements/pyproject) and
run tests to confirm no behavioral changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b3cbb926-c96f-4f75-b3fc-bbd14747b380

📥 Commits

Reviewing files that changed from the base of the PR and between 6ca8e97 and 5dd986b.

📒 Files selected for processing (3)
  • .gitignore
  • src/workflow/CommandExecutor.py
  • src/workflow/ParameterManager.py

Comment on lines +80 to +83
def get_bool_param_pairs(self) -> set:
"""Return the cached set of (tool, param path) bool params; empty set if none."""
return st.session_state.get(self.bool_pairs_session_key(), set())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cat -n src/workflow/ParameterManager.py | head -100

Repository: OpenMS/streamlit-template

Length of output: 4854


🏁 Script executed:

rg "get_bool_param_pairs" --type py -B 3 -A 3

Repository: OpenMS/streamlit-template

Length of output: 665


🏁 Script executed:

rg "get_bool_param_pairs\(\)" --type py

Repository: OpenMS/streamlit-template

Length of output: 51


🏁 Script executed:

find . -type f -name "*.py" | xargs grep -l "get_bool_param_pairs" 2>/dev/null

Repository: OpenMS/streamlit-template

Length of output: 104


🌐 Web query:

Streamlit st.session_state RuntimeError no active session

💡 Result:

Streamlit error “RuntimeError: no active session” (or similarly worded “Session state does not function when running a script without streamlit run”) happens when you access st.session_state outside an active Streamlit runtime session. Most common causes 1) Running the file as a normal Python script - st.session_state only works when the app is started by Streamlit (i.e., via streamlit run ...), because session state is tied to Streamlit’s WebSocket/runtime session. The Streamlit docs explain that session state is for “each user session” and is reset when the WebSocket/session is reset (e.g., refresh/navigation). [1] - If you run your script with python your_script.py, Streamlit emits a warning that session state does not function without streamlit run, followed by failures when you access attributes/keys. [2][3][4] 2) Code path executed during “startup”/external execution (e.g., debugger, background thread, import-time execution) - Community reports show that session state can be “reconstructed cleanly” or lost when code is executed outside the Streamlit-run context (e.g., debugging outside streamlit run). [5] 3) You’re in a session, but the specific key was never initialized yet - If you access a key that hasn’t been set in the current session, you’ll get a “no key … Did you forget to initialize it?” exception; this is separate from “no active session”, but it often appears during first run / first rerender. Initialize with a guard like if 'key' not in st.session_state: .... [1] How to fix A) Ensure you start the app correctly - Start with: - streamlit run path/to/app.py - Do not run with python app.py. This is exactly what the warning and error indicate. [2][4][3] B) Ensure session_state usage happens inside the Streamlit script execution - Avoid accessing/setting st.session_state at module import time if that code may run in a non-Streamlit context. - Avoid accessing session state from code that is executed outside Streamlit’s app lifecycle (e.g., separate background worker that is not managed by Streamlit’s runtime). Session state is tied to the Streamlit session/WebSocket. [1] C) Initialize keys before access - At the top of your app code (inside the Streamlit run), initialize keys before reading them, e.g.: - if 'foo' not in st.session_state: st.session_state['foo'] = default This is the documented initialization pattern. [1] Quick diagnosis checklist - Are you launching the app with streamlit run? If not, that’s the root cause. [2][3][4] - Do you see the warning about “Session state does not function when running a script without streamlit run”? That points directly to an inactive/no-runtime session. [2][6][3] - If you are definitely using streamlit run, check that the access is not happening in code that runs outside Streamlit’s lifecycle, and that you initialize keys with guards. [1][5]

Citations:


Guard get_bool_param_pairs() for non-Streamlit contexts.

The method calls st.session_state.get() which raises RuntimeError when no active Streamlit session exists. Since _merge_bool_params_from_ini() already guards against this case, apply the same pattern for consistency.

🔧 Suggested change
 def get_bool_param_pairs(self) -> set:
     """Return the cached set of (tool, param path) bool params; empty set if none."""
-    return st.session_state.get(self.bool_pairs_session_key(), set())
+    try:
+        return st.session_state.get(self.bool_pairs_session_key(), set())
+    except RuntimeError:
+        return set()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def get_bool_param_pairs(self) -> set:
"""Return the cached set of (tool, param path) bool params; empty set if none."""
return st.session_state.get(self.bool_pairs_session_key(), set())
def get_bool_param_pairs(self) -> set:
"""Return the cached set of (tool, param path) bool params; empty set if none."""
try:
return st.session_state.get(self.bool_pairs_session_key(), set())
except RuntimeError:
return set()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workflow/ParameterManager.py` around lines 80 - 83, The
get_bool_param_pairs method currently calls st.session_state.get(...) which
throws RuntimeError outside of a Streamlit session; guard this call the same way
as _merge_bool_params_from_ini does (e.g., check for an active session or catch
RuntimeError) and return the default empty set when no session exists; update
get_bool_param_pairs to first verify Streamlit session availability before
accessing st.session_state.get using the same check/pattern used in
_merge_bool_params_from_ini so behavior is consistent.

Comment on lines +90 to +94
sk = self.bool_pairs_session_key()
if sk not in st.session_state:
st.session_state[sk] = set()
for short in bool_param_paths_from_param_xml_ini(ini_path, tool):
st.session_state[sk].add((tool, short))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace per-tool bool metadata instead of only unioning.

Lines 93-94 only add entries. If a tool .ini changes during a session, removed bool params remain cached and may be emitted incorrectly as flags.

🔧 Suggested change
             sk = self.bool_pairs_session_key()
             if sk not in st.session_state:
                 st.session_state[sk] = set()
+            st.session_state[sk] = {
+                pair for pair in st.session_state[sk] if pair[0] != tool
+            }
             for short in bool_param_paths_from_param_xml_ini(ini_path, tool):
                 st.session_state[sk].add((tool, short))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/workflow/ParameterManager.py` around lines 90 - 94, The code currently
unions new bool params into the session set (using bool_pairs_session_key())
causing stale params to persist when a tool's .ini removes flags; instead,
compute the current set of bool pairs for the given tool by calling
bool_param_paths_from_param_xml_ini(ini_path, tool), remove any existing entries
in st.session_state[sk] that belong to this tool (matching the first element of
the tuple), then add the current tuples (tool, short) or simply replace
st.session_state[sk] entries for that tool with the new ones; update the logic
around bool_pairs_session_key(), bool_param_paths_from_param_xml_ini, ini_path
and tool to ensure removal of old tool-specific entries before adding the fresh
list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant