diff --git a/CHANGES.rst b/CHANGES.rst index 54c621a4..fbc4fd89 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -31,6 +31,12 @@ describe future plans. - Add 'dynamic_import()' (support 'ad_creator()' from device file). + Fixes + ----- + + - 'PVPositionerSoftDone' used an invalid subscription event type + in unusual cases (with fake ophyd simulated devices). + Maintenance ----------- diff --git a/apstools/devices/positioner_soft_done.py b/apstools/devices/positioner_soft_done.py index 54367aba..157da42a 100644 --- a/apstools/devices/positioner_soft_done.py +++ b/apstools/devices/positioner_soft_done.py @@ -138,7 +138,10 @@ def __init__( self.readback.subscribe(self.cb_readback) self.setpoint.subscribe(self.cb_setpoint) - self.setpoint.subscribe(self.cb_update_target, event_type="setpoint") + options = {} + if "setpoint" in self.event_types: + options["event_type"] = "setpoint" + self.setpoint.subscribe(self.cb_update_target, **options) # cancel subscriptions before object is garbage collected weakref.finalize(self.readback, self.readback.unsubscribe_all) diff --git a/apstools/devices/tests/test_positioner_soft_done.py b/apstools/devices/tests/test_positioner_soft_done.py index 51e926ce..073fa4c2 100644 --- a/apstools/devices/tests/test_positioner_soft_done.py +++ b/apstools/devices/tests/test_positioner_soft_done.py @@ -1,9 +1,11 @@ import math import time +from contextlib import nullcontext as does_not_raise import pytest from ophyd import Component from ophyd import EpicsSignal +from ophyd.sim import instantiate_fake_device from ...synApps.swait import UserCalcsDevice from ...tests import IOC_GP @@ -11,9 +13,9 @@ from ...tests import rand from ...tests import timed_pause from ...utils import run_in_thread +from ..positioner_soft_done import TARGET_UNDEFINED from ..positioner_soft_done import PVPositionerSoftDone from ..positioner_soft_done import PVPositionerSoftDoneWithStop -from ..positioner_soft_done import TARGET_UNDEFINED PV_PREFIX = f"{IOC_GP}gp:" delay_active = False @@ -365,3 +367,19 @@ def motion(p, goal): motion(calcpos, round(rand(-1.1, 0.2), 4)) # known starting position motion(calcpos, target) motion(calcpos, target) # issue #725, repeated move to same target + + +def test_issue_1022(): + """ + PVPositionerSoftDone should work with simulated fake devices. + + 'instantiate_fake_device()' produces a device that does not + have the 'setpoint' event_type. + """ + with does_not_raise(): + d = instantiate_fake_device( + PVPositionerSoftDone, + readback_pv="spam:", + setpoint_pv="eggs:", + ) + assert d is not None