CarlyneB commited on
Commit
396f68b
·
1 Parent(s): 43a73a8

[REFACTOR] tab2: extract refresh_active_methods from _sync_constraint_widgets so it can be called without visiting Tab 2

Browse files
Files changed (1) hide show
  1. tabs/tab2_constraints.py +45 -16
tabs/tab2_constraints.py CHANGED
@@ -3,7 +3,7 @@ import streamlit as st
3
 
4
  from config.config import CO2_UNIT, method_groups, method_order, method_tooltips, secondary_resources, hidden_resource_names
5
  from utils.ui_helpers import show_bar
6
- from utils.data_utils import strip_unit_suffix, is_other_method, get_other_method_variants, make_variant_name, default_constraint
7
 
8
 
9
  def _make_slider_cb(m):
@@ -385,30 +385,37 @@ def build_summary_df():
385
 
386
 
387
 
388
- def _sync_constraint_widgets(cost_sliders_norm):
389
- """Drive all constraint widget keys from the constraint dict before any widget is drawn.
390
 
391
- Two modes:
392
- - force mode: after a file/scenario load (constraints_just_loaded flag) or for
393
- freshly activated methods (just_activated_methods). All keys are set
394
- unconditionally from the constraint.
395
- - normal mode: setdefault only; never overrides a value the user already set.
 
 
 
 
 
 
 
396
 
397
  Args:
398
- cost_sliders_norm (dict): {method: {resource: {min, median, max}}} with unit suffixes stripped.
 
399
 
400
  Returns:
401
- None
402
  """
403
- just_loaded = st.session_state.pop("constraints_just_loaded", False)
404
- just_activated = st.session_state.pop("just_activated_methods", set())
405
  auto_disabled = st.session_state.get("auto_disabled_methods", set())
 
406
 
407
  for m, c in st.session_state.constraints.items():
408
  if get_all_missing_required(m, cost_sliders_norm):
409
  st.session_state.constraints[m]["active"] = False
410
- # Keep the method in auto_disabled so apply_auto_disable_logic can
411
- # re-enable it (and fire just_activated) once the resource is added.
412
  auto_disabled.add(m)
413
  st.session_state.pop(f"toggle_{m}", None)
414
  st.session_state.pop(f"cap_type_{m}", None)
@@ -421,6 +428,30 @@ def _sync_constraint_widgets(cost_sliders_norm):
421
  auto_disabled.discard(m)
422
  just_activated.add(m)
423
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
  force = just_loaded or (m in just_activated)
425
  if c["active"]:
426
  cap_type = c.get("cap_type", "percent")
@@ -457,8 +488,6 @@ def _sync_constraint_widgets(cost_sliders_norm):
457
  st.session_state.pop(f"slider_{m}", None)
458
  st.session_state.pop(f"manual_{m}", None)
459
 
460
- st.session_state["auto_disabled_methods"] = auto_disabled
461
-
462
 
463
  def render_constraints_summary():
464
  """Render the summary dataframe of active methods and their caps.
 
3
 
4
  from config.config import CO2_UNIT, method_groups, method_order, method_tooltips, secondary_resources, hidden_resource_names
5
  from utils.ui_helpers import show_bar
6
+ from utils.data_utils import strip_unit_suffix, get_other_method_variants, make_variant_name, default_constraint
7
 
8
 
9
  def _make_slider_cb(m):
 
385
 
386
 
387
 
388
+ def refresh_active_methods(cost_sliders_norm):
389
+ """Auto-activate/deactivate methods based on real resource availability.
390
 
391
+ A method is auto-deactivated when it's missing a required resource, and
392
+ auto-reactivated (only if it was previously auto-deactivated, not
393
+ manually turned off by the user) once that resource becomes available
394
+ again.
395
+
396
+ This must run on every app render — not just when Tab 2 itself draws —
397
+ otherwise a user who goes straight from Tab 1 to Tab 3/4/5 without
398
+ visiting Tab 2 first finds every method stuck at its initial
399
+ "active: False" state (set once at app startup), and the optimisation
400
+ fails with "No active methods" despite correctly configured resources.
401
+ Call this from app.py's shared init in addition to Tab 2's own
402
+ _sync_constraint_widgets (which calls it too, for its widget-key sync).
403
 
404
  Args:
405
+ cost_sliders_norm (dict): {method: {resource: {min, median, max}}} with
406
+ unit suffixes stripped.
407
 
408
  Returns:
409
+ set[str]: method names that were just (re)activated by this call.
410
  """
 
 
411
  auto_disabled = st.session_state.get("auto_disabled_methods", set())
412
+ just_activated = set()
413
 
414
  for m, c in st.session_state.constraints.items():
415
  if get_all_missing_required(m, cost_sliders_norm):
416
  st.session_state.constraints[m]["active"] = False
417
+ # Keep the method in auto_disabled so it gets re-enabled (and
418
+ # fires just_activated) once the resource is added.
419
  auto_disabled.add(m)
420
  st.session_state.pop(f"toggle_{m}", None)
421
  st.session_state.pop(f"cap_type_{m}", None)
 
428
  auto_disabled.discard(m)
429
  just_activated.add(m)
430
 
431
+ st.session_state["auto_disabled_methods"] = auto_disabled
432
+ return just_activated
433
+
434
+
435
+ def _sync_constraint_widgets(cost_sliders_norm):
436
+ """Drive all constraint widget keys from the constraint dict before any widget is drawn.
437
+
438
+ Two modes:
439
+ - force mode: after a file/scenario load (constraints_just_loaded flag) or for
440
+ freshly activated methods (just_activated_methods). All keys are set
441
+ unconditionally from the constraint.
442
+ - normal mode: setdefault only; never overrides a value the user already set.
443
+
444
+ Args:
445
+ cost_sliders_norm (dict): {method: {resource: {min, median, max}}} with unit suffixes stripped.
446
+
447
+ Returns:
448
+ None
449
+ """
450
+ just_loaded = st.session_state.pop("constraints_just_loaded", False)
451
+ just_activated = st.session_state.pop("just_activated_methods", set())
452
+ just_activated |= refresh_active_methods(cost_sliders_norm)
453
+
454
+ for m, c in st.session_state.constraints.items():
455
  force = just_loaded or (m in just_activated)
456
  if c["active"]:
457
  cap_type = c.get("cap_type", "percent")
 
488
  st.session_state.pop(f"slider_{m}", None)
489
  st.session_state.pop(f"manual_{m}", None)
490
 
 
 
491
 
492
  def render_constraints_summary():
493
  """Render the summary dataframe of active methods and their caps.