From 22f27a9877aee41a5799865a6996dd1f3e969820 Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Wed, 2 Apr 2025 09:33:47 +0100 Subject: [PATCH 1/5] allow redefine to be optional for refl param --- .../devices/reflectometry/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ibex_bluesky_core/devices/reflectometry/__init__.py b/src/ibex_bluesky_core/devices/reflectometry/__init__.py index 4b3c7803..4109b877 100644 --- a/src/ibex_bluesky_core/devices/reflectometry/__init__.py +++ b/src/ibex_bluesky_core/devices/reflectometry/__init__.py @@ -18,16 +18,17 @@ logger = logging.getLogger(__name__) -class ReflParameter(StandardReadable): +class ReflParameter(StandardReadable, NamedMovable[float]): """Utility device for a reflectometry server parameter.""" - def __init__(self, prefix: str, name: str, changing_timeout_s: float) -> None: + def __init__(self, prefix: str, name: str, changing_timeout_s: float, *, has_redefine: bool = True) -> None: """Reflectometry server parameter. Args: prefix: the PV prefix. name: the name of the parameter. changing_timeout_s: seconds to wait for the CHANGING signal to go to False after a set. + has_redefine: whether this parameter can be redefined. """ with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL): @@ -36,7 +37,10 @@ def __init__(self, prefix: str, name: str, changing_timeout_s: float) -> None: self.changing: SignalR[bool] = epics_signal_r( bool, f"{prefix}REFL_01:PARAM:{name}:CHANGING" ) - self.redefine = ReflParameterRedefine(prefix=f"{prefix}REFL_01:PARAM:{name}:", name="") + if has_redefine: + self.redefine = ReflParameterRedefine(prefix=f"{prefix}REFL_01:PARAM:{name}:", name="") + else: + self.redefine = None self.changing_timeout = changing_timeout_s super().__init__(name=name) self.readback.set_name(name) From 9f5278d99bad4f39275f87b15ccabfbdabb00a7f Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Wed, 2 Apr 2025 09:47:10 +0100 Subject: [PATCH 2/5] add import for namedmovable --- src/ibex_bluesky_core/devices/reflectometry/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ibex_bluesky_core/devices/reflectometry/__init__.py b/src/ibex_bluesky_core/devices/reflectometry/__init__.py index 4109b877..b487d861 100644 --- a/src/ibex_bluesky_core/devices/reflectometry/__init__.py +++ b/src/ibex_bluesky_core/devices/reflectometry/__init__.py @@ -3,6 +3,7 @@ import asyncio import logging +from bluesky.protocols import NamedMovable from ophyd_async.core import ( AsyncStatus, SignalR, @@ -21,7 +22,9 @@ class ReflParameter(StandardReadable, NamedMovable[float]): """Utility device for a reflectometry server parameter.""" - def __init__(self, prefix: str, name: str, changing_timeout_s: float, *, has_redefine: bool = True) -> None: + def __init__( + self, prefix: str, name: str, changing_timeout_s: float, *, has_redefine: bool = True + ) -> None: """Reflectometry server parameter. Args: From a0df1ff69d090449f05994fe83c0b9bd08014db6 Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Wed, 2 Apr 2025 09:53:30 +0100 Subject: [PATCH 3/5] add test --- src/ibex_bluesky_core/plan_stubs/__init__.py | 2 ++ tests/test_plan_stubs.py | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/ibex_bluesky_core/plan_stubs/__init__.py b/src/ibex_bluesky_core/plan_stubs/__init__.py index 5f2e2f70..501bfe1d 100644 --- a/src/ibex_bluesky_core/plan_stubs/__init__.py +++ b/src/ibex_bluesky_core/plan_stubs/__init__.py @@ -120,6 +120,8 @@ def redefine_refl_parameter( position: The position to set. """ + if parameter.redefine is None: + raise ValueError(f"Parameter {parameter.name} cannot be redefined.") logger.info("Redefining refl parameter %s to %s", parameter.name, position) yield from bps.mv(parameter.redefine, position) diff --git a/tests/test_plan_stubs.py b/tests/test_plan_stubs.py index 4e0bc2cc..91fbf9e6 100644 --- a/tests/test_plan_stubs.py +++ b/tests/test_plan_stubs.py @@ -158,6 +158,19 @@ async def test_redefine_refl_parameter(RE): get_mock_put(param.redefine.define_pos_sp).assert_called_once_with(42.0, wait=True) +async def test_raises_when_attempting_to_redefine_refl_parameter_with_no_redefine(RE): + param = ReflParameter( + prefix="", name="some_refl_parameter_no_redefine", changing_timeout_s=1, has_redefine=False + ) + await param.connect(mock=True) + with pytest.raises( + ValueError, + match=r"Parameter some_refl_parameter_no_redefine" + r" cannot be redefined.", + ): + RE(redefine_refl_parameter(param, 42.0)) + + def test_get_user_input(RE): with patch("ibex_bluesky_core.plan_stubs.input") as mock_input: mock_input.__name__ = "mock" From 2d011f290c4f96555b63715fae99812472649287 Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Wed, 2 Apr 2025 09:56:44 +0100 Subject: [PATCH 4/5] pyright --- tests/test_plan_stubs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_plan_stubs.py b/tests/test_plan_stubs.py index 91fbf9e6..a6d05a72 100644 --- a/tests/test_plan_stubs.py +++ b/tests/test_plan_stubs.py @@ -155,7 +155,7 @@ async def test_redefine_refl_parameter(RE): RE(redefine_refl_parameter(param, 42.0)) - get_mock_put(param.redefine.define_pos_sp).assert_called_once_with(42.0, wait=True) + get_mock_put(param.redefine.define_pos_sp).assert_called_once_with(42.0, wait=True) # pyright: ignore [reportOptionalMemberAccess] async def test_raises_when_attempting_to_redefine_refl_parameter_with_no_redefine(RE): From 44393a67d5776431262587a1b53be2741541cb10 Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Wed, 2 Apr 2025 11:07:06 +0100 Subject: [PATCH 5/5] add note in docs --- doc/plan_stubs/redefining.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/plan_stubs/redefining.md b/doc/plan_stubs/redefining.md index 58d8a8a2..76fcb926 100644 --- a/doc/plan_stubs/redefining.md +++ b/doc/plan_stubs/redefining.md @@ -31,7 +31,7 @@ def my_plan(): ## `redefine_refl_parameter` The {py:obj}`ibex_bluesky_core.plan_stubs.redefine_refl_parameter` plan stub can be used to redefine the current -position of a {py:obj}`ibex_bluesky_core.devices.reflectometry.ReflParameter` to a new value. +position of a {py:obj}`ibex_bluesky_core.devices.reflectometry.ReflParameter` to a new value. Note that some reflectometry parameters ie. `Theta` cannot be redefined, so these must be constructed with `has_redefine=False`. This plan stub will handle this case and raise an error if a user tries to redefine it. This plan stub has an identical API to that of the {py:obj}`ibex_bluesky_core.plan_stubs.redefine_motor` plan stub described above, but operates on a reflectometry parameter rather than a motor.