Skip to content

Conversation

@t0mdavid-m
Copy link
Member

@t0mdavid-m t0mdavid-m commented Jan 16, 2026

Add a new conditional_sections parameter to input_TOPP() that allows parameter sections to be shown/hidden based on a controlling parameter's value:

  • Sections are hidden entirely when the controlling parameter doesn't match
  • Sections are shown in an expanded expander when the value matches
  • Supports single values or lists of values for matching
  • Validates that controlling parameters are not inside their controlled sections
  • Supports prefix matching (e.g., "algorithm" controls "algorithm:common")

Example usage:
conditional_sections={ "algorithm:mtd": { "param": "algorithm:common:enable_mtd", "value": "true" } }

Summary by CodeRabbit

  • New Features

    • Added conditional visibility feature for TOPP tool parameter sections, enabling dynamic display or hide based on parameter values.
    • Implemented validation to prevent misconfiguration of section controls.
  • Documentation

    • Added example documentation illustrating conditional section configuration usage.

✏️ Tip: You can customize this high-level summary in your review settings.

Add a new `conditional_sections` parameter to `input_TOPP()` that allows
parameter sections to be shown/hidden based on a controlling parameter's value:

- Sections are hidden entirely when the controlling parameter doesn't match
- Sections are shown in an expanded expander when the value matches
- Supports single values or lists of values for matching
- Validates that controlling parameters are not inside their controlled sections
- Supports prefix matching (e.g., "algorithm" controls "algorithm:common")

Example usage:
  conditional_sections={
      "algorithm:mtd": {
          "param": "algorithm:common:enable_mtd",
          "value": "true"
      }
  }
@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

📝 Walkthrough

Walkthrough

The changes introduce conditional section visibility control to TOPP parameter input handling. A new conditional_sections parameter enables showing/hiding parameter sections based on other parameter values. Implementation includes helper functions to retrieve parameter values, determine section visibility, and validate configuration constraints.

Changes

Cohort / File(s) Summary
Documentation Enhancement
src/Workflow.py
Added detailed code comment illustrating conditional_sections usage for FeatureFinderMetabo TOPP tool, with example showing section visibility tied to parameter matching and constraint clarifications. No functional changes.
Conditional Sections Feature
src/workflow/StreamlitUI.py
Introduced conditional_sections parameter to input_TOPP method. Implemented helper functions (get_param_value, get_controlling_section, should_show_section, get_section_label) for runtime section visibility computation. Added validation to prevent controlling parameters from residing inside controlled sections. Modified section rendering logic for both standard and tabbed layouts to apply conditional display with expander styling. Updated method signature and docstring.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Sections hide and sections show,
When parameters steal the glow,
Controlled visibility, logic so neat,
Makes TOPP parameters skip and fleet!
Conditional magic, now precise and bright— ✨
The workflow interface shines just right!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add collapsible sections to tool parameters' accurately and concisely summarizes the main change: introducing conditional visibility for TOPP parameter sections with collapsible/expander UI elements.

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

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
src/workflow/StreamlitUI.py (1)

535-566: Avoid mutable default for conditional_sections.

A default {} can be shared across calls if mutated (Ruff B006). Prefer None and initialize inside input_TOPP.

♻️ Suggested fix
-from typing import Any, Union, List, Literal
+from typing import Any, Union, List, Literal, Optional
...
-        conditional_sections: dict = {},
+        conditional_sections: Optional[dict] = None,
...
-        if not display_subsections:
+        if conditional_sections is None:
+            conditional_sections = {}
+        if not display_subsections:
             display_subsection_tabs = False

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ab28ad and ac8ca76.

📒 Files selected for processing (2)
  • src/Workflow.py
  • src/workflow/StreamlitUI.py
🧰 Additional context used
🪛 Ruff (0.14.11)
src/workflow/StreamlitUI.py

545-545: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Agent
  • GitHub Check: CodeQL analysis (python)
  • GitHub Check: build-full-app
  • GitHub Check: build-simple-app
  • GitHub Check: build-openms
🔇 Additional comments (4)
src/Workflow.py (1)

40-48: Helpful conditional_sections example.

Clear usage guidance without changing behavior.

src/workflow/StreamlitUI.py (3)

764-778: Good guardrail against self-controlled sections.

This validation prevents invalid configurations early.


873-893: The help parameter is supported in this project's Streamlit version (1.49.1 ≥ 1.21.0 where the parameter was introduced). The code is correct and will not raise a TypeError.


701-763: No changes needed—repository targets Python 3.10+.

The Dockerfile explicitly sets python=3.10, and requirements.txt was compiled with Python 3.12. The type hints using dict | None (PEP 604) and tuple[bool, bool] (PEP 585) are valid and appropriate for the declared minimum version. No migration to Optional[dict] is required.

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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

Copilot AI left a 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 adds a new conditional_sections parameter to the input_TOPP() function that enables dynamic visibility control of parameter sections based on the values of controlling parameters. Sections can be hidden when conditions aren't met or shown in an expanded expander when they are.

Changes:

  • Added conditional_sections parameter to input_TOPP() with validation logic to prevent circular dependencies
  • Implemented section visibility logic with prefix matching support for hierarchical sections
  • Added helper functions for parameter value retrieval, section control checking, and label formatting

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
src/workflow/StreamlitUI.py Added conditional sections feature with validation, visibility control logic, and expander display for controlled sections
src/Workflow.py Added commented example demonstrating usage of the new conditional_sections parameter
Comments suppressed due to low confidence (1)

src/workflow/StreamlitUI.py:659

  • Corrected spelling of 'adavnaced' to 'advanced'.
                # Skip adavnaced parameters if not selected

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +701 to +706
def get_param_value(param_name: str):
"""Get the current value of a parameter by its short name (e.g., 'algorithm:common:param')."""
for p in params:
short_name = p["key"].decode().split(":1:")[1]
if short_name == param_name:
return p["value"]
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The get_param_value function performs a linear search through all parameters each time it's called. This is invoked for every section via should_show_section(). Consider building a parameter lookup dictionary once before the loop to avoid O(n) lookups for each section, especially when there are many sections.

Suggested change
def get_param_value(param_name: str):
"""Get the current value of a parameter by its short name (e.g., 'algorithm:common:param')."""
for p in params:
short_name = p["key"].decode().split(":1:")[1]
if short_name == param_name:
return p["value"]
# Build a lookup table for parameters by their short name to avoid
# repeatedly scanning the full `params` list in get_param_value().
param_lookup: dict[str, dict] = {}
for _p in params:
short_name = _p["key"].decode().split(":1:")[1]
# Preserve previous behavior of returning the first matching entry
# in case of duplicate short names.
if short_name not in param_lookup:
param_lookup[short_name] = _p
def get_param_value(param_name: str):
"""Get the current value of a parameter by its short name (e.g., 'algorithm:common:param')."""
p = param_lookup.get(param_name)
if p is not None:
return p["value"]

Copilot uses AI. Check for mistakes.
Comment on lines +719 to +720
# Check prefix matches (e.g., "algorithm" controls "algorithm:common")
for controlled_section in conditional_sections:
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The prefix matching logic may return the wrong control config when multiple controlled sections share a common prefix. For example, if conditional_sections contains both "algorithm" and "algorithm:common", checking "algorithm:common:param" could match "algorithm" first depending on dictionary iteration order. Consider sorting controlled sections by length in descending order before checking, or use more specific matching logic.

Suggested change
# Check prefix matches (e.g., "algorithm" controls "algorithm:common")
for controlled_section in conditional_sections:
# Check prefix matches (e.g., "algorithm" controls "algorithm:common").
# When multiple keys share a prefix (e.g., "algorithm" and "algorithm:common"),
# prefer the most specific (longest) match by sorting keys by length descending.
for controlled_section in sorted(conditional_sections, key=len, reverse=True):

Copilot uses AI. Check for mistakes.
# Validate that controlling parameters are not inside their controlled sections
if conditional_sections:
for controlled_section, control in conditional_sections.items():
controlling_param = control.get("param", "")
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

If the controlling parameter name is empty (when "param" key is missing from the control dict), controlling_param_section will also be empty, and the validation check on lines 771-772 may not detect all invalid configurations. Consider adding validation to ensure both "param" and "value" keys exist in control configs before proceeding.

Suggested change
controlling_param = control.get("param", "")
# Ensure control config contains required keys
if not isinstance(control, dict) or "param" not in control or "value" not in control:
st.error(
f"Configuration error: Conditional section '{controlled_section}' "
"must define both 'param' and 'value' keys."
)
return
controlling_param = control.get("param")
# controlling_param must be a non-empty string
if not isinstance(controlling_param, str) or not controlling_param.strip():
st.error(
f"Configuration error: Controlling parameter for section "
f"'{controlled_section}' must be a non-empty string."
)
return

Copilot uses AI. Check for mistakes.
Comment on lines +747 to +751

# Check if current value matches any expected value
if current_value in expected_values:
return (True, True) # Show in expander
# Handle string comparison for booleans
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

When current_value is None (parameter not found), the function still converts it to string "none" and checks against expected values. This could lead to unintended matches if "none" or "None" is in the expected values list. Consider explicitly handling the None case before performing comparisons.

Suggested change
# Check if current value matches any expected value
if current_value in expected_values:
return (True, True) # Show in expander
# Handle string comparison for booleans
# If the controlling parameter is not found (None), do not match any expected value
if current_value is None:
return (False, False) # Hide entirely when controlling parameter is missing
# Check if current value matches any expected value
if current_value in expected_values:
return (True, True) # Show in expander
# Handle string comparison for booleans and case-insensitive matches

Copilot uses AI. Check for mistakes.
)
return

def display_TOPP_params(params: dict, num_cols):
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The parameter params is annotated as dict but is actually a list of parameter dictionaries based on how it's called (e.g., section_params on line 878). The type annotation should be list instead of dict.

Suggested change
def display_TOPP_params(params: dict, num_cols):
def display_TOPP_params(params: list[dict[str, Any]], num_cols):

Copilot uses AI. Check for mistakes.
if not section or section == "all":
return "Parameters"
parts = section.split(":")
return ":".join(parts[:-1]) + (":" if len(parts) > 1 else "") + f"**{parts[-1]}**"
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The label formatting logic creates markdown with bold formatting for the last part. However, when there's only one part (len(parts) == 1), it returns **part** without any prefix, but when there are multiple parts, it adds a trailing colon before the bold part. This creates inconsistent formatting. Consider simplifying to always return the formatted string consistently regardless of the number of parts.

Suggested change
return ":".join(parts[:-1]) + (":" if len(parts) > 1 else "") + f"**{parts[-1]}**"
if len(parts) == 1:
# Single-part section: just bold the name
return f"**{parts[0]}**"
# Multi-part section: show prefix, then bold the last part
prefix = ":".join(parts[:-1])
return f"{prefix}:**{parts[-1]}**"

Copilot uses AI. Check for mistakes.
Comment on lines +867 to +871
for section, section_params in param_sections.items():
should_show, use_expander = should_show_section(section)

if not should_show:
continue # Hide section entirely
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The new conditional section visibility logic lacks test coverage. The feature includes multiple code paths (exact match, prefix match, value matching, validation errors) that should be tested to ensure correct behavior, especially the validation logic on lines 765-777 and the section visibility decisions.

Copilot uses AI. Check for mistakes.
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.

3 participants