pymmcore-plus 0.11.0__py3-none-any.whl → 0.12.0__py3-none-any.whl
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.
- pymmcore_plus/_build.py +4 -1
- pymmcore_plus/_cli.py +7 -7
- pymmcore_plus/_logger.py +4 -1
- pymmcore_plus/_util.py +2 -1
- pymmcore_plus/core/_config.py +5 -3
- pymmcore_plus/core/_config_group.py +2 -1
- pymmcore_plus/core/_metadata.py +2 -2
- pymmcore_plus/core/_mmcore_plus.py +4 -6
- pymmcore_plus/core/_property.py +3 -1
- pymmcore_plus/core/_sequencing.py +8 -6
- pymmcore_plus/core/events/__init__.py +3 -3
- pymmcore_plus/core/events/_device_signal_view.py +8 -6
- pymmcore_plus/core/events/_norm_slot.py +2 -4
- pymmcore_plus/core/events/_prop_event_mixin.py +7 -4
- pymmcore_plus/core/events/_protocol.py +5 -2
- pymmcore_plus/install.py +4 -2
- pymmcore_plus/mda/_engine.py +5 -7
- pymmcore_plus/mda/_protocol.py +1 -1
- pymmcore_plus/mda/_runner.py +29 -21
- pymmcore_plus/mda/_thread_relay.py +5 -3
- pymmcore_plus/mda/handlers/_5d_writer_base.py +3 -1
- pymmcore_plus/mda/handlers/_img_sequence_writer.py +2 -1
- pymmcore_plus/mda/handlers/_ome_zarr_writer.py +6 -6
- pymmcore_plus/mda/handlers/_tensorstore_handler.py +3 -2
- pymmcore_plus/mda/handlers/_util.py +1 -1
- pymmcore_plus/metadata/functions.py +2 -2
- pymmcore_plus/metadata/schema.py +23 -23
- pymmcore_plus/metadata/serialize.py +5 -1
- pymmcore_plus/model/_config_file.py +2 -1
- pymmcore_plus/model/_config_group.py +2 -1
- pymmcore_plus/model/_core_device.py +3 -1
- pymmcore_plus/model/_core_link.py +2 -1
- pymmcore_plus/model/_device.py +2 -1
- pymmcore_plus/model/_microscope.py +4 -2
- pymmcore_plus/model/_pixel_size_config.py +3 -2
- pymmcore_plus/model/_property.py +2 -1
- {pymmcore_plus-0.11.0.dist-info → pymmcore_plus-0.12.0.dist-info}/METADATA +5 -6
- pymmcore_plus-0.12.0.dist-info/RECORD +59 -0
- pymmcore_plus-0.11.0.dist-info/RECORD +0 -59
- {pymmcore_plus-0.11.0.dist-info → pymmcore_plus-0.12.0.dist-info}/WHEEL +0 -0
- {pymmcore_plus-0.11.0.dist-info → pymmcore_plus-0.12.0.dist-info}/entry_points.txt +0 -0
- {pymmcore_plus-0.11.0.dist-info → pymmcore_plus-0.12.0.dist-info}/licenses/LICENSE +0 -0
pymmcore_plus/_build.py
CHANGED
|
@@ -11,12 +11,15 @@ import subprocess
|
|
|
11
11
|
import tempfile
|
|
12
12
|
from contextlib import contextmanager
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
from typing import
|
|
14
|
+
from typing import TYPE_CHECKING
|
|
15
15
|
from urllib.request import Request, urlopen
|
|
16
16
|
|
|
17
17
|
from rich import print
|
|
18
18
|
from rich.prompt import Prompt
|
|
19
19
|
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from collections.abc import Iterator, Sequence
|
|
22
|
+
|
|
20
23
|
MM_REPO = "micro-manager/micro-manager"
|
|
21
24
|
MMCORE_AND_DEV = "micro-manager/mmCoreAndDevices"
|
|
22
25
|
MM_REPO_URL = f"https://github.com/{MM_REPO}.git"
|
pymmcore_plus/_cli.py
CHANGED
|
@@ -6,7 +6,7 @@ import sys
|
|
|
6
6
|
import time
|
|
7
7
|
from contextlib import suppress
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import Optional, Union, cast
|
|
10
10
|
|
|
11
11
|
try:
|
|
12
12
|
import typer
|
|
@@ -31,7 +31,7 @@ def _show_version_and_exit(value: bool) -> None:
|
|
|
31
31
|
import pymmcore
|
|
32
32
|
|
|
33
33
|
typer.echo(f"pymmcore-plus v{pymmcore_plus.__version__}")
|
|
34
|
-
typer.echo(f"pymmcore v{pymmcore.__version__}")
|
|
34
|
+
typer.echo(f"pymmcore v{pymmcore.__version__}")
|
|
35
35
|
typer.echo(f"MMCore v{pymmcore.CMMCore().getAPIVersionInfo()}")
|
|
36
36
|
raise typer.Exit()
|
|
37
37
|
|
|
@@ -53,7 +53,7 @@ def _main(
|
|
|
53
53
|
# fix for windows CI encoding and emoji printing
|
|
54
54
|
if getattr(sys.stdout, "encoding", None) != "utf-8":
|
|
55
55
|
with suppress(AttributeError):
|
|
56
|
-
sys.stdout.reconfigure(encoding="utf-8") # type: ignore [attr
|
|
56
|
+
sys.stdout.reconfigure(encoding="utf-8") # type: ignore [union-attr]
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
if "mkdocs" in sys.argv[0]: # pragma: no cover
|
|
@@ -190,10 +190,10 @@ def run(
|
|
|
190
190
|
None, help="Asymmetric range of z-stack below position."
|
|
191
191
|
),
|
|
192
192
|
z_step: Optional[float] = typer.Option(None, help="Step size of z-stack."),
|
|
193
|
-
z_relative: Optional[
|
|
193
|
+
z_relative: Optional[list[float]] = typer.Option(
|
|
194
194
|
None, "-zr", help="Relative z-positions to acquire (may use multiple times)."
|
|
195
195
|
),
|
|
196
|
-
z_absolute: Optional[
|
|
196
|
+
z_absolute: Optional[list[float]] = typer.Option(
|
|
197
197
|
None, "-za", help="Absolute z-positions to acquire (may use multiple times)."
|
|
198
198
|
),
|
|
199
199
|
t_interval: Optional[float] = typer.Option(
|
|
@@ -207,7 +207,7 @@ def run(
|
|
|
207
207
|
axis_order: Optional[str] = typer.Option(
|
|
208
208
|
None, help="Order of axes to acquire (e.g. 'TPCZ')."
|
|
209
209
|
),
|
|
210
|
-
channel: Optional[
|
|
210
|
+
channel: Optional[list[str]] = typer.Option(
|
|
211
211
|
None,
|
|
212
212
|
help="\bChannel to acquire. Argument is a string of the following form:\n"
|
|
213
213
|
'\b - name: "DAPI"\n'
|
|
@@ -294,7 +294,7 @@ def run(
|
|
|
294
294
|
|
|
295
295
|
@app.command()
|
|
296
296
|
def build_dev(
|
|
297
|
-
devices: Optional[
|
|
297
|
+
devices: Optional[list[str]] = typer.Argument(
|
|
298
298
|
None, help=f"Device adapters to build. Defaults to {DEFAULT_PACKAGES}"
|
|
299
299
|
),
|
|
300
300
|
dest: Path = typer.Option(
|
pymmcore_plus/_logger.py
CHANGED
|
@@ -6,7 +6,10 @@ import sys
|
|
|
6
6
|
from contextlib import contextmanager
|
|
7
7
|
from logging.handlers import RotatingFileHandler
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Iterator
|
|
10
13
|
|
|
11
14
|
__all__ = ["logger"]
|
|
12
15
|
|
pymmcore_plus/_util.py
CHANGED
|
@@ -18,8 +18,9 @@ from typing import TYPE_CHECKING, cast, overload
|
|
|
18
18
|
from platformdirs import user_data_dir
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
|
+
from collections.abc import Iterator
|
|
21
22
|
from re import Pattern
|
|
22
|
-
from typing import Any, Callable,
|
|
23
|
+
from typing import Any, Callable, Literal, TypeVar
|
|
23
24
|
|
|
24
25
|
QtConnectionType = Literal["AutoConnection", "DirectConnection", "QueuedConnection"]
|
|
25
26
|
|
pymmcore_plus/core/_config.py
CHANGED
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from collections import defaultdict
|
|
6
|
-
from typing import TYPE_CHECKING, Any,
|
|
6
|
+
from typing import TYPE_CHECKING, Any, overload
|
|
7
7
|
|
|
8
8
|
import pymmcore
|
|
9
9
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Iterable, Iterator
|
|
12
|
+
|
|
11
13
|
from typing_extensions import TypeAlias # py310
|
|
12
14
|
|
|
13
|
-
DevPropValueTuple: TypeAlias =
|
|
14
|
-
DevPropTuple: TypeAlias =
|
|
15
|
+
DevPropValueTuple: TypeAlias = tuple[str, str, str]
|
|
16
|
+
DevPropTuple: TypeAlias = tuple[str, str]
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class Configuration(pymmcore.Configuration):
|
pymmcore_plus/core/_metadata.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""pythonic wrapper on pymmcore.Metadata object."""
|
|
2
2
|
|
|
3
|
-
from collections.abc import Mapping
|
|
3
|
+
from collections.abc import ItemsView, Iterator, KeysView, Mapping, ValuesView
|
|
4
4
|
from types import new_class
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, cast
|
|
6
6
|
|
|
7
7
|
import pymmcore
|
|
8
8
|
|
|
@@ -10,17 +10,14 @@ from collections import defaultdict
|
|
|
10
10
|
from contextlib import contextmanager, suppress
|
|
11
11
|
from datetime import datetime
|
|
12
12
|
from pathlib import Path
|
|
13
|
+
from re import Pattern
|
|
13
14
|
from textwrap import dedent
|
|
14
15
|
from threading import RLock, Thread
|
|
15
16
|
from typing import (
|
|
16
17
|
TYPE_CHECKING,
|
|
17
18
|
Any,
|
|
18
19
|
Callable,
|
|
19
|
-
Iterable,
|
|
20
|
-
Iterator,
|
|
21
20
|
NamedTuple,
|
|
22
|
-
Pattern,
|
|
23
|
-
Sequence,
|
|
24
21
|
TypeVar,
|
|
25
22
|
overload,
|
|
26
23
|
)
|
|
@@ -51,6 +48,7 @@ from ._sequencing import can_sequence_events
|
|
|
51
48
|
from .events import CMMCoreSignaler, PCoreSignaler, _get_auto_core_callback_class
|
|
52
49
|
|
|
53
50
|
if TYPE_CHECKING:
|
|
51
|
+
from collections.abc import Iterable, Iterator, Sequence
|
|
54
52
|
from typing import Literal, TypedDict
|
|
55
53
|
|
|
56
54
|
import numpy as np
|
|
@@ -1594,7 +1592,7 @@ class CMMCorePlus(pymmcore.CMMCore):
|
|
|
1594
1592
|
|
|
1595
1593
|
try:
|
|
1596
1594
|
channel_group = self.getPropertyFromCache("Core", "ChannelGroup")
|
|
1597
|
-
channel = self.getCurrentConfigFromCache(channel_group)
|
|
1595
|
+
channel: str = self.getCurrentConfigFromCache(channel_group)
|
|
1598
1596
|
except Exception:
|
|
1599
1597
|
channel = "Default"
|
|
1600
1598
|
tags["Channel"] = channel
|
|
@@ -2010,7 +2008,7 @@ class CMMCorePlus(pymmcore.CMMCore):
|
|
|
2010
2008
|
|
|
2011
2009
|
:sparkles: *This method is new in `CMMCorePlus`.*
|
|
2012
2010
|
"""
|
|
2013
|
-
_current = {
|
|
2011
|
+
_current: dict[str, str] = {
|
|
2014
2012
|
self.getCameraDevice(): "Camera",
|
|
2015
2013
|
self.getXYStageDevice(): "XYStage",
|
|
2016
2014
|
self.getFocusDevice(): "Focus",
|
pymmcore_plus/core/_property.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from functools import cached_property
|
|
4
|
-
from typing import TYPE_CHECKING, Any,
|
|
4
|
+
from typing import TYPE_CHECKING, Any, TypedDict
|
|
5
5
|
|
|
6
6
|
from pymmcore import g_Keyword_Label, g_Keyword_State
|
|
7
7
|
|
|
@@ -9,6 +9,8 @@ from ._constants import DeviceType, PropertyType
|
|
|
9
9
|
from .events._device_signal_view import _DevicePropValueSignal
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
|
|
12
14
|
from ._mmcore_plus import CMMCorePlus
|
|
13
15
|
|
|
14
16
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from itertools import product
|
|
4
|
-
from typing import TYPE_CHECKING, Literal,
|
|
4
|
+
from typing import TYPE_CHECKING, Literal, overload
|
|
5
5
|
|
|
6
6
|
from useq import AcquireImage, MDAEvent
|
|
7
7
|
|
|
8
8
|
from pymmcore_plus.core._constants import DeviceType
|
|
9
9
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Sequence
|
|
12
|
+
|
|
11
13
|
from pymmcore_plus import CMMCorePlus
|
|
12
14
|
|
|
13
15
|
|
|
@@ -18,12 +20,12 @@ class SequencedEvent(MDAEvent):
|
|
|
18
20
|
calculate sequences for x, y, z, and exposure based on an a sequence of events.
|
|
19
21
|
"""
|
|
20
22
|
|
|
21
|
-
events:
|
|
23
|
+
events: tuple[MDAEvent, ...]
|
|
22
24
|
|
|
23
|
-
exposure_sequence:
|
|
24
|
-
x_sequence:
|
|
25
|
-
y_sequence:
|
|
26
|
-
z_sequence:
|
|
25
|
+
exposure_sequence: tuple[float, ...]
|
|
26
|
+
x_sequence: tuple[float, ...]
|
|
27
|
+
y_sequence: tuple[float, ...]
|
|
28
|
+
z_sequence: tuple[float, ...]
|
|
27
29
|
|
|
28
30
|
# technically this is more like a field, but it requires a core instance
|
|
29
31
|
# to getConfigData for channels, so we leave it as a method.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, Any
|
|
1
|
+
from typing import TYPE_CHECKING, Any
|
|
2
2
|
|
|
3
3
|
from pymmcore_plus._util import signals_backend
|
|
4
4
|
|
|
@@ -18,7 +18,7 @@ __all__ = [
|
|
|
18
18
|
]
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
def _get_auto_core_callback_class() ->
|
|
21
|
+
def _get_auto_core_callback_class() -> type[PCoreSignaler]:
|
|
22
22
|
if signals_backend() == "qt":
|
|
23
23
|
from ._qsignals import QCoreSignaler
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ def _get_auto_core_callback_class() -> Type[PCoreSignaler]:
|
|
|
26
26
|
return CMMCoreSignaler
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
def __dir__() ->
|
|
29
|
+
def __dir__() -> list[str]: # pragma: no cover
|
|
30
30
|
return [*list(globals()), "QCoreSignaler"]
|
|
31
31
|
|
|
32
32
|
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
2
4
|
|
|
3
5
|
if TYPE_CHECKING:
|
|
4
6
|
from pymmcore_plus.core import CMMCorePlus
|
|
5
7
|
|
|
6
|
-
from ._prop_event_mixin import _C
|
|
8
|
+
from ._prop_event_mixin import _C
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
class _DevicePropValueSignal:
|
|
10
12
|
def __init__(
|
|
11
|
-
self, device_label: str, property_name:
|
|
13
|
+
self, device_label: str, property_name: str | None, mmcore: CMMCorePlus
|
|
12
14
|
) -> None:
|
|
13
15
|
self._dev = device_label
|
|
14
16
|
self._prop = property_name
|
|
@@ -18,13 +20,13 @@ class _DevicePropValueSignal:
|
|
|
18
20
|
sig = self._mmc.events.devicePropertyChanged(self._dev, self._prop)
|
|
19
21
|
return sig.connect(callback) # type: ignore
|
|
20
22
|
|
|
21
|
-
def disconnect(self, callback: _C) -> None:
|
|
23
|
+
def disconnect(self, callback: _C | None = None) -> None:
|
|
22
24
|
sig = self._mmc.events.devicePropertyChanged(self._dev, self._prop)
|
|
23
|
-
|
|
25
|
+
sig.disconnect(callback)
|
|
24
26
|
|
|
25
27
|
def emit(self, *args: Any) -> Any:
|
|
26
28
|
"""Emits the signal with the given arguments."""
|
|
27
29
|
self._mmc.events.devicePropertyChanged(self._dev, self._prop).emit(*args)
|
|
28
30
|
|
|
29
|
-
def __call__(self, property: str) ->
|
|
31
|
+
def __call__(self, property: str) -> _DevicePropValueSignal:
|
|
30
32
|
return _DevicePropValueSignal(self._dev, property, self._mmc)
|
|
@@ -8,13 +8,11 @@ from types import MethodType
|
|
|
8
8
|
from typing import TYPE_CHECKING, Any, Callable, Union
|
|
9
9
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
|
-
from typing import Tuple
|
|
12
|
-
|
|
13
11
|
from typing_extensions import TypeGuard # py310
|
|
14
12
|
|
|
15
|
-
MethodRef =
|
|
13
|
+
MethodRef = tuple[weakref.ReferenceType[object], str, Callable | None]
|
|
16
14
|
NormedCallback = Union[MethodRef, Callable]
|
|
17
|
-
StoredSlot =
|
|
15
|
+
StoredSlot = tuple[NormedCallback, int | None]
|
|
18
16
|
ReducerFunc = Callable[[tuple, tuple], tuple]
|
|
19
17
|
|
|
20
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Callable, ClassVar,
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Callable, ClassVar, TypeVar
|
|
4
4
|
|
|
5
5
|
from ._norm_slot import denormalize_slot, normalize_slot
|
|
6
6
|
from ._protocol import PCoreSignaler
|
|
@@ -8,8 +8,8 @@ from ._protocol import PCoreSignaler
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
9
|
from ._norm_slot import NormedCallback
|
|
10
10
|
|
|
11
|
-
PropKey =
|
|
12
|
-
PropKeyDict =
|
|
11
|
+
PropKey = tuple[str, str | None, NormedCallback]
|
|
12
|
+
PropKeyDict = dict[PropKey, Callable]
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
_C = TypeVar("_C", bound=Callable[..., Any])
|
|
@@ -64,8 +64,11 @@ class _PropertySignal:
|
|
|
64
64
|
self._events.propertyChanged.connect(_wrapper)
|
|
65
65
|
return callback
|
|
66
66
|
|
|
67
|
-
def disconnect(self, callback: Callable) -> None:
|
|
67
|
+
def disconnect(self, callback: Callable | None = None) -> None:
|
|
68
68
|
"""Disconnect `callback` from this device and/or property."""
|
|
69
|
+
if callback is None:
|
|
70
|
+
self._events.propertyChanged.disconnect()
|
|
71
|
+
return
|
|
69
72
|
key = (self._device, self._property, normalize_slot(callback))
|
|
70
73
|
cb = self._events.property_callbacks.pop(key, None)
|
|
71
74
|
if cb is None:
|
|
@@ -12,8 +12,11 @@ class PSignalInstance(Protocol):
|
|
|
12
12
|
def connect(self, slot: Callable) -> Any:
|
|
13
13
|
"""Connect slot to this signal."""
|
|
14
14
|
|
|
15
|
-
def disconnect(self, slot: Callable) -> Any:
|
|
16
|
-
"""Disconnect slot from this signal.
|
|
15
|
+
def disconnect(self, slot: Optional[Callable] = None) -> Any:
|
|
16
|
+
"""Disconnect slot from this signal.
|
|
17
|
+
|
|
18
|
+
If `None`, all slots should be disconnected.
|
|
19
|
+
"""
|
|
17
20
|
|
|
18
21
|
def emit(self, *args: Any) -> Any:
|
|
19
22
|
"""Emits the signal with the given arguments."""
|
pymmcore_plus/install.py
CHANGED
|
@@ -10,7 +10,7 @@ import tempfile
|
|
|
10
10
|
from contextlib import contextmanager, nullcontext
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
from platform import system
|
|
13
|
-
from typing import TYPE_CHECKING, Callable,
|
|
13
|
+
from typing import TYPE_CHECKING, Callable, Protocol
|
|
14
14
|
from urllib.request import urlopen, urlretrieve
|
|
15
15
|
|
|
16
16
|
import typer
|
|
@@ -18,6 +18,8 @@ import typer
|
|
|
18
18
|
from pymmcore_plus._util import USER_DATA_MM_PATH
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
|
+
from collections.abc import Iterator
|
|
22
|
+
from contextlib import AbstractContextManager
|
|
21
23
|
|
|
22
24
|
class _MsgLogger(Protocol):
|
|
23
25
|
def __call__(self, text: str, color: str = "", emoji: str = "") -> None: ...
|
|
@@ -70,7 +72,7 @@ def _get_download_name(url: str) -> str:
|
|
|
70
72
|
return ""
|
|
71
73
|
|
|
72
74
|
|
|
73
|
-
def _get_spinner(log_msg: _MsgLogger) -> Callable[[str],
|
|
75
|
+
def _get_spinner(log_msg: _MsgLogger) -> Callable[[str], AbstractContextManager]:
|
|
74
76
|
if log_msg is _pretty_print:
|
|
75
77
|
spinner = _spinner
|
|
76
78
|
else:
|
pymmcore_plus/mda/_engine.py
CHANGED
|
@@ -5,10 +5,7 @@ from contextlib import suppress
|
|
|
5
5
|
from itertools import product
|
|
6
6
|
from typing import (
|
|
7
7
|
TYPE_CHECKING,
|
|
8
|
-
Iterable,
|
|
9
|
-
Iterator,
|
|
10
8
|
NamedTuple,
|
|
11
|
-
Sequence,
|
|
12
9
|
cast,
|
|
13
10
|
)
|
|
14
11
|
|
|
@@ -29,6 +26,8 @@ from pymmcore_plus.metadata import (
|
|
|
29
26
|
from ._protocol import PMDAEngine
|
|
30
27
|
|
|
31
28
|
if TYPE_CHECKING:
|
|
29
|
+
from collections.abc import Iterable, Iterator, Sequence
|
|
30
|
+
|
|
32
31
|
from numpy.typing import NDArray
|
|
33
32
|
|
|
34
33
|
from pymmcore_plus.core import CMMCorePlus
|
|
@@ -54,12 +53,11 @@ class MDAEngine(PMDAEngine):
|
|
|
54
53
|
attempt to combine MDAEvents into a single `SequencedEvent` if
|
|
55
54
|
[`core.canSequenceEvents()`][pymmcore_plus.CMMCorePlus.canSequenceEvents]
|
|
56
55
|
reports that the events can be sequenced. This can be set after instantiation.
|
|
57
|
-
By default, this is `
|
|
58
|
-
|
|
59
|
-
set to `True` to improve performance.
|
|
56
|
+
By default, this is `True`, however in various testing and demo scenarios, you
|
|
57
|
+
may wish to set it to `False` in order to avoid unexpected behavior.
|
|
60
58
|
"""
|
|
61
59
|
|
|
62
|
-
def __init__(self, mmc: CMMCorePlus, use_hardware_sequencing: bool =
|
|
60
|
+
def __init__(self, mmc: CMMCorePlus, use_hardware_sequencing: bool = True) -> None:
|
|
63
61
|
self._mmc = mmc
|
|
64
62
|
self.use_hardware_sequencing = use_hardware_sequencing
|
|
65
63
|
|
pymmcore_plus/mda/_protocol.py
CHANGED
|
@@ -4,7 +4,7 @@ from abc import abstractmethod
|
|
|
4
4
|
from typing import TYPE_CHECKING, Protocol, runtime_checkable
|
|
5
5
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
7
|
-
from
|
|
7
|
+
from collections.abc import Iterable, Iterator
|
|
8
8
|
|
|
9
9
|
from numpy.typing import NDArray
|
|
10
10
|
from useq import MDAEvent, MDASequence
|
pymmcore_plus/mda/_runner.py
CHANGED
|
@@ -2,17 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
4
|
import warnings
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Iterable, Iterator, Sequence
|
|
6
|
+
from contextlib import AbstractContextManager, nullcontext
|
|
6
7
|
from pathlib import Path
|
|
7
|
-
from typing import
|
|
8
|
-
TYPE_CHECKING,
|
|
9
|
-
Any,
|
|
10
|
-
ContextManager,
|
|
11
|
-
Iterable,
|
|
12
|
-
Iterator,
|
|
13
|
-
Sequence,
|
|
14
|
-
Tuple,
|
|
15
|
-
)
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
16
9
|
from unittest.mock import MagicMock
|
|
17
10
|
|
|
18
11
|
from useq import MDASequence
|
|
@@ -39,7 +32,7 @@ MSG = (
|
|
|
39
32
|
|
|
40
33
|
|
|
41
34
|
class GeneratorMDASequence(MDASequence):
|
|
42
|
-
axis_order:
|
|
35
|
+
axis_order: tuple[str, ...] = ()
|
|
43
36
|
|
|
44
37
|
@property
|
|
45
38
|
def sizes(self) -> dict[str, int]: # pragma: no cover
|
|
@@ -77,7 +70,10 @@ class MDARunner:
|
|
|
77
70
|
|
|
78
71
|
self._canceled = False
|
|
79
72
|
self._sequence: MDASequence | None = None
|
|
80
|
-
|
|
73
|
+
# timer for the full sequence, reset only once at the beginning of the sequence
|
|
74
|
+
self._sequence_t0: float = 0.0
|
|
75
|
+
# event clock, reset whenever `event.reset_event_timer` is True
|
|
76
|
+
self._t0: float = 0.0
|
|
81
77
|
|
|
82
78
|
def set_engine(self, engine: PMDAEngine) -> PMDAEngine | None:
|
|
83
79
|
"""Set the [`PMDAEngine`][pymmcore_plus.mda.PMDAEngine] to use for the MDA run.""" # noqa: E501
|
|
@@ -212,11 +208,19 @@ class MDARunner:
|
|
|
212
208
|
|
|
213
209
|
def seconds_elapsed(self) -> float:
|
|
214
210
|
"""Return the number of seconds since the start of the acquisition."""
|
|
211
|
+
return time.perf_counter() - self._sequence_t0
|
|
212
|
+
|
|
213
|
+
def event_seconds_elapsed(self) -> float:
|
|
214
|
+
"""Return the number of seconds on the "event clock".
|
|
215
|
+
|
|
216
|
+
This is the time since either the start of the acquisition or the last
|
|
217
|
+
event with `reset_event_timer` set to `True`.
|
|
218
|
+
"""
|
|
215
219
|
return time.perf_counter() - self._t0
|
|
216
220
|
|
|
217
221
|
def _outputs_connected(
|
|
218
222
|
self, output: SingleOutput | Sequence[SingleOutput] | None
|
|
219
|
-
) ->
|
|
223
|
+
) -> AbstractContextManager:
|
|
220
224
|
"""Context in which output handlers are connected to the frameReady signal."""
|
|
221
225
|
if output is None:
|
|
222
226
|
return nullcontext()
|
|
@@ -272,9 +276,12 @@ class MDARunner:
|
|
|
272
276
|
teardown_event = getattr(engine, "teardown_event", lambda e: None)
|
|
273
277
|
event_iterator = getattr(engine, "event_iterator", iter)
|
|
274
278
|
_events: Iterator[MDAEvent] = event_iterator(events)
|
|
275
|
-
self.
|
|
279
|
+
self._reset_event_timer()
|
|
280
|
+
self._sequence_t0 = self._t0
|
|
276
281
|
|
|
277
282
|
for event in _events:
|
|
283
|
+
if event.reset_event_timer:
|
|
284
|
+
self._reset_event_timer()
|
|
278
285
|
# If cancelled break out of the loop
|
|
279
286
|
if self._wait_until_event(event) or not self._running:
|
|
280
287
|
break
|
|
@@ -284,17 +291,18 @@ class MDARunner:
|
|
|
284
291
|
engine.setup_event(event)
|
|
285
292
|
|
|
286
293
|
try:
|
|
287
|
-
|
|
294
|
+
runner_time_ms = self.seconds_elapsed() * 1000
|
|
288
295
|
# this is a bit of a hack to pass the time into the engine
|
|
289
|
-
# it is used for intra-event time calculations
|
|
296
|
+
# it is used for intra-event time calculations inside the engine.
|
|
290
297
|
# we pop it off after the event is executed.
|
|
291
|
-
event.metadata["runner_t0"] = self.
|
|
298
|
+
event.metadata["runner_t0"] = self._sequence_t0
|
|
292
299
|
output = engine.exec_event(event) or () # in case output is None
|
|
293
300
|
for payload in output:
|
|
294
301
|
img, event, meta = payload
|
|
295
302
|
event.metadata.pop("runner_t0", None)
|
|
303
|
+
# if the engine calculated its own time, don't overwrite it
|
|
296
304
|
if "runner_time_ms" not in meta:
|
|
297
|
-
meta["runner_time_ms"] =
|
|
305
|
+
meta["runner_time_ms"] = runner_time_ms
|
|
298
306
|
with exceptions_logged():
|
|
299
307
|
self._signals.frameReady.emit(img, event, meta)
|
|
300
308
|
finally:
|
|
@@ -321,7 +329,7 @@ class MDARunner:
|
|
|
321
329
|
logger.info("MDA Started: %s", sequence)
|
|
322
330
|
return self._engine
|
|
323
331
|
|
|
324
|
-
def
|
|
332
|
+
def _reset_event_timer(self) -> None:
|
|
325
333
|
self._t0 = time.perf_counter() # reference time, in seconds
|
|
326
334
|
|
|
327
335
|
def _check_canceled(self) -> bool:
|
|
@@ -374,7 +382,7 @@ class MDARunner:
|
|
|
374
382
|
go_at = event.min_start_time + self._paused_time
|
|
375
383
|
# We need to enter a loop here checking paused and canceled.
|
|
376
384
|
# otherwise you'll potentially wait a long time to cancel
|
|
377
|
-
remaining_wait_time = go_at - self.
|
|
385
|
+
remaining_wait_time = go_at - self.event_seconds_elapsed()
|
|
378
386
|
while remaining_wait_time > 0:
|
|
379
387
|
self._signals.awaitingEvent.emit(event, remaining_wait_time)
|
|
380
388
|
while self._paused and not self._canceled:
|
|
@@ -385,7 +393,7 @@ class MDARunner:
|
|
|
385
393
|
if self._canceled:
|
|
386
394
|
break
|
|
387
395
|
time.sleep(min(remaining_wait_time, 0.5))
|
|
388
|
-
remaining_wait_time = go_at - self.
|
|
396
|
+
remaining_wait_time = go_at - self.event_seconds_elapsed()
|
|
389
397
|
|
|
390
398
|
# check canceled again in case it was canceled
|
|
391
399
|
# during the waiting loop
|
|
@@ -11,7 +11,9 @@ from pymmcore_plus._util import listeners_connected
|
|
|
11
11
|
from .events import _get_auto_MDA_callback_class
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
|
-
from
|
|
14
|
+
from collections.abc import Iterator
|
|
15
|
+
from contextlib import AbstractContextManager
|
|
16
|
+
from typing import Any
|
|
15
17
|
|
|
16
18
|
from pymmcore_plus.core.events._protocol import PSignalInstance
|
|
17
19
|
from pymmcore_plus.mda import PMDASignaler
|
|
@@ -24,7 +26,7 @@ def mda_listeners_connected(
|
|
|
24
26
|
name_map: dict[str, str] | None = ...,
|
|
25
27
|
asynchronous: Literal[False],
|
|
26
28
|
wait_on_exit: bool = ...,
|
|
27
|
-
) ->
|
|
29
|
+
) -> AbstractContextManager[None]: ...
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
@overload
|
|
@@ -34,7 +36,7 @@ def mda_listeners_connected(
|
|
|
34
36
|
name_map: dict[str, str] | None = ...,
|
|
35
37
|
asynchronous: Literal[True] = ...,
|
|
36
38
|
wait_on_exit: bool = ...,
|
|
37
|
-
) ->
|
|
39
|
+
) -> AbstractContextManager[MDARelayThread]: ...
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
@contextmanager
|
|
@@ -3,11 +3,13 @@ from __future__ import annotations
|
|
|
3
3
|
import warnings
|
|
4
4
|
from abc import abstractmethod
|
|
5
5
|
from collections import defaultdict
|
|
6
|
-
from typing import TYPE_CHECKING, Generic,
|
|
6
|
+
from typing import TYPE_CHECKING, Generic, Protocol, TypeVar
|
|
7
7
|
|
|
8
8
|
from ._util import position_sizes
|
|
9
9
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Mapping
|
|
12
|
+
|
|
11
13
|
import numpy as np
|
|
12
14
|
import useq
|
|
13
15
|
|
|
@@ -7,9 +7,10 @@ provided.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
from collections.abc import Mapping, Sequence
|
|
10
11
|
from itertools import count
|
|
11
12
|
from pathlib import Path
|
|
12
|
-
from typing import TYPE_CHECKING, Any, Callable, ClassVar,
|
|
13
|
+
from typing import TYPE_CHECKING, Any, Callable, ClassVar, cast
|
|
13
14
|
|
|
14
15
|
from pymmcore_plus.metadata.serialize import json_dumps
|
|
15
16
|
|
|
@@ -6,7 +6,7 @@ import os.path
|
|
|
6
6
|
import shutil
|
|
7
7
|
import tempfile
|
|
8
8
|
from contextlib import suppress
|
|
9
|
-
from typing import TYPE_CHECKING, Any, Literal,
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Literal, Protocol
|
|
10
10
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
|
|
@@ -15,8 +15,10 @@ from pymmcore_plus.metadata.serialize import to_builtins
|
|
|
15
15
|
from ._5d_writer_base import _5DWriterBase
|
|
16
16
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
|
+
from collections.abc import MutableMapping, Sequence
|
|
19
|
+
from contextlib import AbstractAsyncContextManager
|
|
18
20
|
from os import PathLike
|
|
19
|
-
from typing import
|
|
21
|
+
from typing import TypedDict
|
|
20
22
|
|
|
21
23
|
import xarray as xr
|
|
22
24
|
import zarr
|
|
@@ -24,7 +26,7 @@ if TYPE_CHECKING:
|
|
|
24
26
|
from numcodecs.abc import Codec
|
|
25
27
|
|
|
26
28
|
class ZarrSynchronizer(Protocol):
|
|
27
|
-
def __getitem__(self, key: str) ->
|
|
29
|
+
def __getitem__(self, key: str) -> AbstractAsyncContextManager: ...
|
|
28
30
|
|
|
29
31
|
class ArrayCreationKwargs(TypedDict, total=False):
|
|
30
32
|
compressor: str | Codec
|
|
@@ -276,9 +278,7 @@ class OMEZarrWriter(_5DWriterBase["zarr.Array"]):
|
|
|
276
278
|
self._group.attrs["multiscales"] = scales
|
|
277
279
|
ary.attrs["_ARRAY_DIMENSIONS"] = dims
|
|
278
280
|
if seq := self.current_sequence:
|
|
279
|
-
ary.attrs["useq_MDASequence"] = to_builtins(
|
|
280
|
-
seq.model_dump(exclude_unset=True)
|
|
281
|
-
)
|
|
281
|
+
ary.attrs["useq_MDASequence"] = to_builtins(seq)
|
|
282
282
|
|
|
283
283
|
return ary
|
|
284
284
|
|
|
@@ -14,7 +14,8 @@ from pymmcore_plus.metadata.serialize import json_dumps, json_loads
|
|
|
14
14
|
from ._util import position_sizes
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
|
-
from
|
|
17
|
+
from collections.abc import Mapping, Sequence
|
|
18
|
+
from typing import Literal, TypeAlias
|
|
18
19
|
|
|
19
20
|
import numpy as np
|
|
20
21
|
import tensorstore as ts
|
|
@@ -258,7 +259,7 @@ class TensorStoreHandler:
|
|
|
258
259
|
# expand the sizes to include the largest size we encounter for each axis
|
|
259
260
|
# in the case of positions with subsequences, we'll still end up with a
|
|
260
261
|
# jagged array, but it won't take extra space, and we won't get index errors
|
|
261
|
-
max_sizes = seq.sizes
|
|
262
|
+
max_sizes = dict(seq.sizes)
|
|
262
263
|
for psize in position_sizes(seq):
|
|
263
264
|
for k, v in psize.items():
|
|
264
265
|
max_sizes[k] = max(max_sizes.get(k, 0), v)
|
|
@@ -29,7 +29,7 @@ def position_sizes(seq: useq.MDASequence) -> list[dict[str, int]]:
|
|
|
29
29
|
`{dim: size}` pairs for each dimension in the sequence. Dimensions with no size
|
|
30
30
|
will be omitted, though singletons will be included.
|
|
31
31
|
"""
|
|
32
|
-
main_sizes = seq.sizes
|
|
32
|
+
main_sizes = dict(seq.sizes)
|
|
33
33
|
main_sizes.pop("p", None) # remove position
|
|
34
34
|
|
|
35
35
|
if not seq.stage_positions:
|
|
@@ -180,7 +180,7 @@ def image_info(core: CMMCorePlus) -> ImageInfo:
|
|
|
180
180
|
if (mag_factor := core.getMagnificationFactor()) != 1.0:
|
|
181
181
|
info["magnification_factor"] = mag_factor
|
|
182
182
|
if (affine := core.getPixelSizeAffine(True)) != (1.0, 0.0, 0.0, 0.0, 1.0, 0.0):
|
|
183
|
-
info["pixel_size_affine"] = affine
|
|
183
|
+
info["pixel_size_affine"] = affine
|
|
184
184
|
|
|
185
185
|
with suppress(RuntimeError):
|
|
186
186
|
if (roi := core.getROI()) != [0, 0, w, h]:
|
|
@@ -278,7 +278,7 @@ def pixel_size_config(core: CMMCorePlus, *, config_name: str) -> PixelSizeConfig
|
|
|
278
278
|
}
|
|
279
279
|
affine = core.getPixelSizeAffineByID(config_name)
|
|
280
280
|
if affine != (1.0, 0.0, 0.0, 0.0, 1.0, 0.0):
|
|
281
|
-
info["pixel_size_affine"] = affine
|
|
281
|
+
info["pixel_size_affine"] = affine
|
|
282
282
|
return info
|
|
283
283
|
|
|
284
284
|
|
pymmcore_plus/metadata/schema.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any,
|
|
1
|
+
from typing import Any, Literal, Optional, TypedDict, Union
|
|
2
2
|
|
|
3
3
|
import useq
|
|
4
4
|
from typing_extensions import NotRequired
|
|
@@ -17,7 +17,7 @@ __all__ = [
|
|
|
17
17
|
"SystemInfo",
|
|
18
18
|
]
|
|
19
19
|
|
|
20
|
-
AffineTuple =
|
|
20
|
+
AffineTuple = tuple[float, float, float, float, float, float]
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class PropertyInfo(TypedDict):
|
|
@@ -53,9 +53,9 @@ class PropertyInfo(TypedDict):
|
|
|
53
53
|
value: Optional[str]
|
|
54
54
|
data_type: Literal["undefined", "float", "int", "str"]
|
|
55
55
|
is_read_only: bool
|
|
56
|
-
allowed_values: NotRequired[
|
|
56
|
+
allowed_values: NotRequired[tuple[str, ...]]
|
|
57
57
|
is_pre_init: NotRequired[bool]
|
|
58
|
-
limits: NotRequired[
|
|
58
|
+
limits: NotRequired[tuple[float, float]]
|
|
59
59
|
sequenceable: NotRequired[bool]
|
|
60
60
|
sequence_max_length: NotRequired[int]
|
|
61
61
|
# device_label: str
|
|
@@ -104,14 +104,14 @@ class DeviceInfo(TypedDict):
|
|
|
104
104
|
name: str
|
|
105
105
|
type: str
|
|
106
106
|
description: str
|
|
107
|
-
properties:
|
|
107
|
+
properties: tuple[PropertyInfo, ...]
|
|
108
108
|
|
|
109
109
|
# hub devices and non-peripheral devices will have no parent_label
|
|
110
110
|
parent_label: NotRequired[str]
|
|
111
111
|
# state device only
|
|
112
|
-
labels: NotRequired[
|
|
112
|
+
labels: NotRequired[tuple[str, ...]]
|
|
113
113
|
# hub device only
|
|
114
|
-
child_names: NotRequired[
|
|
114
|
+
child_names: NotRequired[tuple[str, ...]]
|
|
115
115
|
# stage/focus device only
|
|
116
116
|
is_continuous_focus_drive: NotRequired[bool]
|
|
117
117
|
focus_direction: NotRequired[Literal["Unknown", "TowardSample", "AwayFromSample"]]
|
|
@@ -159,7 +159,7 @@ class SystemInfo(TypedDict):
|
|
|
159
159
|
pymmcore_plus_version: str
|
|
160
160
|
mmcore_version: str
|
|
161
161
|
device_api_version: str
|
|
162
|
-
device_adapter_search_paths:
|
|
162
|
+
device_adapter_search_paths: tuple[str, ...]
|
|
163
163
|
system_configuration_file: Optional[str]
|
|
164
164
|
primary_log_file: str
|
|
165
165
|
sequence_buffer_size_mb: int
|
|
@@ -215,7 +215,7 @@ class ImageInfo(TypedDict):
|
|
|
215
215
|
""" # noqa: E501
|
|
216
216
|
|
|
217
217
|
camera_label: str
|
|
218
|
-
plane_shape:
|
|
218
|
+
plane_shape: tuple[int, ...]
|
|
219
219
|
dtype: str
|
|
220
220
|
|
|
221
221
|
height: int
|
|
@@ -238,8 +238,8 @@ class ImageInfo(TypedDict):
|
|
|
238
238
|
pixel_size_um: float
|
|
239
239
|
magnification_factor: NotRequired[float]
|
|
240
240
|
pixel_size_affine: NotRequired[AffineTuple]
|
|
241
|
-
roi: NotRequired[
|
|
242
|
-
multi_roi: NotRequired[
|
|
241
|
+
roi: NotRequired[tuple[int, int, int, int]]
|
|
242
|
+
multi_roi: NotRequired[tuple[list[int], list[int], list[int], list[int]]]
|
|
243
243
|
|
|
244
244
|
# # this will be != 1 for things like multi-camera device,
|
|
245
245
|
# # or any "single" device adapter that manages multiple detectors, like PMTs, etc..
|
|
@@ -250,7 +250,7 @@ class StagePosition(TypedDict):
|
|
|
250
250
|
"""Represents the position of a single stage device."""
|
|
251
251
|
|
|
252
252
|
device_label: str
|
|
253
|
-
position: Union[float,
|
|
253
|
+
position: Union[float, tuple[float, float]]
|
|
254
254
|
|
|
255
255
|
|
|
256
256
|
class Position(TypedDict):
|
|
@@ -276,7 +276,7 @@ class Position(TypedDict):
|
|
|
276
276
|
x: NotRequired[float]
|
|
277
277
|
y: NotRequired[float]
|
|
278
278
|
z: NotRequired[float]
|
|
279
|
-
all_stages: NotRequired[
|
|
279
|
+
all_stages: NotRequired[list[StagePosition]]
|
|
280
280
|
|
|
281
281
|
|
|
282
282
|
class PropertyValue(TypedDict):
|
|
@@ -312,7 +312,7 @@ class ConfigPreset(TypedDict):
|
|
|
312
312
|
"""
|
|
313
313
|
|
|
314
314
|
name: str
|
|
315
|
-
settings:
|
|
315
|
+
settings: tuple[PropertyValue, ...]
|
|
316
316
|
|
|
317
317
|
|
|
318
318
|
class PixelSizeConfigPreset(ConfigPreset):
|
|
@@ -350,7 +350,7 @@ class ConfigGroup(TypedDict):
|
|
|
350
350
|
"""
|
|
351
351
|
|
|
352
352
|
name: str
|
|
353
|
-
presets:
|
|
353
|
+
presets: tuple[ConfigPreset, ...]
|
|
354
354
|
|
|
355
355
|
|
|
356
356
|
class SummaryMetaV1(TypedDict):
|
|
@@ -395,14 +395,14 @@ class SummaryMetaV1(TypedDict):
|
|
|
395
395
|
format: Literal["summary-dict"]
|
|
396
396
|
version: Literal["1.0"]
|
|
397
397
|
datetime: NotRequired[str]
|
|
398
|
-
devices:
|
|
398
|
+
devices: tuple[DeviceInfo, ...]
|
|
399
399
|
system_info: SystemInfo
|
|
400
|
-
image_infos:
|
|
401
|
-
config_groups:
|
|
402
|
-
pixel_size_configs:
|
|
400
|
+
image_infos: tuple[ImageInfo, ...]
|
|
401
|
+
config_groups: tuple[ConfigGroup, ...]
|
|
402
|
+
pixel_size_configs: tuple[PixelSizeConfigPreset, ...]
|
|
403
403
|
position: Position
|
|
404
404
|
mda_sequence: NotRequired[useq.MDASequence]
|
|
405
|
-
extra: NotRequired[
|
|
405
|
+
extra: NotRequired[dict[str, Any]]
|
|
406
406
|
|
|
407
407
|
|
|
408
408
|
class FrameMetaV1(TypedDict):
|
|
@@ -462,10 +462,10 @@ class FrameMetaV1(TypedDict):
|
|
|
462
462
|
camera_device: Optional[str]
|
|
463
463
|
exposure_ms: float
|
|
464
464
|
position: Position
|
|
465
|
-
property_values:
|
|
465
|
+
property_values: tuple[PropertyValue, ...]
|
|
466
466
|
runner_time_ms: float
|
|
467
467
|
mda_event: NotRequired[useq.MDAEvent]
|
|
468
468
|
hardware_triggered: NotRequired[bool]
|
|
469
469
|
images_remaining_in_buffer: NotRequired[int]
|
|
470
|
-
camera_metadata: NotRequired[
|
|
471
|
-
extra: NotRequired[
|
|
470
|
+
camera_metadata: NotRequired[dict[str, Any]]
|
|
471
|
+
extra: NotRequired[dict[str, Any]]
|
|
@@ -2,10 +2,12 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import sys
|
|
5
|
+
from collections.abc import Mapping, Sequence
|
|
5
6
|
from contextlib import suppress
|
|
6
7
|
from datetime import timedelta
|
|
8
|
+
from enum import Enum
|
|
7
9
|
from types import MappingProxyType
|
|
8
|
-
from typing import TYPE_CHECKING, Any
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
9
11
|
|
|
10
12
|
import numpy as np
|
|
11
13
|
|
|
@@ -35,6 +37,8 @@ def encode_hook(obj: Any, raises: bool = True) -> Any:
|
|
|
35
37
|
return obj.item()
|
|
36
38
|
if isinstance(obj, timedelta):
|
|
37
39
|
return obj.total_seconds()
|
|
40
|
+
if isinstance(obj, Enum):
|
|
41
|
+
return obj.value
|
|
38
42
|
if raises:
|
|
39
43
|
raise NotImplementedError(f"Cannot serialize object of type {type(obj)}")
|
|
40
44
|
return obj
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import warnings
|
|
6
|
-
from typing import TYPE_CHECKING, Any, Callable
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Callable
|
|
7
7
|
|
|
8
8
|
from pymmcore_plus import CFGCommand, DeviceType, FocusDirection, Keyword
|
|
9
9
|
from pymmcore_plus._util import timestamp
|
|
@@ -15,6 +15,7 @@ from ._pixel_size_config import DEFAULT_AFFINE, PixelSizePreset
|
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
17
|
import io
|
|
18
|
+
from collections.abc import Iterable, Sequence
|
|
18
19
|
from typing import TypeAlias
|
|
19
20
|
|
|
20
21
|
Executor: TypeAlias = Callable[[Microscope, Sequence[str]], None]
|
|
@@ -4,7 +4,8 @@ from dataclasses import dataclass, field
|
|
|
4
4
|
from typing import TYPE_CHECKING, NamedTuple
|
|
5
5
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
7
|
-
from
|
|
7
|
+
from collections.abc import Container, MutableMapping
|
|
8
|
+
from typing import Final
|
|
8
9
|
|
|
9
10
|
from typing_extensions import Self # py311
|
|
10
11
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from pymmcore_plus import CMMCorePlus, DeviceType, Keyword
|
|
7
7
|
|
|
@@ -9,6 +9,8 @@ from ._device import Device
|
|
|
9
9
|
from ._property import Property
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Container
|
|
13
|
+
|
|
12
14
|
from pymmcore_plus.model._core_link import ErrCallback
|
|
13
15
|
|
|
14
16
|
CORE = Keyword.CoreDevice.value
|
|
@@ -5,8 +5,9 @@ from dataclasses import fields
|
|
|
5
5
|
from typing import TYPE_CHECKING, Protocol
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
|
+
from collections.abc import Container, Iterable
|
|
8
9
|
from dataclasses import Field
|
|
9
|
-
from typing import Any, Callable, ClassVar,
|
|
10
|
+
from typing import Any, Callable, ClassVar, TypeVar
|
|
10
11
|
|
|
11
12
|
from typing_extensions import TypeAlias # py310
|
|
12
13
|
|
pymmcore_plus/model/_device.py
CHANGED
|
@@ -12,7 +12,8 @@ from ._core_link import CoreObject
|
|
|
12
12
|
from ._property import Property
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
|
-
from
|
|
15
|
+
from collections.abc import Container, Iterable
|
|
16
|
+
from typing import Any, Callable
|
|
16
17
|
|
|
17
18
|
from typing_extensions import (
|
|
18
19
|
Self, # py311
|
|
@@ -4,7 +4,7 @@ import os
|
|
|
4
4
|
from copy import deepcopy
|
|
5
5
|
from dataclasses import dataclass, field, fields
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import TYPE_CHECKING, Any, Callable
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Callable
|
|
8
8
|
|
|
9
9
|
from pymmcore_plus import DeviceType, Keyword
|
|
10
10
|
|
|
@@ -14,6 +14,8 @@ from ._device import AvailableDevice, Device, get_available_devices
|
|
|
14
14
|
from ._pixel_size_config import PixelSizeGroup
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
|
+
from collections.abc import Container, Iterable
|
|
18
|
+
|
|
17
19
|
from pymmcore_plus import CMMCorePlus
|
|
18
20
|
from pymmcore_plus.metadata.schema import SummaryMetaV1
|
|
19
21
|
|
|
@@ -212,7 +214,7 @@ class Microscope:
|
|
|
212
214
|
self.devices = [
|
|
213
215
|
Device.create_from_core(core, name=name)
|
|
214
216
|
for name in core.getLoadedDevices()
|
|
215
|
-
if name != Keyword.CoreDevice
|
|
217
|
+
if name != Keyword.CoreDevice # type: ignore [comparison-overlap]
|
|
216
218
|
]
|
|
217
219
|
if "core_device" not in exclude:
|
|
218
220
|
self.core_device.update_from_core(core)
|
|
@@ -6,7 +6,8 @@ from typing import TYPE_CHECKING
|
|
|
6
6
|
from ._config_group import ConfigGroup, ConfigPreset, Setting
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
|
-
from
|
|
9
|
+
from collections.abc import Container, Iterable, MutableMapping
|
|
10
|
+
from typing import Any, Final
|
|
10
11
|
|
|
11
12
|
from typing_extensions import (
|
|
12
13
|
Self, # py311
|
|
@@ -77,7 +78,7 @@ class PixelSizeGroup(ConfigGroup):
|
|
|
77
78
|
preset: PixelSizePreset(
|
|
78
79
|
name=preset,
|
|
79
80
|
pixel_size_um=core.getPixelSizeUmByID(preset),
|
|
80
|
-
affine=core.getPixelSizeAffineByID(preset),
|
|
81
|
+
affine=core.getPixelSizeAffineByID(preset),
|
|
81
82
|
settings=[Setting(*d) for d in core.getPixelSizeConfigData(preset)],
|
|
82
83
|
)
|
|
83
84
|
for preset in core.getAvailablePixelSizeConfigs()
|
pymmcore_plus/model/_property.py
CHANGED
|
@@ -8,7 +8,8 @@ from pymmcore_plus import CMMCorePlus, PropertyType
|
|
|
8
8
|
from ._core_link import CoreObject
|
|
9
9
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
|
-
from
|
|
11
|
+
from collections.abc import Container
|
|
12
|
+
from typing import Any, Callable
|
|
12
13
|
|
|
13
14
|
from typing_extensions import TypeAlias # py310
|
|
14
15
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: pymmcore-plus
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: pymmcore superset providing improved APIs, event handling, and a pure python acquisition engine
|
|
5
5
|
Project-URL: Source, https://github.com/pymmcore-plus/pymmcore-plus
|
|
6
6
|
Project-URL: Tracker, https://github.com/pymmcore-plus/pymmcore-plus/issues
|
|
@@ -16,7 +16,6 @@ Classifier: License :: OSI Approved :: BSD License
|
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
17
17
|
Classifier: Programming Language :: Python
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -24,7 +23,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
24
23
|
Classifier: Topic :: System :: Hardware
|
|
25
24
|
Classifier: Topic :: System :: Hardware :: Hardware Drivers
|
|
26
25
|
Classifier: Topic :: Utilities
|
|
27
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.9
|
|
28
27
|
Requires-Dist: numpy>=1.17.3
|
|
29
28
|
Requires-Dist: platformdirs>=3.0.0
|
|
30
29
|
Requires-Dist: psygnal>=0.7
|
|
@@ -33,7 +32,7 @@ Requires-Dist: rich>=10.2.0
|
|
|
33
32
|
Requires-Dist: tensorstore
|
|
34
33
|
Requires-Dist: typer>=0.4.2
|
|
35
34
|
Requires-Dist: typing-extensions
|
|
36
|
-
Requires-Dist: useq-schema>=0.
|
|
35
|
+
Requires-Dist: useq-schema>=0.5.0
|
|
37
36
|
Requires-Dist: wrapt>=1.14
|
|
38
37
|
Provides-Extra: cli
|
|
39
38
|
Requires-Dist: rich>=10.2.0; extra == 'cli'
|
|
@@ -53,7 +52,7 @@ Requires-Dist: mkdocstrings-python==1.1.2; extra == 'docs'
|
|
|
53
52
|
Requires-Dist: mkdocstrings==0.22.0; extra == 'docs'
|
|
54
53
|
Provides-Extra: io
|
|
55
54
|
Requires-Dist: tifffile>=2021.6.14; extra == 'io'
|
|
56
|
-
Requires-Dist: zarr
|
|
55
|
+
Requires-Dist: zarr<3,>=2.2; extra == 'io'
|
|
57
56
|
Provides-Extra: test
|
|
58
57
|
Requires-Dist: msgpack; extra == 'test'
|
|
59
58
|
Requires-Dist: msgspec; extra == 'test'
|
|
@@ -65,7 +64,7 @@ Requires-Dist: rich; extra == 'test'
|
|
|
65
64
|
Requires-Dist: tifffile>=2021.6.14; extra == 'test'
|
|
66
65
|
Requires-Dist: typer>=0.4.2; extra == 'test'
|
|
67
66
|
Requires-Dist: xarray; extra == 'test'
|
|
68
|
-
Requires-Dist: zarr
|
|
67
|
+
Requires-Dist: zarr<3,>=2.2; extra == 'test'
|
|
69
68
|
Description-Content-Type: text/markdown
|
|
70
69
|
|
|
71
70
|
# pymmcore-plus
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
pymmcore_plus/__init__.py,sha256=y2y48MqOnY-B1h7QnJc36HRDuXEegMsPNqKq51bu8DQ,1415
|
|
2
|
+
pymmcore_plus/_build.py,sha256=RPTAuwCZWGL5IDJj4JZo1DIIouUsIqS3vnbPbG2_bRE,10993
|
|
3
|
+
pymmcore_plus/_cli.py,sha256=rtbxbru85YcbEVjpmC0-EwlTe4TUYVaUBe2Kb-ZELmk,14252
|
|
4
|
+
pymmcore_plus/_logger.py,sha256=YZt1ueX5mHtNGPXMqJQMrNdy46KSGlMReCOcmzjhBvQ,5153
|
|
5
|
+
pymmcore_plus/_util.py,sha256=49gAx6G4wzD7MuGd7mtniXbq28qCRXihDuJcRZW7chM,20278
|
|
6
|
+
pymmcore_plus/install.py,sha256=Vr_Z2Q9tNWEu0x-iw6HC2h1iv6K9H9tgI9aRFtckgQU,8576
|
|
7
|
+
pymmcore_plus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
pymmcore_plus/seq_tester.py,sha256=6PqLFHpd0SvnzYVtE80AxytiqCVtB1ULiU1myzO3G7w,3768
|
|
9
|
+
pymmcore_plus/core/__init__.py,sha256=r9bvL6sqgN72ZV7785WuRKT-o1VlsbYQcAKSy3rNS9k,897
|
|
10
|
+
pymmcore_plus/core/_adapter.py,sha256=eu2BhGe_dnoQrIsh-u3poxWXsiF2Y8pfbKIGWbUgOk8,2857
|
|
11
|
+
pymmcore_plus/core/_config.py,sha256=jatzHm6D-JwvlAPhvNYfzzrqXoKCpQ-EwKu6LhFeruc,10645
|
|
12
|
+
pymmcore_plus/core/_config_group.py,sha256=jE0TxM93VuwOa7UrwIBjMBGSSa9oTr84uEn1aMhSBIE,8499
|
|
13
|
+
pymmcore_plus/core/_constants.py,sha256=55lKxI38TXceowsM_Z7ShWZ-DfQiBJB_qqzaU8G9PSc,11743
|
|
14
|
+
pymmcore_plus/core/_device.py,sha256=Uy5A58Jj_bIY5n6OymtTJPRnYkktoCq6ZtQV4KcLwPo,7756
|
|
15
|
+
pymmcore_plus/core/_metadata.py,sha256=RT6dNZ9YkRlFd85hd_Vd6zLVjjbX4Cn831t6wAYDOvI,2618
|
|
16
|
+
pymmcore_plus/core/_mmcore_plus.py,sha256=CGtHubJhsnt8Bzd3DjcsmL8sfxixU5P19mhjnVXn5a4,87596
|
|
17
|
+
pymmcore_plus/core/_property.py,sha256=gO2Zy1I2y0wBAgQAVHnz1Vm7E2PYegGuLffNA1QBc6Y,8315
|
|
18
|
+
pymmcore_plus/core/_sequencing.py,sha256=e1INgj-UGGVG67B_eXbH11RVVwYRI7ZokVpGkXLCIbQ,11797
|
|
19
|
+
pymmcore_plus/core/events/__init__.py,sha256=_CIWCstUu2-xTqarK9fS_ENpZu7VxStLP4VNfcVmaBs,1094
|
|
20
|
+
pymmcore_plus/core/events/_device_signal_view.py,sha256=t-NfBdg3E4rms4vDFxkkR5XtrpLxaBT7mfPwkpIsbVk,1079
|
|
21
|
+
pymmcore_plus/core/events/_norm_slot.py,sha256=8DCBoLHGh7cbB1OB19IJYwL6sFBFmkD8IakfBOvFbw8,2907
|
|
22
|
+
pymmcore_plus/core/events/_prop_event_mixin.py,sha256=FvJJnpEKrOR-_Sp3-NNCwFoUUHwmNKiHruo0Y1vybsY,4042
|
|
23
|
+
pymmcore_plus/core/events/_protocol.py,sha256=V4st91mw6LoogII2c05vJxD5SIQU24va86J0iqJWqXU,7528
|
|
24
|
+
pymmcore_plus/core/events/_psygnal.py,sha256=owaKlW2zpvocXDbAW4kHovBoVv4Fjfn-S5oUJrVWsD4,1646
|
|
25
|
+
pymmcore_plus/core/events/_qsignals.py,sha256=gr-GDiSVLhFhSfaoKrdTz2y3I_2IUg62bYDGuGrB3j0,3018
|
|
26
|
+
pymmcore_plus/mda/__init__.py,sha256=NF4OReQbShxZeLFaNaLPyMwkr1e5j5zMZmzHvHeSBzE,298
|
|
27
|
+
pymmcore_plus/mda/_engine.py,sha256=wHbRDTdIK7G5kERMv81uBe6mYrqvuerTTM9bMlU0haE,24392
|
|
28
|
+
pymmcore_plus/mda/_protocol.py,sha256=10CDJ9H57oX1z0oqK3eShXyQhufHvvu3_8wdaCYpPIg,3254
|
|
29
|
+
pymmcore_plus/mda/_runner.py,sha256=ieSUh1st1DWvvvToaoHb01-3JCcqt7UbSx9LRGr9ehw,16256
|
|
30
|
+
pymmcore_plus/mda/_thread_relay.py,sha256=Ww-9gyvLEzwRhnpL1dpze71wL7IRlhH8K3Q1dmJIxgs,6193
|
|
31
|
+
pymmcore_plus/mda/events/__init__.py,sha256=UZFBlIzTmKqgMw_vVSZSSAN1tkAu8qccYb-aXXBRc3I,1192
|
|
32
|
+
pymmcore_plus/mda/events/_protocol.py,sha256=9Q7LjYOgEWQGS8gHMV97UXM9bhoVW2OeyoPyNsQbwzw,1659
|
|
33
|
+
pymmcore_plus/mda/events/_psygnal.py,sha256=TdN1mFGpTPXmEs9iwFKSC1svv87PDZkT2JZvl0tEGrQ,640
|
|
34
|
+
pymmcore_plus/mda/events/_qsignals.py,sha256=tULQg-e_NX197DxJXaWHn1zLJ-4tzc9QyOAnsobEDtA,554
|
|
35
|
+
pymmcore_plus/mda/handlers/_5d_writer_base.py,sha256=c9cA0n8DOBoZcy9asue5eV7jW8hFVC0XEewroFgDNHA,11925
|
|
36
|
+
pymmcore_plus/mda/handlers/__init__.py,sha256=yQFRVDdCyu5t2JilobHGPC8lgCY4htNF5dzctrteSZA,305
|
|
37
|
+
pymmcore_plus/mda/handlers/_img_sequence_writer.py,sha256=fAj6CB90RXYJ2jJIRDFxZgQb-TfwuRPWGCPFopCijRI,11549
|
|
38
|
+
pymmcore_plus/mda/handlers/_ome_tiff_writer.py,sha256=pqqdl3KQd0tH5Gp4rHVgYqqh2Y8iwoKRXTjwq1JLy1E,6239
|
|
39
|
+
pymmcore_plus/mda/handlers/_ome_zarr_writer.py,sha256=tjq7v3K3wrbPmTSlkvnEDTyMilno2sqyDkZxOjAh7FE,12275
|
|
40
|
+
pymmcore_plus/mda/handlers/_tensorstore_handler.py,sha256=0DpHf0SHcHgpbmlIZ2YLK3krDFcEe_aEQSk10a8WHvg,14672
|
|
41
|
+
pymmcore_plus/mda/handlers/_util.py,sha256=pZydpKAXtQ_gjq5x1yNK1D0hfS7NUL2nH9ivOBg4abc,1600
|
|
42
|
+
pymmcore_plus/metadata/__init__.py,sha256=r_2dI4qbc5GPl3MP6ye-W7-c1RBZZXkCgFqJ4HaPJOA,699
|
|
43
|
+
pymmcore_plus/metadata/functions.py,sha256=RsXuYS6ytIRicefRF0h7NiGfDhmimKbpgL9Vrp1p548,12188
|
|
44
|
+
pymmcore_plus/metadata/schema.py,sha256=Zsh7D-UptVisP_AiDcAdUDoXZsQfZNSJIrCkIgxtt5Q,17241
|
|
45
|
+
pymmcore_plus/metadata/serialize.py,sha256=hpXJm0tzILELf6OYECMg0sQhuf-h25ob6_DDl-TUUME,3805
|
|
46
|
+
pymmcore_plus/model/__init__.py,sha256=zKZkkSpNK4ERu-VMdi9gvRrj1aXAjNaYxlYB5PdYSg0,479
|
|
47
|
+
pymmcore_plus/model/_config_file.py,sha256=cnTF9fcclnwhnwl-qfZxSyVO75d_ljMD3CQeGrXzzMI,13280
|
|
48
|
+
pymmcore_plus/model/_config_group.py,sha256=vL_-EWH-Nsb8xTgFqpYIFaJzBk_RDBFchBnQ61DMSvI,3407
|
|
49
|
+
pymmcore_plus/model/_core_device.py,sha256=cucoGtFue71yOqC5VcT7Uvk8mY4EhPmX0pyhXsgakXE,2402
|
|
50
|
+
pymmcore_plus/model/_core_link.py,sha256=dsbT0gncfa3TAORSaWUrZR9rcI_nOLX9e5BTmyo-UYo,2737
|
|
51
|
+
pymmcore_plus/model/_device.py,sha256=ZQs6luAt2KXpDKpR2DwoHnh3izM6xWX1ckIxFhpHP9U,15748
|
|
52
|
+
pymmcore_plus/model/_microscope.py,sha256=69VV6cuevinOK_LhYEkQygHGesvCZefdn9YNt3mV618,11353
|
|
53
|
+
pymmcore_plus/model/_pixel_size_config.py,sha256=smoOmT54nSkg52RaSQzTFG0YwyMR_SEq_lkS-JyJW9U,3514
|
|
54
|
+
pymmcore_plus/model/_property.py,sha256=fl2wUldY3H9qK9aoIcZLJCr7wDcxOFLoIjvR9rHnAnk,3359
|
|
55
|
+
pymmcore_plus-0.12.0.dist-info/METADATA,sha256=nvAEtFjaYJkMQrJY657Fgd5ouJzee72mCfKrSTc9BXU,9221
|
|
56
|
+
pymmcore_plus-0.12.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
57
|
+
pymmcore_plus-0.12.0.dist-info/entry_points.txt,sha256=NtFyndrQzBpUNJyil-8e5hMGke2utAf7mkGavTLcLOY,51
|
|
58
|
+
pymmcore_plus-0.12.0.dist-info/licenses/LICENSE,sha256=OHJjRpOPKKRc7FEnpehNWdR5LRBdBhUtIFG-ZI0dCEA,1522
|
|
59
|
+
pymmcore_plus-0.12.0.dist-info/RECORD,,
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
pymmcore_plus/__init__.py,sha256=y2y48MqOnY-B1h7QnJc36HRDuXEegMsPNqKq51bu8DQ,1415
|
|
2
|
-
pymmcore_plus/_build.py,sha256=PU6rm_4l-SGMurPQT5RuloUMkrgqKTI0Y9ePbPmWOmo,10928
|
|
3
|
-
pymmcore_plus/_cli.py,sha256=M2ndZGKv6HN7DtVaeB48bAQiaJN8Yu8GcupjaGZelNQ,14291
|
|
4
|
-
pymmcore_plus/_logger.py,sha256=IQl--kuEQqUwV9C4P1sY-7J5IW6V7q45wsi2NbfnAbM,5088
|
|
5
|
-
pymmcore_plus/_util.py,sha256=mNabztc90ck1rN_15RtaYjk6acyP2azSJGzMkyeJELs,20247
|
|
6
|
-
pymmcore_plus/install.py,sha256=a85-KCifBetKSQXwH1DqEkz7il5iqFcl9LR0qFIVvbk,8503
|
|
7
|
-
pymmcore_plus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
pymmcore_plus/seq_tester.py,sha256=6PqLFHpd0SvnzYVtE80AxytiqCVtB1ULiU1myzO3G7w,3768
|
|
9
|
-
pymmcore_plus/core/__init__.py,sha256=r9bvL6sqgN72ZV7785WuRKT-o1VlsbYQcAKSy3rNS9k,897
|
|
10
|
-
pymmcore_plus/core/_adapter.py,sha256=eu2BhGe_dnoQrIsh-u3poxWXsiF2Y8pfbKIGWbUgOk8,2857
|
|
11
|
-
pymmcore_plus/core/_config.py,sha256=5Vzwv2QEuJSXgKjERSHiTzwmpWyizY_aa4n3OjpPyPc,10620
|
|
12
|
-
pymmcore_plus/core/_config_group.py,sha256=w-psUtMk3X6MzqU17j4D2yZ_ugLP7u0-mvPIXPuIxwQ,8472
|
|
13
|
-
pymmcore_plus/core/_constants.py,sha256=55lKxI38TXceowsM_Z7ShWZ-DfQiBJB_qqzaU8G9PSc,11743
|
|
14
|
-
pymmcore_plus/core/_device.py,sha256=Uy5A58Jj_bIY5n6OymtTJPRnYkktoCq6ZtQV4KcLwPo,7756
|
|
15
|
-
pymmcore_plus/core/_metadata.py,sha256=64RdptyRGRqtRJ8pWMlAyevSgYMAE1Hzs8TB3DBQHAA,2618
|
|
16
|
-
pymmcore_plus/core/_mmcore_plus.py,sha256=fOtv3hf11YkV7ekEZePOS0tCkDqGdFpihqrIZot20n8,87548
|
|
17
|
-
pymmcore_plus/core/_property.py,sha256=sd28rZE-_l4HaIJxqJlUX7DlM-Fa9_Xr6cLERwOtBYc,8283
|
|
18
|
-
pymmcore_plus/core/_sequencing.py,sha256=ueyuqsUPbfH7FLMdqFUpHoxSZfBRHHkYmv12lOt72hI,11847
|
|
19
|
-
pymmcore_plus/core/events/__init__.py,sha256=8NjFkVdRVRiiLUQ_brGQSlTaK3rqNizdNEX17NEXAis,1106
|
|
20
|
-
pymmcore_plus/core/events/_device_signal_view.py,sha256=st_di51xOmKKOM9-yY8ouKlTZqG-7NWorRaoaN1sJ44,1065
|
|
21
|
-
pymmcore_plus/core/events/_norm_slot.py,sha256=cp6VeH5h98G7bPWrKzTsHJmzCIbi2D4sv6bSdywQbsk,2937
|
|
22
|
-
pymmcore_plus/core/events/_prop_event_mixin.py,sha256=XfoXrMjRRXPHv6XkavBmSuz-6nItpJ8oG60DqK2WBEA,3939
|
|
23
|
-
pymmcore_plus/core/events/_protocol.py,sha256=Cf9uGZe_uP8nIa8rsaDIX5RCW5pNQQt2juLL-rriRn4,7448
|
|
24
|
-
pymmcore_plus/core/events/_psygnal.py,sha256=owaKlW2zpvocXDbAW4kHovBoVv4Fjfn-S5oUJrVWsD4,1646
|
|
25
|
-
pymmcore_plus/core/events/_qsignals.py,sha256=gr-GDiSVLhFhSfaoKrdTz2y3I_2IUg62bYDGuGrB3j0,3018
|
|
26
|
-
pymmcore_plus/mda/__init__.py,sha256=NF4OReQbShxZeLFaNaLPyMwkr1e5j5zMZmzHvHeSBzE,298
|
|
27
|
-
pymmcore_plus/mda/_engine.py,sha256=qHIMwLsl9NROa8pVv41dKzZP3OoNeRhosMjuIL4a0sY,24432
|
|
28
|
-
pymmcore_plus/mda/_protocol.py,sha256=vuotAc2P1zl2EX4wGjfaasarQHNqtF5UpOwPtUqHG2Y,3245
|
|
29
|
-
pymmcore_plus/mda/_runner.py,sha256=edgRQo-YRzF5f2VEVjATsTV70wUjuRcUFF5XtRLgguE,15498
|
|
30
|
-
pymmcore_plus/mda/_thread_relay.py,sha256=wjP1tag7nN2Sr0RzaPnYRqHl8XjAQg2MpXOt0ONLcQ8,6112
|
|
31
|
-
pymmcore_plus/mda/events/__init__.py,sha256=UZFBlIzTmKqgMw_vVSZSSAN1tkAu8qccYb-aXXBRc3I,1192
|
|
32
|
-
pymmcore_plus/mda/events/_protocol.py,sha256=9Q7LjYOgEWQGS8gHMV97UXM9bhoVW2OeyoPyNsQbwzw,1659
|
|
33
|
-
pymmcore_plus/mda/events/_psygnal.py,sha256=TdN1mFGpTPXmEs9iwFKSC1svv87PDZkT2JZvl0tEGrQ,640
|
|
34
|
-
pymmcore_plus/mda/events/_qsignals.py,sha256=tULQg-e_NX197DxJXaWHn1zLJ-4tzc9QyOAnsobEDtA,554
|
|
35
|
-
pymmcore_plus/mda/handlers/_5d_writer_base.py,sha256=myFcpj_uqoBkYb_1JFB0GjmRhFxW-8jyZAhqoO8CRfo,11893
|
|
36
|
-
pymmcore_plus/mda/handlers/__init__.py,sha256=yQFRVDdCyu5t2JilobHGPC8lgCY4htNF5dzctrteSZA,305
|
|
37
|
-
pymmcore_plus/mda/handlers/_img_sequence_writer.py,sha256=bOnw9htxovIqUhJCoJml5YayaWD30IN2uuB_TijNVHk,11522
|
|
38
|
-
pymmcore_plus/mda/handlers/_ome_tiff_writer.py,sha256=pqqdl3KQd0tH5Gp4rHVgYqqh2Y8iwoKRXTjwq1JLy1E,6239
|
|
39
|
-
pymmcore_plus/mda/handlers/_ome_zarr_writer.py,sha256=ReJW8bnk-vQk4J1Zd66swkQATg17uV_hzpoBosUWuP4,12253
|
|
40
|
-
pymmcore_plus/mda/handlers/_tensorstore_handler.py,sha256=gweY2WoXgjPmiQbfTgL3TwB4b-u8cjlrlWEr-5n84OM,14642
|
|
41
|
-
pymmcore_plus/mda/handlers/_util.py,sha256=p-8Gg5Q2Jo0zyYdniP9a0NirUOnuKNLWzwjhzcKqskg,1601
|
|
42
|
-
pymmcore_plus/metadata/__init__.py,sha256=r_2dI4qbc5GPl3MP6ye-W7-c1RBZZXkCgFqJ4HaPJOA,699
|
|
43
|
-
pymmcore_plus/metadata/functions.py,sha256=b9bdLwvzqzhku4cLkFfRiAUXL8-wJNaZKayYzks39qg,12254
|
|
44
|
-
pymmcore_plus/metadata/schema.py,sha256=bP0SMwMfvgTfmTKMIWveAXbw5fDnE18kmFYu-FLenAM,17260
|
|
45
|
-
pymmcore_plus/metadata/serialize.py,sha256=XB-epU7-bJfmP6HItBH9t0-lOsJuW7xSFjc5y3mO1Jg,3701
|
|
46
|
-
pymmcore_plus/model/__init__.py,sha256=zKZkkSpNK4ERu-VMdi9gvRrj1aXAjNaYxlYB5PdYSg0,479
|
|
47
|
-
pymmcore_plus/model/_config_file.py,sha256=46xdrVLa193uNbQxq0puzWYDcfFIqRAw6M8v9TVu3U4,13249
|
|
48
|
-
pymmcore_plus/model/_config_group.py,sha256=O9DzPyKe2Q3iInsQNbDsQfJeCWVcnzgMHGD_zXTMBw0,3376
|
|
49
|
-
pymmcore_plus/model/_core_device.py,sha256=afNYGIRFunUPYNYJ_yHJwOjo7HO9FW8qGWTMeiKRmNU,2370
|
|
50
|
-
pymmcore_plus/model/_core_link.py,sha256=myE0qa2pEWEinbsIhTN4uB_c-lr9dtUG3npLgsHEI_0,2706
|
|
51
|
-
pymmcore_plus/model/_device.py,sha256=IuSTdxR6OwGnmhTgV77QDEwIwuZOLbmU-gCnSdd2H-c,15717
|
|
52
|
-
pymmcore_plus/model/_microscope.py,sha256=CkzkpGtl1n-phMtDBygsIa7wVnTWLtEqgZ-hgZYxdRE,11284
|
|
53
|
-
pymmcore_plus/model/_pixel_size_config.py,sha256=l-BkE7NuBcnXfytEPIblYA5vgCqb4nhvv1yhSCvr8pQ,3499
|
|
54
|
-
pymmcore_plus/model/_property.py,sha256=gJM7SFjLB2HnN0E8HOn4qVlB2wAxmkEFxSJFjKauZEk,3328
|
|
55
|
-
pymmcore_plus-0.11.0.dist-info/METADATA,sha256=DxCVFUfpvr1bEbezpQ6O73IBBAD01sTUiADwP7Tk0Y4,9265
|
|
56
|
-
pymmcore_plus-0.11.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
57
|
-
pymmcore_plus-0.11.0.dist-info/entry_points.txt,sha256=NtFyndrQzBpUNJyil-8e5hMGke2utAf7mkGavTLcLOY,51
|
|
58
|
-
pymmcore_plus-0.11.0.dist-info/licenses/LICENSE,sha256=OHJjRpOPKKRc7FEnpehNWdR5LRBdBhUtIFG-ZI0dCEA,1522
|
|
59
|
-
pymmcore_plus-0.11.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|