pyobs-fli 2.0.0.dev11__tar.gz → 2.0.0.dev12__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyobs_fli-2.0.0.dev12/.github/workflows/dependabot-automerge.yml +24 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/PKG-INFO +1 -1
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/pyobs_fli/flibase.py +24 -5
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/pyobs_fli/flifilterwheel.py +30 -2
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/pyproject.toml +1 -1
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/tests/test_flicamera.py +2 -2
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/tests/test_flifilterwheel.py +8 -4
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/uv.lock +1 -1
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/.github/dependabot.yml +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/.github/workflows/pypi.yml +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/.github/workflows/pyrefly.yml +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/.github/workflows/pytest.yml +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/.github/workflows/ruff.yml +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/.pre-commit-config.yaml +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/.readthedocs.yml +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/CHANGELOG.rst +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/CMakeLists.txt +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/LICENSE +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/README.md +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/docs/Makefile +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/docs/make.bat +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/docs/requirements.txt +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/docs/source/_static/pyobs.gif +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/docs/source/conf.py +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/docs/source/index.rst +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/Makefile +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/docxx.sty +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-camera-parport.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-camera-parport.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-camera-usb.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-camera-usb.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-camera.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-camera.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-debug.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-filter-focuser.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-filter-focuser.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-libfli.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-mem.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-mem.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-raw.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli-raw.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli.dxx +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/libfli.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/bsd/libfli-usb-sys.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/libfli-debug.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/libfli-parport.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/libfli-serial.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/libfli-serial.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/libfli-sys.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/libfli-sys.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/libfli-usb.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/libfli-usb.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/linux/fli_ioctl.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/linux/fliusb_ioctl.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/linux/libfli-parport.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/linux/libfli-usb-sys.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/osx/libfli-usb-sys.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/unix/osx/libfli-usb-sys.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli-debug.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli-parport.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli-serial.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli-serial.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli-sys.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli-usb.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli-usb.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli-windows-parport.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli-windows.c +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli.def +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli.rc +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli.sln +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli.vcproj +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/libfli64.def +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/lib/windows/resource.h +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/poetry.lock +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/pyobs_fli/__init__.py +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/pyobs_fli/flicamera.py +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/pyobs_fli/flidriver.pyx +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/pyobs_fli/gui.py +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/pyobs_fli/libfli.pxd +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/specs/plans/2026-08-16-nogil-fli-driver-calls.md +0 -0
- {pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/tests/test_import.py +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Dependabot auto-merge
|
|
2
|
+
|
|
3
|
+
on: pull_request
|
|
4
|
+
|
|
5
|
+
permissions:
|
|
6
|
+
contents: write
|
|
7
|
+
pull-requests: write
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
dependabot:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
|
|
13
|
+
steps:
|
|
14
|
+
- name: Fetch Dependabot metadata
|
|
15
|
+
id: metadata
|
|
16
|
+
uses: dependabot/fetch-metadata@v2
|
|
17
|
+
with:
|
|
18
|
+
compat-lookup: true
|
|
19
|
+
- name: Enable auto-merge for patch and minor updates
|
|
20
|
+
if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor' }}
|
|
21
|
+
run: gh pr merge --auto --merge "$PR_URL"
|
|
22
|
+
env:
|
|
23
|
+
PR_URL: ${{ github.event.pull_request.html_url }}
|
|
24
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -27,9 +27,10 @@ class FliBaseMixin:
|
|
|
27
27
|
dev_name: str | None = None,
|
|
28
28
|
dev_path: str | None = None,
|
|
29
29
|
keep_alive_ping: int = 10,
|
|
30
|
+
sdk_call_timeout: float = _SDK_CALL_TIMEOUT,
|
|
30
31
|
**kwargs: Any,
|
|
31
32
|
):
|
|
32
|
-
"""Initializes a new
|
|
33
|
+
"""Initializes a new FLI device mixin.
|
|
33
34
|
|
|
34
35
|
If neither dev_name nor dev_path are given, the first found device is used.
|
|
35
36
|
|
|
@@ -38,6 +39,7 @@ class FliBaseMixin:
|
|
|
38
39
|
dev_name: Optional name for device.
|
|
39
40
|
dev_path: Optional path to device.
|
|
40
41
|
keep_alive_ping: Interval for keep alive ping.
|
|
42
|
+
sdk_call_timeout: Default timeout for blocking FLI SDK calls.
|
|
41
43
|
"""
|
|
42
44
|
from .flidriver import FliDriver # type: ignore
|
|
43
45
|
|
|
@@ -46,6 +48,7 @@ class FliBaseMixin:
|
|
|
46
48
|
self._dev_name = dev_name
|
|
47
49
|
self._dev_path = dev_path
|
|
48
50
|
self._keep_alive_ping = keep_alive_ping
|
|
51
|
+
self._sdk_call_timeout = sdk_call_timeout
|
|
49
52
|
self._driver: FliDriver | None = None
|
|
50
53
|
self._device: Any | None = None
|
|
51
54
|
|
|
@@ -57,24 +60,35 @@ class FliBaseMixin:
|
|
|
57
60
|
# claim its own kwargs cooperatively instead of this mixin silently absorbing them
|
|
58
61
|
super().__init__(**kwargs) # type: ignore[call-arg]
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
async def _run_blocking(func: Callable[[], None], timeout: float = _SDK_CALL_TIMEOUT) -> bool:
|
|
63
|
+
async def _run_blocking(self, func: Callable[[], None], timeout: float | None = None) -> bool:
|
|
62
64
|
"""Run a blocking FLI SDK call in a daemon thread, so a hung call can't freeze the module.
|
|
63
65
|
|
|
64
66
|
A plain executor isn't used here, since its worker threads are non-daemon and Python joins
|
|
65
67
|
them on interpreter shutdown -- a hung call would then just move the freeze to process exit.
|
|
66
68
|
|
|
69
|
+
Args:
|
|
70
|
+
func: Blocking callable to run off the event loop.
|
|
71
|
+
timeout: Seconds to wait for completion. Defaults to sdk_call_timeout.
|
|
72
|
+
|
|
67
73
|
Returns:
|
|
68
74
|
True if func completed within timeout, False if it's still running in the background.
|
|
69
75
|
"""
|
|
76
|
+
timeout = self._sdk_call_timeout if timeout is None else timeout
|
|
70
77
|
loop = asyncio.get_running_loop()
|
|
71
78
|
future: asyncio.Future[None] = loop.create_future()
|
|
72
79
|
|
|
80
|
+
def _complete() -> None:
|
|
81
|
+
# The worker thread may outlive the timeout (wait_for cancels the future on
|
|
82
|
+
# timeout), so guard against a late set_result on an already-completed future --
|
|
83
|
+
# otherwise the loop callback raises InvalidStateError.
|
|
84
|
+
if not future.done():
|
|
85
|
+
future.set_result(None)
|
|
86
|
+
|
|
73
87
|
def _wrapper() -> None:
|
|
74
88
|
try:
|
|
75
89
|
func()
|
|
76
90
|
finally:
|
|
77
|
-
loop.call_soon_threadsafe(
|
|
91
|
+
loop.call_soon_threadsafe(_complete)
|
|
78
92
|
|
|
79
93
|
threading.Thread(target=_wrapper, daemon=True).start()
|
|
80
94
|
try:
|
|
@@ -83,14 +97,19 @@ class FliBaseMixin:
|
|
|
83
97
|
except TimeoutError:
|
|
84
98
|
return False
|
|
85
99
|
|
|
86
|
-
async def _run_blocking_or_raise(self, func: Callable[[], _T], timeout: float =
|
|
100
|
+
async def _run_blocking_or_raise(self, func: Callable[[], _T], timeout: float | None = None) -> _T:
|
|
87
101
|
"""Run a blocking FLI SDK call in a thread, returning its result or re-raising what it raised.
|
|
88
102
|
|
|
89
103
|
Unlike _run_blocking(), this also carries the callable's return value/exception back to the
|
|
90
104
|
caller -- several FLI calls drive control flow via their return value or a raised ValueError
|
|
91
105
|
(e.g. device enumeration, readout), which a bare fire-and-forget thread call would otherwise
|
|
92
106
|
silently lose.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
func: Blocking callable to run off the event loop.
|
|
110
|
+
timeout: Seconds to wait for completion. Defaults to sdk_call_timeout.
|
|
93
111
|
"""
|
|
112
|
+
timeout = self._sdk_call_timeout if timeout is None else timeout
|
|
94
113
|
outcome: list[Any] = []
|
|
95
114
|
|
|
96
115
|
def _wrapper() -> None:
|
|
@@ -16,17 +16,28 @@ from pyobs_fli.flidriver import DeviceType
|
|
|
16
16
|
|
|
17
17
|
log = logging.getLogger(__name__)
|
|
18
18
|
|
|
19
|
+
# A physical filter move can take far longer than a typical SDK call (a long rotation
|
|
20
|
+
# can be several seconds), so give it its own generous, configurable deadline instead of
|
|
21
|
+
# the short SDK-call default.
|
|
22
|
+
_FILTER_MOVE_TIMEOUT = 120.0
|
|
23
|
+
|
|
19
24
|
|
|
20
25
|
class FliFilterWheel(Module, FliBaseMixin, MotionStatusMixin, IFilters, IFitsHeaderBefore):
|
|
21
26
|
"""A pyobs module for FLI filter wheels."""
|
|
22
27
|
|
|
23
28
|
__module__ = "pyobs_fli"
|
|
24
29
|
|
|
25
|
-
def __init__(
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
filter_names: list[str] | list[list[str]],
|
|
33
|
+
filter_move_timeout: float = _FILTER_MOVE_TIMEOUT,
|
|
34
|
+
**kwargs: Any,
|
|
35
|
+
):
|
|
26
36
|
"""Initializes a new FliFilterWheel.
|
|
27
37
|
|
|
28
38
|
Args:
|
|
29
39
|
filter_names: Names of filters.
|
|
40
|
+
filter_move_timeout: Seconds to wait for a filter move to complete.
|
|
30
41
|
"""
|
|
31
42
|
super().__init__(dev_type=DeviceType.FILTERWHEEL, motion_status_interfaces=["IFilters"], **kwargs)
|
|
32
43
|
|
|
@@ -34,6 +45,7 @@ class FliFilterWheel(Module, FliBaseMixin, MotionStatusMixin, IFilters, IFitsHea
|
|
|
34
45
|
[filter_names] if isinstance(filter_names[0], str) else filter_names # type: ignore[arg-type,list-item]
|
|
35
46
|
)
|
|
36
47
|
|
|
48
|
+
self._filter_move_timeout = filter_move_timeout
|
|
37
49
|
self._current_filter = ""
|
|
38
50
|
|
|
39
51
|
async def open(self) -> None:
|
|
@@ -95,7 +107,23 @@ class FliFilterWheel(Module, FliBaseMixin, MotionStatusMixin, IFilters, IFitsHea
|
|
|
95
107
|
def _set() -> None:
|
|
96
108
|
driver.set_filter_pos(pos)
|
|
97
109
|
|
|
98
|
-
|
|
110
|
+
try:
|
|
111
|
+
# A physical filter move can legitimately take far longer than a typical SDK
|
|
112
|
+
# call, so bound it with a dedicated, configurable move timeout rather than the
|
|
113
|
+
# short SDK-call default -- which cut off long rotations mid-move.
|
|
114
|
+
await self._run_blocking_or_raise(_set, timeout=self._filter_move_timeout)
|
|
115
|
+
|
|
116
|
+
# Confirm the wheel actually reports the requested position before declaring
|
|
117
|
+
# success, so an SDK call that returned without the wheel having arrived can't
|
|
118
|
+
# leave the published filter state silently wrong.
|
|
119
|
+
actual = await self._run_blocking_or_raise(driver.get_filter_pos)
|
|
120
|
+
if actual != pos:
|
|
121
|
+
raise exc.MoveError(f"Filter wheel reported position {actual} after moving to {pos}.")
|
|
122
|
+
except Exception:
|
|
123
|
+
# Don't leave the wheel stuck reporting "slewing" after a failed move.
|
|
124
|
+
await self._change_motion_status(MotionStatus.ERROR)
|
|
125
|
+
raise
|
|
126
|
+
|
|
99
127
|
self._current_filter = filter_name
|
|
100
128
|
await self._change_motion_status(MotionStatus.POSITIONED)
|
|
101
129
|
await self.comm.send_event(FilterChangedEvent(filter_name))
|
|
@@ -73,7 +73,7 @@ async def test_run_blocking_runs_func_and_returns_true() -> None:
|
|
|
73
73
|
def fast() -> None:
|
|
74
74
|
ran.append(True)
|
|
75
75
|
|
|
76
|
-
assert await FliCamera._run_blocking(fast) is True
|
|
76
|
+
assert await FliCamera()._run_blocking(fast) is True
|
|
77
77
|
assert ran == [True]
|
|
78
78
|
|
|
79
79
|
|
|
@@ -84,7 +84,7 @@ async def test_run_blocking_times_out() -> None:
|
|
|
84
84
|
def slow() -> None:
|
|
85
85
|
done.wait()
|
|
86
86
|
|
|
87
|
-
assert await FliCamera._run_blocking(slow, timeout=0.01) is False
|
|
87
|
+
assert await FliCamera()._run_blocking(slow, timeout=0.01) is False
|
|
88
88
|
done.set()
|
|
89
89
|
await asyncio.sleep(0.05)
|
|
90
90
|
|
|
@@ -61,14 +61,16 @@ async def test_set_filter_first_wheel() -> None:
|
|
|
61
61
|
wheel = FliFilterWheel(filter_names=_TWO_WHEELS)
|
|
62
62
|
wheel._driver = MagicMock()
|
|
63
63
|
wheel._driver.set_filter_pos = MagicMock()
|
|
64
|
+
wheel._driver.get_filter_pos = MagicMock(return_value=0)
|
|
64
65
|
|
|
65
|
-
async def fake_run(func, timeout: float =
|
|
66
|
-
func()
|
|
66
|
+
async def fake_run(func, timeout: float | None = None) -> object:
|
|
67
|
+
return func()
|
|
67
68
|
|
|
68
69
|
wheel._run_blocking_or_raise = fake_run # type: ignore[method-assign]
|
|
69
70
|
|
|
70
71
|
await wheel.set_filter("A")
|
|
71
72
|
wheel._driver.set_filter_pos.assert_called_once_with(0)
|
|
73
|
+
wheel._driver.get_filter_pos.assert_called_once()
|
|
72
74
|
assert wheel._current_filter == "A"
|
|
73
75
|
|
|
74
76
|
|
|
@@ -77,14 +79,16 @@ async def test_set_filter_second_wheel() -> None:
|
|
|
77
79
|
wheel = FliFilterWheel(filter_names=_TWO_WHEELS)
|
|
78
80
|
wheel._driver = MagicMock()
|
|
79
81
|
wheel._driver.set_filter_pos = MagicMock()
|
|
82
|
+
wheel._driver.get_filter_pos = MagicMock(return_value=7)
|
|
80
83
|
|
|
81
|
-
async def fake_run(func, timeout: float =
|
|
82
|
-
func()
|
|
84
|
+
async def fake_run(func, timeout: float | None = None) -> object:
|
|
85
|
+
return func()
|
|
83
86
|
|
|
84
87
|
wheel._run_blocking_or_raise = fake_run # type: ignore[method-assign]
|
|
85
88
|
|
|
86
89
|
await wheel.set_filter("H")
|
|
87
90
|
wheel._driver.set_filter_pos.assert_called_once_with(7)
|
|
91
|
+
wheel._driver.get_filter_pos.assert_called_once()
|
|
88
92
|
assert wheel._current_filter == "H"
|
|
89
93
|
|
|
90
94
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyobs_fli-2.0.0.dev11 → pyobs_fli-2.0.0.dev12}/specs/plans/2026-08-16-nogil-fli-driver-calls.md
RENAMED
|
File without changes
|
|
File without changes
|