CarlyneB commited on
Commit
43b4d0f
·
1 Parent(s): 2d250c5

[FIX] In the ‘Method Constraints’ tab: Disable and explain methods that require resources not added in the ‘Resource input’ tab

Browse files
Files changed (1) hide show
  1. 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