Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion doc/devices/blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ type `float`, and as such does not take a type argument (unlike the other block

`Checkable` means that moves which would eventually violate limits can be detected by
bluesky simulators, before the plan ever runs. This can help to catch errors before
the plan is executed against hardware.
the plan is executed against hardware. There is also limit-checking at runtime;
a {external+ophyd_async:py:obj}`MotorLimitsException <ophyd_async.epics.motor.MotorLimitsException>` will be raised
at runtime if a requested position is outside the motor's limits.

`Stoppable` means that the motor can be asked to stop by bluesky. Plans may choose to execute
a `stop()` on failure, or explicitly during a plan.
Expand Down
4 changes: 4 additions & 0 deletions src/ibex_bluesky_core/devices/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,10 @@ def set( # pyright: ignore
"""Pass through set to superclass.

This is needed so that type-checker correctly understands the type of set.

This method will raise
:external+ophyd_async:py:obj:`ophyd_async.epics.motor.MotorLimitsException`
if the requested position was outside the motor's limits.
"""
return super().set(value, timeout)

Expand Down
21 changes: 20 additions & 1 deletion tests/devices/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import bluesky.plan_stubs as bps
import bluesky.plans as bp
import ophyd_async
import pytest
from ophyd_async.testing import get_mock_put, set_mock_value

Expand Down Expand Up @@ -349,13 +350,31 @@ def test_block_reprs():
assert repr(BlockMot(block_name="qux", prefix="")) == "BlockMot(name=qux)"


async def test_block_mot_set(mot_block):
async def test_block_mot_set_within_limits(mot_block):
set_mock_value(mot_block.user_setpoint, 10)
set_mock_value(mot_block.velocity, 10)
set_mock_value(mot_block.high_limit_travel, 1000)
set_mock_value(mot_block.low_limit_travel, -1000)
await mot_block.set(20)
get_mock_put(mot_block.user_setpoint).assert_called_once_with(20, wait=True)


@pytest.mark.skipif(
ophyd_async._version.version_tuple < (0, 13, 2),
reason="Exception only raised in ophyd_async >= 0.13.2",
)
async def test_block_mot_set_outside_limits(mot_block):
# Local import as API not available in older ophyd_async versions
from ophyd_async.epics.motor import MotorLimitsException # noqa PLC0415

set_mock_value(mot_block.user_setpoint, 10)
set_mock_value(mot_block.velocity, 10)
set_mock_value(mot_block.high_limit_travel, 15)
set_mock_value(mot_block.low_limit_travel, 5)
with pytest.raises(MotorLimitsException):
await mot_block.set(20)


@pytest.mark.parametrize("timeout_is_error", [True, False])
async def test_block_failing_write(timeout_is_error):
block = await _block_with_write_config(BlockWriteConfig(timeout_is_error=timeout_is_error))
Expand Down
Loading