|
2 | 2 |
|
3 | 3 | import asyncio |
4 | 4 | import logging |
| 5 | +import sys |
5 | 6 | from collections.abc import Callable |
6 | 7 | from dataclasses import dataclass |
7 | 8 | from typing import Generic, TypeVar |
|
57 | 58 | # looking at the global moving flag. |
58 | 59 | GLOBAL_MOVING_FLAG_PRE_WAIT = 0.1 |
59 | 60 |
|
| 61 | +aio_timeout_error = asyncio.exceptions.TimeoutError if sys.version_info < (3, 11) else TimeoutError |
| 62 | + |
60 | 63 |
|
61 | 64 | @dataclass(kw_only=True, frozen=True) |
62 | 65 | class BlockWriteConfig(Generic[T]): |
@@ -101,13 +104,19 @@ def check(setpoint: T, actual: T) -> bool: |
101 | 104 | move, and all movement needs to be complete before the set is considered complete. Defaults |
102 | 105 | to False. |
103 | 106 |
|
| 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 | +
|
104 | 112 | """ |
105 | 113 |
|
106 | 114 | use_completion_callback: bool = True |
107 | 115 | set_success_func: Callable[[T, T], bool] | None = None |
108 | 116 | set_timeout_s: float | None = None |
109 | 117 | settle_time_s: float = 0.0 |
110 | 118 | use_global_moving_flag: bool = False |
| 119 | + timeout_is_error: bool = True |
111 | 120 |
|
112 | 121 |
|
113 | 122 | class RunControl(StandardReadable): |
@@ -272,7 +281,19 @@ async def set_and_settle(setpoint: T) -> None: |
272 | 281 | ) |
273 | 282 | await asyncio.sleep(self._write_config.settle_time_s) |
274 | 283 |
|
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 | + ) |
276 | 297 | logger.info("block set complete %s value=%s", self.name, value) |
277 | 298 |
|
278 | 299 |
|
@@ -362,6 +383,7 @@ def __init__( |
362 | 383 | use_global_moving_flag: |
363 | 384 | This is unnecessary for a single motor block, as a completion callback will always be |
364 | 385 | used instead to detect when a single move has finished. |
| 386 | +
|
365 | 387 | """ |
366 | 388 | self.run_control = RunControl(f"{prefix}CS:SB:{block_name}:RC:") |
367 | 389 |
|
|
0 commit comments