Refactor basic filament button logic - #297
Conversation
28090bb to
579b2af
Compare
579b2af to
de3287c
Compare
gmmcosta15
left a comment
There was a problem hiding this comment.
What's good
- Moves off the
filamentstring onto the typedfilament_posenum. status != GateStatus.EMPTYhas the right polarity:UNKNOWNstays permissive instead of locking the user out.current_gate_infoalready bounds-checks the gate, so theNoneguard covers bypass/no selection.- Loading the real
devices.amuin the widgets conftest instead of stubbing the enums is the right call, the comparisons need realIntEnumvalues.
1. basicFilamentPanel.py:260-266: FilamentPos.UNKNOWN now resolves to LOADED
UNKNOWN = -1, UNLOADED = 0, and the else branch takes everything that isn't exactly UNLOADED. The old string was tri-state and "Unknown" landed in UNLOADED. Now a freshly booted AMU, or one after MMU_MOTORS_OFF, shows Load disabled and Unload enabled. With no encoder, an eject from an unknown position is the one case worth blocking. FilamentStates.UNKNOWN already exists:
if mmu_state.filament_pos == FilamentPos.UNKNOWN:
self.filament_state = self.FilamentStates.UNKNOWN
elif mmu_state.filament_pos == FilamentPos.UNLOADED:
self.filament_state = self.FilamentStates.UNLOADED
else:
self.filament_state = self.FilamentStates.LOADED2. basicFilamentPanel.py:264: the empty-gate lockout is undone by the next update
setEnabled(status != GateStatus.EMPTY) runs outside the setter, and the setter writes filament_page_load_btn.setEnabled(True) on every UNLOADED transition. on_filament_sensor_update (:145) sets filament_state with no knowledge of the gate, so the next filament_detected=False re-enables Load on an empty gate. Let the setter apply it:
_loaded = update is self.FilamentStates.LOADED
self.filament_page_unload_btn.setEnabled(_loaded or update is self.FilamentStates.UNKNOWN)
self.filament_page_load_btn.setEnabled(not _loaded and self._gate_has_filament)3. basicFilamentPanel.py:265: every intermediate position counts as fully loaded
HOMED_GATE through IN_EXTRUDER (1-9) are mid-move states. Treating them as LOADED makes Unload live while Happy Hare is still driving the gear, and an MMU_EJECT then collides with a move already in progress. Gate the buttons on the MMU being idle too:
_busy = bool(mmu_state.operation) or mmu_state.action not in ("", "Idle")
self.filament_page_unload_btn.setEnabled(not _busy and _loaded)4. tests/widgets/conftest.py:16-24: the eviction list stops one level short
devices and devices.amu are popped but devices.amu.models, the module basicFilamentPanel imports, is not. tests/panels/conftest.py installs fakes with no teardown, so in a shared xdist worker FilamentPos/GateStatus come back as MagicMocks:
"devices", "devices.amu", "devices.amu.models",Minor
-
basicFilamentPanel.py:261-264: the gate lookup reads better as a property next tofilament_state, and item 2 needs it (storemmu_stateasself._mmu_state):
@property
def _gate_has_filament(self) -> bool:
_gate = self._mmu_state.current_gate_info if self._mmu_state else None
return _gate is None or _gate.status != GateStatus.EMPTY-
tests/widgets/conftest.py:26-39: three near-identical module shims, a loop keeps the next one from being a fourth:
for _name, _parts in (("lib", ("lib",)), ("devices", ("devices",)), ("devices.amu", ("devices", "amu"))):
_m = types.ModuleType(_name)
_m.__path__ = [str(_project_root.joinpath("BlocksScreen", *_parts))]
_m.__package__ = _name
sys.modules[_name] = _m
Description
BlocksScreen/lib/panels/widgets/basicFilamentPanel.py