From 0c6ab2e06e05fd3b0b8aca992ee28325771df098 Mon Sep 17 00:00:00 2001 From: Mirko Holler Date: Sun, 6 Sep 2026 20:14:15 -0300 Subject: [PATCH] fix(vision): declare device_manager explicitly in SampleVisionMonitor The device server's construct_device_obj() only injects device_manager into a device's constructor when that class's own __init__ signature names it explicitly (inspect.signature() doesn't look through **kwargs into a base class). SampleVisionMonitor's __init__ only accepted **kwargs, so self.device_manager was always None once instantiated by the real device server -- resolve_vision_interface() then failed at call time with "device manager is not available", even though unit tests passed (they instantiate the class directly with device_manager=mock as a kwarg, which works either way). Declares device_manager as an explicit keyword and forwards it, matching the working ddg_1.py pattern. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01C9zgK28uPoZWJFkJWV4P1G --- csaxs_bec/devices/vision/sample_vision_monitor.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/csaxs_bec/devices/vision/sample_vision_monitor.py b/csaxs_bec/devices/vision/sample_vision_monitor.py index 6a7d6af4..51e81215 100644 --- a/csaxs_bec/devices/vision/sample_vision_monitor.py +++ b/csaxs_bec/devices/vision/sample_vision_monitor.py @@ -21,7 +21,7 @@ from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase from csaxs_bec.devices.vision import vision_toolkit as vt if TYPE_CHECKING: - from bec_lib.devicemanager import ScanInfo + from bec_lib.devicemanager import DeviceManagerBase, ScanInfo class SampleVisionMonitorError(Exception): @@ -56,6 +56,7 @@ class SampleVisionMonitor(PSIDeviceBase): position_tolerance_px: float | None = None, prefix: str = "", scan_info: "ScanInfo | None" = None, + device_manager: "DeviceManagerBase | None" = None, **kwargs, ): """Initialize the sample vision monitor. @@ -65,6 +66,10 @@ class SampleVisionMonitor(PSIDeviceBase): vision_interface_name (str): Name of the ``VisionInterface`` device this monitor scores against, resolved through the device manager at call time (same lazy-lookup pattern as ``VisionInterface``'s own camera dependency). + device_manager (DeviceManagerBase | None): Device manager, needed to resolve + ``vision_interface_name`` at call time -- must be declared explicitly here (not + just inherited via ``**kwargs``) since the device server only injects it into + classes whose own ``__init__`` signature names it. warp_mode (str | int | None): Which drift between a reference and the current frame ``score()``'s *shape* score should tolerate (register away before comparing contours) rather than count toward the score -- one of ``vision_toolkit.WARP_MODES`` @@ -83,7 +88,9 @@ class SampleVisionMonitor(PSIDeviceBase): at all; a pin/gripper in a different spot is not, by itself, treated as a problem. Runtime-adjustable via :meth:`set_position_tolerance_px`. """ - super().__init__(name=name, prefix=prefix, scan_info=scan_info, **kwargs) + super().__init__( + name=name, prefix=prefix, scan_info=scan_info, device_manager=device_manager, **kwargs + ) self._vision_interface_name = vision_interface_name self._warp_mode = warp_mode self._position_tolerance_px = position_tolerance_px