pyobs-zaber 2.0.0.dev7__tar.gz → 2.0.0.dev8__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_zaber-2.0.0.dev8/.github/dependabot.yml +15 -0
- pyobs_zaber-2.0.0.dev8/.github/workflows/pyrefly.yml +23 -0
- pyobs_zaber-2.0.0.dev8/.github/workflows/pytest.yml +25 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/PKG-INFO +3 -3
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/pyproject.toml +8 -3
- pyobs_zaber-2.0.0.dev8/tests/test_import.py +24 -0
- pyobs_zaber-2.0.0.dev8/tests/test_zaberdriver.py +42 -0
- pyobs_zaber-2.0.0.dev8/tests/test_zabermodeselector.py +52 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/uv.lock +970 -700
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/.github/workflows/pypi.yml +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/.github/workflows/ruff.yml +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/.pre-commit-config.yaml +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/.readthedocs.yml +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/LICENSE +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/README.md +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/docs/Makefile +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/docs/make.bat +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/docs/requirements.txt +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/docs/source/_static/pyobs.gif +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/docs/source/conf.py +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/docs/source/index.rst +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/pyobs_zaber/__init__.py +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/pyobs_zaber/zaberdriver.py +0 -0
- {pyobs_zaber-2.0.0.dev7 → pyobs_zaber-2.0.0.dev8}/pyobs_zaber/zabermodeselector.py +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: pyrefly
|
|
2
|
+
on: push
|
|
3
|
+
|
|
4
|
+
jobs:
|
|
5
|
+
pyrefly:
|
|
6
|
+
runs-on: ubuntu-latest
|
|
7
|
+
timeout-minutes: 10
|
|
8
|
+
|
|
9
|
+
steps:
|
|
10
|
+
- name: Check out repository code
|
|
11
|
+
uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: astral-sh/setup-uv@v5
|
|
15
|
+
with:
|
|
16
|
+
enable-cache: true
|
|
17
|
+
python-version: "3.13"
|
|
18
|
+
|
|
19
|
+
- name: Install packages
|
|
20
|
+
run: uv sync --all-extras --dev
|
|
21
|
+
|
|
22
|
+
- name: Run pyrefly
|
|
23
|
+
run: uv run pyrefly check
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: PyTest
|
|
2
|
+
on: push
|
|
3
|
+
|
|
4
|
+
jobs:
|
|
5
|
+
test:
|
|
6
|
+
runs-on: ubuntu-latest
|
|
7
|
+
timeout-minutes: 10
|
|
8
|
+
|
|
9
|
+
steps:
|
|
10
|
+
- name: Check out repository code
|
|
11
|
+
uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: astral-sh/setup-uv@v5
|
|
15
|
+
with:
|
|
16
|
+
enable-cache: true
|
|
17
|
+
python-version: "3.13"
|
|
18
|
+
|
|
19
|
+
- name: Install packages
|
|
20
|
+
run: uv sync --all-extras --dev
|
|
21
|
+
|
|
22
|
+
- name: Run tests
|
|
23
|
+
run: uv run pytest tests
|
|
24
|
+
env:
|
|
25
|
+
CI: true
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: pyobs-zaber
|
|
3
|
-
Version: 2.0.0.
|
|
3
|
+
Version: 2.0.0.dev8
|
|
4
4
|
Summary: pyobs model for Zaber motors
|
|
5
5
|
Author-email: Leon Meerwart <leon.meerwart@uni-goettingen.de>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
License-File: LICENSE
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
|
-
Requires-Dist: pyobs-core<3,>=2.0.0.
|
|
9
|
+
Requires-Dist: pyobs-core<3,>=2.0.0.dev48
|
|
10
10
|
Requires-Dist: zaber-motion<5,>=4.7.0
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pyobs-zaber"
|
|
3
|
-
version = "2.0.0.
|
|
3
|
+
version = "2.0.0.dev8"
|
|
4
4
|
description = "pyobs model for Zaber motors"
|
|
5
5
|
authors = [{ name = "Leon Meerwart", email = "leon.meerwart@uni-goettingen.de" }]
|
|
6
6
|
requires-python = ">=3.11"
|
|
7
7
|
license = "MIT"
|
|
8
8
|
dependencies = [
|
|
9
9
|
"zaber-motion>=4.7.0,<5",
|
|
10
|
-
"pyobs-core>=2.0.0.
|
|
10
|
+
"pyobs-core>=2.0.0.dev48,<3",
|
|
11
11
|
]
|
|
12
12
|
|
|
13
13
|
[dependency-groups]
|
|
14
14
|
dev = [
|
|
15
|
-
"black>=25.1.0,<
|
|
15
|
+
"black>=25.1.0,<27",
|
|
16
16
|
"ruff>=0.9.0",
|
|
17
17
|
"pyrefly>=1.1.1",
|
|
18
18
|
"pre-commit>=4.2.0,<5",
|
|
19
|
+
"pytest>=8.0.0",
|
|
20
|
+
"pytest-asyncio>=0.24.0",
|
|
19
21
|
]
|
|
20
22
|
|
|
21
23
|
[build-system]
|
|
@@ -35,3 +37,6 @@ select = ["E", "F", "W", "I", "UP", "G"]
|
|
|
35
37
|
|
|
36
38
|
[tool.pyrefly]
|
|
37
39
|
python-version = "3.11"
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
asyncio_mode = "strict"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Smoke tests: import every public module and instantiate the driver class without
|
|
2
|
+
hardware, asserting it advertises the interfaces it claims.
|
|
3
|
+
|
|
4
|
+
No motor is involved: ZaberDriver only stores configuration, and the serial connection
|
|
5
|
+
is opened lazily inside each operation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pyobs.interfaces import IMode, IMotion
|
|
9
|
+
from pyobs.modules import Module
|
|
10
|
+
|
|
11
|
+
from pyobs_zaber import ZaberModeSelector
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_import_driver_module() -> None:
|
|
15
|
+
from pyobs_zaber import zaberdriver # noqa: F401
|
|
16
|
+
|
|
17
|
+
assert zaberdriver.ZaberDriver is not None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_instantiate_mode_selector() -> None:
|
|
21
|
+
selector = ZaberModeSelector(modes={"spec": 100.0, "phot": 200.0})
|
|
22
|
+
assert isinstance(selector, Module)
|
|
23
|
+
assert isinstance(selector, IMode)
|
|
24
|
+
assert isinstance(selector, IMotion)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Unit tests for the non-hardware logic in ZaberDriver."""
|
|
2
|
+
|
|
3
|
+
from contextlib import asynccontextmanager
|
|
4
|
+
from unittest.mock import AsyncMock, MagicMock
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from zaber_motion import Units
|
|
8
|
+
|
|
9
|
+
from pyobs_zaber.zaberdriver import ZaberDriver
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_constructor_defaults() -> None:
|
|
13
|
+
driver = ZaberDriver()
|
|
14
|
+
assert driver.port == "/dev/ttyUSB1"
|
|
15
|
+
assert driver.speed == 10000
|
|
16
|
+
assert driver.acceleration == 800
|
|
17
|
+
assert driver.length_unit is Units.ANGLE_DEGREES
|
|
18
|
+
assert driver.system_led is False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.mark.asyncio
|
|
22
|
+
async def test_move_by_defaults_to_configured_speed(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
23
|
+
axis = MagicMock()
|
|
24
|
+
axis.move_relative_async = AsyncMock()
|
|
25
|
+
|
|
26
|
+
@asynccontextmanager
|
|
27
|
+
async def fake_axis(port):
|
|
28
|
+
yield axis
|
|
29
|
+
|
|
30
|
+
monkeypatch.setattr("pyobs_zaber.zaberdriver.zaber_axis", fake_axis)
|
|
31
|
+
|
|
32
|
+
driver = ZaberDriver(speed=12345)
|
|
33
|
+
await driver.move_by(1.0)
|
|
34
|
+
|
|
35
|
+
axis.move_relative_async.assert_awaited_once_with(
|
|
36
|
+
1.0,
|
|
37
|
+
driver.length_unit,
|
|
38
|
+
velocity=12345,
|
|
39
|
+
velocity_unit=driver.speed_unit,
|
|
40
|
+
acceleration=driver.acceleration,
|
|
41
|
+
acceleration_unit=driver.acceleration_unit,
|
|
42
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Unit tests for the mode-selection state logic in ZaberModeSelector.
|
|
2
|
+
|
|
3
|
+
Movement itself is hardware I/O and is mocked out; these cover mode validation,
|
|
4
|
+
short-circuiting, and position mapping.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from unittest.mock import AsyncMock
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from pyobs_zaber import ZaberModeSelector
|
|
12
|
+
|
|
13
|
+
_MODES = {"spec": 100.0, "phot": 200.0}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _make_selector() -> tuple[ZaberModeSelector, AsyncMock]:
|
|
17
|
+
selector = ZaberModeSelector(modes=_MODES)
|
|
18
|
+
move_to = AsyncMock()
|
|
19
|
+
selector.driver.move_to = move_to # type: ignore[method-assign]
|
|
20
|
+
return selector, move_to
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_constructor_stores_modes_and_driver() -> None:
|
|
24
|
+
selector = ZaberModeSelector(modes=_MODES)
|
|
25
|
+
assert selector.modes == _MODES
|
|
26
|
+
assert selector.current_mode == "undefined"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.mark.asyncio
|
|
30
|
+
async def test_set_mode_moves_to_position() -> None:
|
|
31
|
+
selector, move_to = _make_selector()
|
|
32
|
+
await selector.set_mode("phot")
|
|
33
|
+
move_to.assert_awaited_once_with(200.0)
|
|
34
|
+
assert selector.current_mode == "phot"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.mark.asyncio
|
|
38
|
+
async def test_set_mode_unknown_mode_is_ignored() -> None:
|
|
39
|
+
selector, move_to = _make_selector()
|
|
40
|
+
await selector.set_mode("nope")
|
|
41
|
+
move_to.assert_not_awaited()
|
|
42
|
+
assert selector.current_mode == "undefined"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.mark.asyncio
|
|
46
|
+
async def test_set_mode_same_mode_is_noop() -> None:
|
|
47
|
+
selector, move_to = _make_selector()
|
|
48
|
+
await selector.set_mode("spec")
|
|
49
|
+
move_to.reset_mock()
|
|
50
|
+
await selector.set_mode("spec")
|
|
51
|
+
move_to.assert_not_awaited()
|
|
52
|
+
assert selector.current_mode == "spec"
|