Skip to content

Commit e909ce8

Browse files
authored
chore: update sources (#87)
* chore: update sources * chore: update version to 12.5.0.75.0 and reset PYMMCORE_NANO_VERSION to 0 * try remove * chore: update CI and deploy workflows to use TheMrMilchmann/setup-msvc-dev@v4 with architecture specification * Refactor code structure for improved readability and maintainability * test: add per-device timeout tests and update sequence acquisition keyword
1 parent a92547c commit e909ce8

9 files changed

Lines changed: 1951 additions & 852 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ jobs:
3232
- uses: astral-sh/setup-uv@v7
3333
with:
3434
enable-cache: true
35-
- uses: ilammy/msvc-dev-cmd@v1
35+
- uses: TheMrMilchmann/setup-msvc-dev@v4
3636
if: matrix.platform == 'windows-latest'
3737
with:
38-
vsversion: "2022"
38+
arch: x64
3939

4040
- name: install
4141
# install with coverage=true
@@ -72,10 +72,10 @@ jobs:
7272
with:
7373
python-version: "3.13"
7474
enable-cache: true
75-
- uses: ilammy/msvc-dev-cmd@v1
75+
- uses: TheMrMilchmann/setup-msvc-dev@v4
7676
if: matrix.os == 'windows-latest'
7777
with:
78-
vsversion: "2022"
78+
arch: x64
7979
- name: Setup MM test adapters
8080
uses: pymmcore-plus/setup-mm-test-adapters@main
8181
with:

.github/workflows/deploy.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ jobs:
4242
- uses: actions/checkout@v6
4343
with:
4444
fetch-depth: 0
45-
- uses: ilammy/msvc-dev-cmd@v1
45+
- uses: TheMrMilchmann/setup-msvc-dev@v4
46+
if: runner.os == 'Windows'
4647
with:
47-
vsversion: "2022"
48+
arch: x64
4849
- uses: astral-sh/setup-uv@v7
4950
- run: uv run scripts/extract_version.py --update
5051

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
project(
44
'pymmcore-nano',
55
'cpp',
6-
version : '12.2.0.75.1',
6+
version : '12.5.0.75.0',
77
meson_version : '>=1.4.0',
88
default_options : ['cpp_std=c++17']
99
)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ build = ["meson-python", "nanobind", "ninja", "ruff", "typing_extensions"]
4040
test = [
4141
"pytest",
4242
"pytest-cov",
43+
"pytest-rerunfailures",
4344
"gcovr",
4445
"libclang>=18.1.1",
4546
"pymmcore-nano[test-devices]",

src/_pymmcore_nano.cc

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace nb = nanobind;
1616

1717
using namespace nb::literals;
1818

19-
const std::string PYMMCORE_NANO_VERSION = "1";
19+
const std::string PYMMCORE_NANO_VERSION = "0";
2020

2121
///////////////// GIL_MACROS ///////////////////
2222

@@ -969,6 +969,10 @@ MMCore will send notifications on internal events using this interface
969969
.def("usesDeviceDelay", &CMMCore::usesDeviceDelay, "label"_a RGIL)
970970
.def("setTimeoutMs", &CMMCore::setTimeoutMs, "timeoutMs"_a RGIL)
971971
.def("getTimeoutMs", &CMMCore::getTimeoutMs RGIL)
972+
.def("setDeviceTimeoutMs", &CMMCore::setDeviceTimeoutMs, "label"_a, "timeoutMs"_a RGIL)
973+
.def("unsetDeviceTimeout", &CMMCore::unsetDeviceTimeout, "label"_a RGIL)
974+
.def("getDeviceTimeoutMs", &CMMCore::getDeviceTimeoutMs, "label"_a RGIL)
975+
.def("hasDeviceTimeout", &CMMCore::hasDeviceTimeout, "label"_a RGIL)
972976
.def("sleep", &CMMCore::sleep, "intervalMs"_a RGIL)
973977

974978
.def("getCameraDevice", &CMMCore::getCameraDevice RGIL)
@@ -1206,20 +1210,20 @@ MMCore will send notifications on internal events using this interface
12061210
.def("startSequenceAcquisition",
12071211
nb::overload_cast<long, double, bool>(&CMMCore::startSequenceAcquisition),
12081212
"numImages"_a,
1209-
"intervalMs"_a,
1213+
"unused"_a,
12101214
"stopOnOverflow"_a RGIL)
12111215
.def("startSequenceAcquisition",
12121216
nb::overload_cast<const char *, long, double, bool>(
12131217
&CMMCore::startSequenceAcquisition),
12141218
"cameraLabel"_a,
12151219
"numImages"_a,
1216-
"intervalMs"_a,
1220+
"unused"_a,
12171221
"stopOnOverflow"_a RGIL)
12181222
.def(
12191223
"prepareSequenceAcquisition", &CMMCore::prepareSequenceAcquisition, "cameraLabel"_a RGIL)
12201224
.def("startContinuousSequenceAcquisition",
12211225
&CMMCore::startContinuousSequenceAcquisition,
1222-
"intervalMs"_a RGIL)
1226+
"unused"_a RGIL)
12231227
.def("stopSequenceAcquisition", nb::overload_cast<>(&CMMCore::stopSequenceAcquisition) RGIL)
12241228
.def("stopSequenceAcquisition",
12251229
nb::overload_cast<const char *>(&CMMCore::stopSequenceAcquisition),

subprojects/mmcore.wrap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[wrap-git]
22
url = https://github.com/micro-manager/mmcore.git
3-
revision = 29e7de3344988e4b5886c4d7368f72fd61366e42
3+
revision = 8399a00b7210fd0775f3fe51392828a69c9aa57b
44
depth = 1
55

66
[provide]

subprojects/mmdevice.wrap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[wrap-git]
22
url = https://github.com/micro-manager/mmdevice.git
3-
revision = 7e648e90ec170dcdc1a798d596f9b358e4cd8eb6
3+
revision = b31dbbcca65a9a5120232518b9b061e81092a896
44
depth = 1
55

66
[provide]

tests/test_core.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ def test_device_loading(core: pmn.CMMCore) -> None:
152152

153153

154154
# have to use capfd to capture stderr, capsys won't work
155+
# Flaky on macOS CI: capfd occasionally returns partial/null-filled reads
156+
@pytest.mark.flaky(reruns=2)
155157
def test_core_logging(capfd: pytest.CaptureFixture, tmp_path: Path) -> None:
156158
mmc = pmn.CMMCore()
157159
# no file logging at start
@@ -211,6 +213,47 @@ def test_core(demo_core: pmn.CMMCore) -> None:
211213
assert isinstance(cfg, pmn.Configuration)
212214

213215

216+
def test_per_device_timeout(demo_core: pmn.CMMCore) -> None:
217+
global_timeout = demo_core.getTimeoutMs()
218+
219+
# No override is set initially; effective timeout equals global timeout.
220+
assert not demo_core.hasDeviceTimeout("Camera")
221+
assert demo_core.getDeviceTimeoutMs("Camera") == global_timeout
222+
223+
demo_core.setDeviceTimeoutMs("Camera", global_timeout + 1234)
224+
assert demo_core.hasDeviceTimeout("Camera")
225+
assert demo_core.getDeviceTimeoutMs("Camera") == global_timeout + 1234
226+
# Global timeout is unaffected by the per-device override.
227+
assert demo_core.getTimeoutMs() == global_timeout
228+
229+
demo_core.unsetDeviceTimeout("Camera")
230+
assert not demo_core.hasDeviceTimeout("Camera")
231+
assert demo_core.getDeviceTimeoutMs("Camera") == global_timeout
232+
233+
# The Core device cannot have a per-device override.
234+
assert not demo_core.hasDeviceTimeout("Core")
235+
assert demo_core.getDeviceTimeoutMs("Core") == global_timeout
236+
with pytest.raises(pmn.CMMError, match="Core device"):
237+
demo_core.setDeviceTimeoutMs("Core", 1000)
238+
239+
with pytest.raises(pmn.CMMError, match="must be positive"):
240+
demo_core.setDeviceTimeoutMs("Camera", 0)
241+
with pytest.raises(pmn.CMMError, match=r'No device with label "Bogus"'):
242+
demo_core.setDeviceTimeoutMs("Bogus", 1000)
243+
244+
245+
def test_sequence_acquisition_unused_kwarg(demo_core: pmn.CMMCore) -> None:
246+
# Upstream renamed the always-ignored `intervalMs` parameter to `unused`;
247+
# confirm the new keyword name is accepted by all three overloads.
248+
demo_core.startSequenceAcquisition(2, unused=0, stopOnOverflow=False)
249+
_wait_until(lambda: not demo_core.isSequenceRunning())
250+
demo_core.startSequenceAcquisition("Camera", 2, unused=0, stopOnOverflow=False)
251+
_wait_until(lambda: not demo_core.isSequenceRunning())
252+
demo_core.startContinuousSequenceAcquisition(unused=0)
253+
_wait_until(lambda: demo_core.isSequenceRunning())
254+
demo_core.stopSequenceAcquisition()
255+
256+
214257
def test_camera_snap(demo_core: pmn.CMMCore) -> None:
215258
assert demo_core.getCameraDevice() == "Camera"
216259
# change image dimensions to make it non-square

0 commit comments

Comments
 (0)