Spaces:
Sleeping
Sleeping
[FIX] In the ‘Method Constraints’ tab: Disable and explain methods that require resources not added in the ‘Resource input’ tab
Browse files- tabs/tab2_constraints.py +59 -0
tabs/tab2_constraints.py
CHANGED
|
@@ -51,6 +51,49 @@ def get_hidden_resources_for_method(m, method_to_primary_resources, cost_sliders
|
|
| 51 |
return required, optional
|
| 52 |
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
def render_method(m, cols, i, method_to_primary_resources, cost_sliders_norm):
|
| 55 |
"""Render the constraint widget group (toggle + cap slider/input) for one method.
|
| 56 |
|
|
@@ -75,6 +118,22 @@ def render_method(m, cols, i, method_to_primary_resources, cost_sliders_norm):
|
|
| 75 |
toggle_key = f"toggle_{m}"
|
| 76 |
cap_type_key = f"cap_type_{m}"
|
| 77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
was_active = constraint["active"]
|
| 79 |
st.session_state.setdefault(toggle_key, was_active)
|
| 80 |
|
|
|
|
| 51 |
return required, optional
|
| 52 |
|
| 53 |
|
| 54 |
+
def get_uncovered_hidden_resources(m, cost_sliders_norm):
|
| 55 |
+
"""Return (required, optional) hidden resources for method m that leave it unconstrained.
|
| 56 |
+
|
| 57 |
+
A hidden resource is "uncovered" only when the user has provided no resource
|
| 58 |
+
at all from the same group — neither a standard cap (> 0 in tab1) nor a
|
| 59 |
+
custom batch assigned to this method. If at least one standard resource in
|
| 60 |
+
the group has a positive cap, the method is already constrained by it and the
|
| 61 |
+
missing hidden resource does not inflate results.
|
| 62 |
+
|
| 63 |
+
Returns:
|
| 64 |
+
tuple[list[str], list[str]]: (required, optional) uncovered hidden resource names.
|
| 65 |
+
required — must be added for the method to run (not in secondary_resources).
|
| 66 |
+
optional — in secondary_resources, shown as informational only.
|
| 67 |
+
Returns ([], []) when nothing is uncovered.
|
| 68 |
+
"""
|
| 69 |
+
from config.config import resource_groups
|
| 70 |
+
|
| 71 |
+
custom_resources = st.session_state.get("custom_resources", [])
|
| 72 |
+
covered = {b["name"] for b in custom_resources if m in b.get("methods", {})}
|
| 73 |
+
resource_caps = st.session_state.get("resource_caps", {})
|
| 74 |
+
resource_to_group = {r: g for g, resources in resource_groups.items() for r in resources}
|
| 75 |
+
|
| 76 |
+
required, optional = [], []
|
| 77 |
+
for r, coeff_dict in cost_sliders_norm.get(m, {}).items():
|
| 78 |
+
if r not in hidden_resource_names:
|
| 79 |
+
continue
|
| 80 |
+
if coeff_dict.get("median", 0.0) <= 0:
|
| 81 |
+
continue
|
| 82 |
+
if r in covered:
|
| 83 |
+
continue
|
| 84 |
+
group = resource_to_group.get(r)
|
| 85 |
+
group_resources = resource_groups.get(group, []) if group else []
|
| 86 |
+
standard_in_group = [s for s in group_resources if s not in hidden_resource_names]
|
| 87 |
+
any_standard_provided = any(resource_caps.get(s, 0.0) > 0 for s in standard_in_group)
|
| 88 |
+
if any_standard_provided:
|
| 89 |
+
continue
|
| 90 |
+
if (m, r) in secondary_resources:
|
| 91 |
+
optional.append(r)
|
| 92 |
+
else:
|
| 93 |
+
required.append(r)
|
| 94 |
+
return required, optional
|
| 95 |
+
|
| 96 |
+
|
| 97 |
def render_method(m, cols, i, method_to_primary_resources, cost_sliders_norm):
|
| 98 |
"""Render the constraint widget group (toggle + cap slider/input) for one method.
|
| 99 |
|
|
|
|
| 118 |
toggle_key = f"toggle_{m}"
|
| 119 |
cap_type_key = f"cap_type_{m}"
|
| 120 |
|
| 121 |
+
# Check for missing hidden resources BEFORE the toggle widget is
|
| 122 |
+
# instantiated — Streamlit forbids modifying a widget's session-state
|
| 123 |
+
# key after the widget has been created.
|
| 124 |
+
uncovered_required, uncovered_optional = get_uncovered_hidden_resources(m, cost_sliders_norm)
|
| 125 |
+
if uncovered_required:
|
| 126 |
+
st.session_state.constraints[m]["active"] = False
|
| 127 |
+
st.session_state[toggle_key] = False
|
| 128 |
+
st.toggle(m, key=toggle_key, help=tooltip, disabled=True)
|
| 129 |
+
req_list = "\n".join(f"- **{r}** *(required)*" for r in uncovered_required)
|
| 130 |
+
opt_list = "\n".join(f"- **{r}** *(optional)*" for r in uncovered_optional) if uncovered_optional else ""
|
| 131 |
+
body = f"To use this method, add a new resource in the **Resource inputs** tab:\n\n{req_list}"
|
| 132 |
+
if opt_list:
|
| 133 |
+
body += f"\n{opt_list}"
|
| 134 |
+
st.info(body, icon=":material/info:")
|
| 135 |
+
return
|
| 136 |
+
|
| 137 |
was_active = constraint["active"]
|
| 138 |
st.session_state.setdefault(toggle_key, was_active)
|
| 139 |
|