Skip to content

Commit 67c3b5b

Browse files
committed
Merge branch 'troubleshooting_guide' of https://github.com/IsisComputingGroup/ibex_bluesky_core into troubleshooting_guide
2 parents b18ba70 + 5aea340 commit 67c3b5b

File tree

3 files changed

+49
-11
lines changed

3 files changed

+49
-11
lines changed

README.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
[<img src="https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/test-against-main.yml/badge.svg">](https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/test-against-main.yml)
2-
[<img src="https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/lint-and-test-nightly.yml/badge.svg">](https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/lint-and-test-nightly.yml)
3-
4-
51
![ibex_bluesky_core](https://github.com/IsisComputingGroup/ibex_bluesky_core/blob/main/doc/logo.svg?sanitize=true&raw=true)
62

73
Core bluesky plan stubs &amp; devices for use at ISIS.
84

9-
Documentation: https://isiscomputinggroup.github.io/ibex_bluesky_core/
10-
11-
Source: https://github.com/ISISComputingGroup/ibex_bluesky_core
12-
13-
PyPi: https://pypi.org/project/ibex-bluesky-core/
5+
| - | - |
6+
|----------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
7+
| [Documentation](https://isiscomputinggroup.github.io/ibex_bluesky_core/) | [![sphinx](https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/documentation.yml/badge.svg)](https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/documentation.yml) |
8+
| [CI (nightly)](https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/lint-and-test-nightly.yml) | [<img src="https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/lint-and-test-nightly.yml/badge.svg">](https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/lint-and-test-nightly.yml) |
9+
| [CI (`bluesky` & `ophyd-async` main)](https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/test-against-main.yml) | [<img src="https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/test-against-main.yml/badge.svg">](https://github.com/ISISComputingGroup/ibex_bluesky_core/actions/workflows/test-against-main.yml) |
10+
| [PyPI](https://pypi.org/project/ibex-bluesky-core/) | ![PyPI - Version](https://img.shields.io/pypi/v/ibex_bluesky_core) |
11+
| [Github](https://github.com/ISISComputingGroup/ibex_bluesky_core) | ![GitHub Release](https://img.shields.io/github/v/release/IsisComputingGroup/ibex_bluesky_core) |
12+
| [License](https://github.com/ISISComputingGroup/ibex_bluesky_core/blob/main/LICENSE) | ![GitHub License](https://img.shields.io/github/license/ISISComputingGroup/ibex_bluesky_core) |

src/ibex_bluesky_core/devices/block.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import asyncio
44
import logging
5+
import sys
56
from collections.abc import Callable
67
from dataclasses import dataclass
78
from typing import Generic, TypeVar
@@ -57,6 +58,8 @@
5758
# looking at the global moving flag.
5859
GLOBAL_MOVING_FLAG_PRE_WAIT = 0.1
5960

61+
aio_timeout_error = asyncio.exceptions.TimeoutError if sys.version_info < (3, 11) else TimeoutError
62+
6063

6164
@dataclass(kw_only=True, frozen=True)
6265
class BlockWriteConfig(Generic[T]):
@@ -101,13 +104,19 @@ def check(setpoint: T, actual: T) -> bool:
101104
move, and all movement needs to be complete before the set is considered complete. Defaults
102105
to False.
103106
107+
timeout_is_error:
108+
Whether a write timeout is considered an error. Defaults to True. If False, a set will be
109+
marked as complete without error even if the block has not given a completion callback or
110+
satisfied set_success_func within settle_time_s.
111+
104112
"""
105113

106114
use_completion_callback: bool = True
107115
set_success_func: Callable[[T, T], bool] | None = None
108116
set_timeout_s: float | None = None
109117
settle_time_s: float = 0.0
110118
use_global_moving_flag: bool = False
119+
timeout_is_error: bool = True
111120

112121

113122
class RunControl(StandardReadable):
@@ -272,7 +281,19 @@ async def set_and_settle(setpoint: T) -> None:
272281
)
273282
await asyncio.sleep(self._write_config.settle_time_s)
274283

275-
await set_and_settle(value)
284+
if self._write_config.timeout_is_error:
285+
await set_and_settle(value)
286+
else:
287+
try:
288+
await set_and_settle(value)
289+
except aio_timeout_error as e:
290+
logger.info(
291+
"block set %s value=%s failed with %s, but continuing anyway because "
292+
"continue_on_failed_write is set.",
293+
self.name,
294+
value,
295+
e,
296+
)
276297
logger.info("block set complete %s value=%s", self.name, value)
277298

278299

@@ -362,6 +383,7 @@ def __init__(
362383
use_global_moving_flag:
363384
This is unnecessary for a single motor block, as a completion callback will always be
364385
used instead to detect when a single move has finished.
386+
365387
"""
366388
self.run_control = RunControl(f"{prefix}CS:SB:{block_name}:RC:")
367389

tests/devices/test_block.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# pyright: reportMissingParameterType=false
22
import asyncio
33
import sys
4+
from contextlib import nullcontext
45
from unittest.mock import ANY, MagicMock, call, patch
56

67
import bluesky.plan_stubs as bps
@@ -73,7 +74,7 @@ def test_block_naming(rw_rbv_block):
7374
def test_mot_block_naming(mot_block):
7475
assert mot_block.name == "mot_block"
7576
assert mot_block.user_readback.name == "mot_block"
76-
assert mot_block.user_setpoint.name == ("mot_block-user_setpoint")
77+
assert mot_block.user_setpoint.name == "mot_block-user_setpoint"
7778

7879

7980
def test_block_signal_monitors_correct_pv(rw_rbv_block):
@@ -353,3 +354,19 @@ async def test_block_mot_set(mot_block):
353354
set_mock_value(mot_block.velocity, 10)
354355
await mot_block.set(20)
355356
get_mock_put(mot_block.user_setpoint).assert_called_once_with(20, wait=True)
357+
358+
359+
@pytest.mark.parametrize("timeout_is_error", [True, False])
360+
async def test_block_failing_write(timeout_is_error):
361+
block = await _block_with_write_config(BlockWriteConfig(timeout_is_error=timeout_is_error))
362+
363+
get_mock_put(block.setpoint).side_effect = aio_timeout_error
364+
365+
with pytest.raises(aio_timeout_error) if timeout_is_error else nullcontext():
366+
await block.set(1)
367+
368+
369+
async def test_block_failing_write_with_default_write_config(writable_block):
370+
get_mock_put(writable_block.setpoint).side_effect = aio_timeout_error
371+
with pytest.raises(aio_timeout_error):
372+
await writable_block.set(1)

0 commit comments

Comments
 (0)