pymmcore-plus 0.9.3__py3-none-any.whl → 0.13.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/__init__.py +7 -4
- pymmcore_plus/_benchmark.py +203 -0
- pymmcore_plus/_build.py +6 -1
- pymmcore_plus/_cli.py +131 -31
- pymmcore_plus/_logger.py +19 -10
- pymmcore_plus/_pymmcore.py +12 -0
- pymmcore_plus/_util.py +139 -32
- pymmcore_plus/core/__init__.py +5 -0
- pymmcore_plus/core/_config.py +6 -4
- pymmcore_plus/core/_config_group.py +4 -3
- pymmcore_plus/core/_constants.py +135 -10
- pymmcore_plus/core/_device.py +4 -4
- pymmcore_plus/core/_metadata.py +3 -3
- pymmcore_plus/core/_mmcore_plus.py +254 -170
- pymmcore_plus/core/_property.py +6 -6
- pymmcore_plus/core/_sequencing.py +370 -233
- pymmcore_plus/core/events/__init__.py +6 -6
- 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/core/events/_psygnal.py +2 -2
- pymmcore_plus/experimental/__init__.py +0 -0
- pymmcore_plus/experimental/unicore/__init__.py +14 -0
- pymmcore_plus/experimental/unicore/_device_manager.py +173 -0
- pymmcore_plus/experimental/unicore/_proxy.py +127 -0
- pymmcore_plus/experimental/unicore/_unicore.py +703 -0
- pymmcore_plus/experimental/unicore/devices/__init__.py +0 -0
- pymmcore_plus/experimental/unicore/devices/_device.py +269 -0
- pymmcore_plus/experimental/unicore/devices/_properties.py +400 -0
- pymmcore_plus/experimental/unicore/devices/_stage.py +221 -0
- pymmcore_plus/install.py +16 -11
- pymmcore_plus/mda/__init__.py +1 -1
- pymmcore_plus/mda/_engine.py +320 -148
- pymmcore_plus/mda/_protocol.py +6 -4
- pymmcore_plus/mda/_runner.py +62 -51
- pymmcore_plus/mda/_thread_relay.py +5 -3
- pymmcore_plus/mda/events/__init__.py +2 -2
- pymmcore_plus/mda/events/_protocol.py +10 -2
- pymmcore_plus/mda/events/_psygnal.py +2 -2
- pymmcore_plus/mda/handlers/_5d_writer_base.py +106 -15
- pymmcore_plus/mda/handlers/__init__.py +7 -1
- pymmcore_plus/mda/handlers/_img_sequence_writer.py +11 -6
- pymmcore_plus/mda/handlers/_ome_tiff_writer.py +8 -4
- pymmcore_plus/mda/handlers/_ome_zarr_writer.py +82 -9
- pymmcore_plus/mda/handlers/_tensorstore_handler.py +374 -0
- pymmcore_plus/mda/handlers/_util.py +1 -1
- pymmcore_plus/metadata/__init__.py +36 -0
- pymmcore_plus/metadata/functions.py +353 -0
- pymmcore_plus/metadata/schema.py +472 -0
- pymmcore_plus/metadata/serialize.py +120 -0
- pymmcore_plus/mocks.py +51 -0
- pymmcore_plus/model/_config_file.py +5 -6
- pymmcore_plus/model/_config_group.py +29 -2
- pymmcore_plus/model/_core_device.py +12 -1
- pymmcore_plus/model/_core_link.py +2 -1
- pymmcore_plus/model/_device.py +39 -8
- pymmcore_plus/model/_microscope.py +39 -3
- pymmcore_plus/model/_pixel_size_config.py +27 -4
- pymmcore_plus/model/_property.py +13 -3
- pymmcore_plus/seq_tester.py +1 -1
- {pymmcore_plus-0.9.3.dist-info → pymmcore_plus-0.13.0.dist-info}/METADATA +22 -12
- pymmcore_plus-0.13.0.dist-info/RECORD +71 -0
- {pymmcore_plus-0.9.3.dist-info → pymmcore_plus-0.13.0.dist-info}/WHEEL +1 -1
- pymmcore_plus/core/_state.py +0 -244
- pymmcore_plus-0.9.3.dist-info/RECORD +0 -55
- {pymmcore_plus-0.9.3.dist-info → pymmcore_plus-0.13.0.dist-info}/entry_points.txt +0 -0
- {pymmcore_plus-0.9.3.dist-info → pymmcore_plus-0.13.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,12 +1,17 @@
|
|
|
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, NamedTuple
|
|
5
5
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
7
|
+
from collections.abc import Container, MutableMapping
|
|
7
8
|
from typing import Final
|
|
8
9
|
|
|
10
|
+
from typing_extensions import Self # py311
|
|
11
|
+
|
|
9
12
|
from pymmcore_plus import CMMCorePlus
|
|
13
|
+
from pymmcore_plus.metadata.schema import ConfigGroup as ConfigGroupMeta
|
|
14
|
+
from pymmcore_plus.metadata.schema import ConfigPreset as ConfigPresetMeta
|
|
10
15
|
|
|
11
16
|
from ._core_link import ErrCallback
|
|
12
17
|
|
|
@@ -37,6 +42,20 @@ class ConfigPreset:
|
|
|
37
42
|
name: str
|
|
38
43
|
settings: list[Setting] = field(default_factory=list)
|
|
39
44
|
|
|
45
|
+
@classmethod
|
|
46
|
+
def from_metadata(cls, meta: ConfigPresetMeta) -> Self:
|
|
47
|
+
return cls(
|
|
48
|
+
name=meta["name"],
|
|
49
|
+
settings=[
|
|
50
|
+
Setting(
|
|
51
|
+
device_name=d["dev"],
|
|
52
|
+
property_name=d["prop"],
|
|
53
|
+
property_value=d["val"],
|
|
54
|
+
)
|
|
55
|
+
for d in meta["settings"]
|
|
56
|
+
],
|
|
57
|
+
)
|
|
58
|
+
|
|
40
59
|
|
|
41
60
|
@dataclass
|
|
42
61
|
class ConfigGroup:
|
|
@@ -46,7 +65,15 @@ class ConfigGroup:
|
|
|
46
65
|
presets: MutableMapping[str, ConfigPreset] = field(default_factory=dict)
|
|
47
66
|
|
|
48
67
|
@classmethod
|
|
49
|
-
def
|
|
68
|
+
def from_metadata(cls, meta: ConfigGroupMeta) -> Self:
|
|
69
|
+
presets = {
|
|
70
|
+
preset["name"]: ConfigPreset.from_metadata(preset)
|
|
71
|
+
for preset in meta["presets"]
|
|
72
|
+
}
|
|
73
|
+
return cls(name=meta["name"], presets=presets)
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def create_from_core(cls, core: CMMCorePlus, name: str) -> Self:
|
|
50
77
|
obj = cls(name=name)
|
|
51
78
|
obj.update_from_core(core)
|
|
52
79
|
return obj
|
|
@@ -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, Any
|
|
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
|
|
@@ -48,6 +50,15 @@ class CoreDevice(Device):
|
|
|
48
50
|
def __post_init__(self) -> None:
|
|
49
51
|
self.CORE_GETTERS = {}
|
|
50
52
|
|
|
53
|
+
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
54
|
+
super().__setstate__(state)
|
|
55
|
+
prop_objects = []
|
|
56
|
+
for prop in self.properties:
|
|
57
|
+
if isinstance(prop, dict):
|
|
58
|
+
prop = Property(**prop)
|
|
59
|
+
prop_objects.append(prop)
|
|
60
|
+
self.properties = prop_objects
|
|
61
|
+
|
|
51
62
|
def __hash__(self) -> int:
|
|
52
63
|
return super().__hash__()
|
|
53
64
|
|
|
@@ -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
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
from contextlib import suppress
|
|
5
|
-
from dataclasses import dataclass, field
|
|
5
|
+
from dataclasses import asdict, dataclass, field
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from pymmcore_plus import CMMCorePlus, DeviceType, FocusDirection, Keyword
|
|
@@ -12,9 +12,15 @@ 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
|
-
from typing_extensions import
|
|
18
|
+
from typing_extensions import (
|
|
19
|
+
Self, # py311
|
|
20
|
+
TypeAlias, # py310
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from pymmcore_plus.metadata.schema import DeviceInfo
|
|
18
24
|
|
|
19
25
|
from ._core_link import ErrCallback
|
|
20
26
|
from ._microscope import Microscope
|
|
@@ -84,6 +90,20 @@ class Device(CoreObject):
|
|
|
84
90
|
# from the same library that can be loaded into this hub.
|
|
85
91
|
children: tuple[str, ...] = field(default_factory=tuple)
|
|
86
92
|
|
|
93
|
+
@classmethod
|
|
94
|
+
def from_metadata(cls, metadata: DeviceInfo) -> Self:
|
|
95
|
+
return cls(
|
|
96
|
+
name=metadata["label"],
|
|
97
|
+
library=metadata["library"],
|
|
98
|
+
adapter_name=metadata["name"],
|
|
99
|
+
description=metadata["description"],
|
|
100
|
+
device_type=DeviceType[metadata["type"]],
|
|
101
|
+
parent_label=metadata.get("parent_label") or "",
|
|
102
|
+
labels=tuple(metadata.get("labels", [])),
|
|
103
|
+
focus_direction=FocusDirection[metadata.get("focus_direction", "Unknown")],
|
|
104
|
+
children=tuple(metadata.get("child_names", [])),
|
|
105
|
+
)
|
|
106
|
+
|
|
87
107
|
def __post_init__(self) -> None:
|
|
88
108
|
if self.name == Keyword.CoreDevice or self.device_type == DeviceType.Core:
|
|
89
109
|
raise ValueError(
|
|
@@ -173,11 +193,7 @@ class Device(CoreObject):
|
|
|
173
193
|
raise RuntimeError(f"Device {self.name} is not loaded in the core.")
|
|
174
194
|
|
|
175
195
|
self.device_type = core.getDeviceType(self.name)
|
|
176
|
-
self.
|
|
177
|
-
DeviceType.StateDevice: STATE_DEVICE_GETTERS,
|
|
178
|
-
DeviceType.StageDevice: STAGE_DEVICE_GETTERS,
|
|
179
|
-
DeviceType.Hub: HUB_DEVICE_GETTERS,
|
|
180
|
-
}.get(self.device_type, DEVICE_GETTERS)
|
|
196
|
+
self._update_core_getters()
|
|
181
197
|
|
|
182
198
|
super().update_from_core(core, exclude=exclude, on_err=on_err)
|
|
183
199
|
self.properties = [
|
|
@@ -185,6 +201,21 @@ class Device(CoreObject):
|
|
|
185
201
|
for prop_name in core.getDevicePropertyNames(self.name)
|
|
186
202
|
]
|
|
187
203
|
|
|
204
|
+
# pulled out for the sake of picklability
|
|
205
|
+
def _update_core_getters(self) -> None:
|
|
206
|
+
self.CORE_GETTERS = {
|
|
207
|
+
DeviceType.StateDevice: STATE_DEVICE_GETTERS,
|
|
208
|
+
DeviceType.StageDevice: STAGE_DEVICE_GETTERS,
|
|
209
|
+
DeviceType.Hub: HUB_DEVICE_GETTERS,
|
|
210
|
+
}.get(self.device_type, DEVICE_GETTERS)
|
|
211
|
+
|
|
212
|
+
def __reduce__(self) -> str | tuple[Any, ...]:
|
|
213
|
+
return self.__class__, (), asdict(self)
|
|
214
|
+
|
|
215
|
+
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
216
|
+
self.__dict__.update(state)
|
|
217
|
+
self._update_core_getters()
|
|
218
|
+
|
|
188
219
|
def load(self, core: CMMCorePlus, *, reload: bool = False) -> None:
|
|
189
220
|
"""Load device properties from the core."""
|
|
190
221
|
if reload and self.name in core.getLoadedDevices():
|
|
@@ -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,7 +14,10 @@ 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
|
|
20
|
+
from pymmcore_plus.metadata.schema import SummaryMetaV1
|
|
18
21
|
|
|
19
22
|
from ._core_link import ErrCallback
|
|
20
23
|
from ._property import Property
|
|
@@ -126,7 +129,7 @@ class Microscope:
|
|
|
126
129
|
# ------------- Config-file methods -------------
|
|
127
130
|
|
|
128
131
|
@classmethod
|
|
129
|
-
def create_from_config(cls, config_file: str) -> Microscope:
|
|
132
|
+
def create_from_config(cls, config_file: str | Path) -> Microscope:
|
|
130
133
|
obj = cls()
|
|
131
134
|
obj.load_config(config_file)
|
|
132
135
|
obj.mark_clean()
|
|
@@ -154,6 +157,39 @@ class Microscope:
|
|
|
154
157
|
|
|
155
158
|
self.mark_clean()
|
|
156
159
|
|
|
160
|
+
@classmethod
|
|
161
|
+
def from_summary_metadata(cls, summary_meta: SummaryMetaV1) -> Microscope:
|
|
162
|
+
"""Create a Microscope model from summary metadata.
|
|
163
|
+
|
|
164
|
+
This may be used to load a model from summary metadata, such as as written
|
|
165
|
+
during the course of a Multi-Dimensional Acquisition. This is useful for
|
|
166
|
+
restoring the state of a microscope from a specific experiment, or writing
|
|
167
|
+
out a cfg file that can be used to restore the state of the microscope.
|
|
168
|
+
"""
|
|
169
|
+
core_device = next(
|
|
170
|
+
(d for d in summary_meta["devices"] if d["name"] == Keyword.CoreDevice),
|
|
171
|
+
None,
|
|
172
|
+
)
|
|
173
|
+
if core_device is None:
|
|
174
|
+
raise ValueError("CoreDevice not found in metadata")
|
|
175
|
+
return cls(
|
|
176
|
+
core_device=CoreDevice.from_metadata(core_device),
|
|
177
|
+
devices=[
|
|
178
|
+
Device.from_metadata(d)
|
|
179
|
+
for d in summary_meta["devices"]
|
|
180
|
+
if d["name"] != Keyword.CoreDevice
|
|
181
|
+
],
|
|
182
|
+
config_groups={
|
|
183
|
+
grp["name"]: ConfigGroup.from_metadata(grp)
|
|
184
|
+
for grp in summary_meta["config_groups"]
|
|
185
|
+
},
|
|
186
|
+
pixel_size_group=PixelSizeGroup.from_metadata(
|
|
187
|
+
summary_meta["pixel_size_configs"]
|
|
188
|
+
),
|
|
189
|
+
config_file=summary_meta["system_info"].get("system_configuration_file")
|
|
190
|
+
or "",
|
|
191
|
+
)
|
|
192
|
+
|
|
157
193
|
# ------------- Core-interacting methods -------------
|
|
158
194
|
|
|
159
195
|
@classmethod
|
|
@@ -178,7 +214,7 @@ class Microscope:
|
|
|
178
214
|
self.devices = [
|
|
179
215
|
Device.create_from_core(core, name=name)
|
|
180
216
|
for name in core.getLoadedDevices()
|
|
181
|
-
if name != Keyword.CoreDevice
|
|
217
|
+
if name != Keyword.CoreDevice # type: ignore [comparison-overlap]
|
|
182
218
|
]
|
|
183
219
|
if "core_device" not in exclude:
|
|
184
220
|
self.core_device.update_from_core(core)
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass, field, fields
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
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
|
-
from typing_extensions import
|
|
12
|
+
from typing_extensions import (
|
|
13
|
+
Self, # py311
|
|
14
|
+
TypeAlias, # py310
|
|
15
|
+
)
|
|
12
16
|
|
|
13
17
|
from pymmcore_plus import CMMCorePlus
|
|
18
|
+
from pymmcore_plus.metadata.schema import PixelSizeConfigPreset
|
|
14
19
|
|
|
15
20
|
from ._core_link import ErrCallback
|
|
16
21
|
|
|
@@ -27,6 +32,14 @@ class PixelSizePreset(ConfigPreset):
|
|
|
27
32
|
pixel_size_um: float = 0.0
|
|
28
33
|
affine: AffineTuple = DEFAULT_AFFINE
|
|
29
34
|
|
|
35
|
+
@classmethod
|
|
36
|
+
def from_metadata(cls, meta: PixelSizeConfigPreset) -> Self: # type: ignore [override]
|
|
37
|
+
obj = super().from_metadata(meta)
|
|
38
|
+
obj.pixel_size_um = meta["pixel_size_um"]
|
|
39
|
+
if "pixel_size_affine" in meta:
|
|
40
|
+
obj.affine = meta["pixel_size_affine"]
|
|
41
|
+
return obj
|
|
42
|
+
|
|
30
43
|
def __rich_repr__(self, *, defaults: bool = False) -> Iterable[tuple[str, Any]]:
|
|
31
44
|
"""Make AvailableDevices look a little less verbose."""
|
|
32
45
|
for f in fields(self):
|
|
@@ -45,6 +58,16 @@ class PixelSizeGroup(ConfigGroup):
|
|
|
45
58
|
name: str = PIXEL_SIZE_GROUP
|
|
46
59
|
presets: MutableMapping[str, PixelSizePreset] = field(default_factory=dict) # type: ignore
|
|
47
60
|
|
|
61
|
+
@classmethod
|
|
62
|
+
def from_metadata(cls, meta: tuple[PixelSizeConfigPreset, ...]) -> Self: # type: ignore [override]
|
|
63
|
+
"""Create a PixelSizeGroup from metadata."""
|
|
64
|
+
return cls(
|
|
65
|
+
presets={
|
|
66
|
+
preset_info["name"]: PixelSizePreset.from_metadata(preset_info)
|
|
67
|
+
for preset_info in meta
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
|
|
48
71
|
@classmethod
|
|
49
72
|
def create_from_core(
|
|
50
73
|
cls, core: CMMCorePlus, name: str = PIXEL_SIZE_GROUP
|
|
@@ -55,7 +78,7 @@ class PixelSizeGroup(ConfigGroup):
|
|
|
55
78
|
preset: PixelSizePreset(
|
|
56
79
|
name=preset,
|
|
57
80
|
pixel_size_um=core.getPixelSizeUmByID(preset),
|
|
58
|
-
affine=core.getPixelSizeAffineByID(preset),
|
|
81
|
+
affine=core.getPixelSizeAffineByID(preset),
|
|
59
82
|
settings=[Setting(*d) for d in core.getPixelSizeConfigData(preset)],
|
|
60
83
|
)
|
|
61
84
|
for preset in core.getAvailablePixelSizeConfigs()
|
pymmcore_plus/model/_property.py
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from dataclasses import dataclass, field
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from dataclasses import asdict, dataclass, field
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
5
|
|
|
6
6
|
from pymmcore_plus import CMMCorePlus, PropertyType
|
|
7
7
|
|
|
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
|
|
|
@@ -52,6 +53,15 @@ class Property(CoreObject):
|
|
|
52
53
|
"exists": CMMCorePlus.hasProperty,
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
def __reduce__(self) -> tuple:
|
|
57
|
+
# Return the class, arguments for __init__, and any state to restore
|
|
58
|
+
state = asdict(self)
|
|
59
|
+
return self.__class__, (self.device_name, self.name), state
|
|
60
|
+
|
|
61
|
+
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
62
|
+
# Restore the state of the object
|
|
63
|
+
self.__dict__.update(state)
|
|
64
|
+
|
|
55
65
|
def _core_args(self) -> tuple[str, str]:
|
|
56
66
|
# the first two args to all of the funcs in CORE_GETTERS
|
|
57
67
|
return self.device_name, self.name
|
pymmcore_plus/seq_tester.py
CHANGED
|
@@ -41,7 +41,7 @@ if TYPE_CHECKING:
|
|
|
41
41
|
import numpy as np
|
|
42
42
|
from typing_extensions import Self # py311
|
|
43
43
|
|
|
44
|
-
__all__ = ["CameraInfo", "
|
|
44
|
+
__all__ = ["CameraInfo", "InfoPacket", "Setting", "SettingEvent", "decode_image"]
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
@dataclass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pymmcore-plus
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.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,24 +16,24 @@ 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
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
24
|
Classifier: Topic :: System :: Hardware
|
|
25
25
|
Classifier: Topic :: System :: Hardware :: Hardware Drivers
|
|
26
26
|
Classifier: Topic :: Utilities
|
|
27
|
-
Requires-Python: >=3.
|
|
27
|
+
Requires-Python: >=3.9
|
|
28
28
|
Requires-Dist: numpy>=1.17.3
|
|
29
29
|
Requires-Dist: platformdirs>=3.0.0
|
|
30
30
|
Requires-Dist: psygnal>=0.7
|
|
31
31
|
Requires-Dist: pymmcore>=10.7.0.71.0
|
|
32
32
|
Requires-Dist: rich>=10.2.0
|
|
33
|
+
Requires-Dist: tensorstore; python_version < '3.13'
|
|
33
34
|
Requires-Dist: typer>=0.4.2
|
|
34
35
|
Requires-Dist: typing-extensions
|
|
35
|
-
Requires-Dist: useq-schema>=0.
|
|
36
|
-
Requires-Dist: wrapt>=1.14
|
|
36
|
+
Requires-Dist: useq-schema>=0.6.2
|
|
37
37
|
Provides-Extra: cli
|
|
38
38
|
Requires-Dist: rich>=10.2.0; extra == 'cli'
|
|
39
39
|
Requires-Dist: typer>=0.4.2; extra == 'cli'
|
|
@@ -43,17 +43,27 @@ Requires-Dist: mypy; extra == 'dev'
|
|
|
43
43
|
Requires-Dist: pdbpp; extra == 'dev'
|
|
44
44
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
45
45
|
Requires-Dist: ruff; extra == 'dev'
|
|
46
|
+
Requires-Dist: tensorstore-stubs; extra == 'dev'
|
|
46
47
|
Provides-Extra: docs
|
|
47
48
|
Requires-Dist: mkdocs-material; extra == 'docs'
|
|
49
|
+
Requires-Dist: mkdocs-typer==0.0.3; extra == 'docs'
|
|
48
50
|
Requires-Dist: mkdocs>=1.4; extra == 'docs'
|
|
49
51
|
Requires-Dist: mkdocstrings-python==1.1.2; extra == 'docs'
|
|
50
52
|
Requires-Dist: mkdocstrings==0.22.0; extra == 'docs'
|
|
51
53
|
Provides-Extra: io
|
|
52
54
|
Requires-Dist: tifffile>=2021.6.14; extra == 'io'
|
|
53
|
-
Requires-Dist: zarr
|
|
55
|
+
Requires-Dist: zarr<3,>=2.2; extra == 'io'
|
|
56
|
+
Provides-Extra: pyqt5
|
|
57
|
+
Requires-Dist: pyqt5>=5.15.4; extra == 'pyqt5'
|
|
58
|
+
Provides-Extra: pyqt6
|
|
59
|
+
Requires-Dist: pyqt6<6.8,>=6.4.2; extra == 'pyqt6'
|
|
60
|
+
Provides-Extra: pyside2
|
|
61
|
+
Requires-Dist: pyside2>=5.15; extra == 'pyside2'
|
|
62
|
+
Provides-Extra: pyside6
|
|
63
|
+
Requires-Dist: pyside6<6.8,>=6.4.0; extra == 'pyside6'
|
|
54
64
|
Provides-Extra: test
|
|
55
65
|
Requires-Dist: msgpack; extra == 'test'
|
|
56
|
-
Requires-Dist:
|
|
66
|
+
Requires-Dist: msgspec; (python_version < '3.13') and extra == 'test'
|
|
57
67
|
Requires-Dist: pytest-cov>=4; extra == 'test'
|
|
58
68
|
Requires-Dist: pytest-qt>=4; extra == 'test'
|
|
59
69
|
Requires-Dist: pytest>=7.3.2; extra == 'test'
|
|
@@ -61,7 +71,8 @@ Requires-Dist: qtpy>=2; extra == 'test'
|
|
|
61
71
|
Requires-Dist: rich; extra == 'test'
|
|
62
72
|
Requires-Dist: tifffile>=2021.6.14; extra == 'test'
|
|
63
73
|
Requires-Dist: typer>=0.4.2; extra == 'test'
|
|
64
|
-
Requires-Dist:
|
|
74
|
+
Requires-Dist: xarray; extra == 'test'
|
|
75
|
+
Requires-Dist: zarr<3,>=2.2; extra == 'test'
|
|
65
76
|
Description-Content-Type: text/markdown
|
|
66
77
|
|
|
67
78
|
# pymmcore-plus
|
|
@@ -70,7 +81,7 @@ Description-Content-Type: text/markdown
|
|
|
70
81
|
[](https://pypi.org/project/pymmcore-plus)
|
|
71
82
|
[](https://pypi.org/project/pymmcore-plus)
|
|
72
83
|
[](https://anaconda.org/conda-forge/pymmcore-plus)
|
|
73
|
-
[](https://github.com/pymmcore-plus/pymmcore-plus/actions/workflows/ci.yml)
|
|
74
85
|
[](https://pymmcore-plus.github.io/pymmcore-plus/)
|
|
75
86
|
[](https://codecov.io/gh/pymmcore-plus/pymmcore-plus)
|
|
76
87
|
[](https://codspeed.io/pymmcore-plus/pymmcore-plus)
|
|
@@ -141,8 +152,7 @@ provides a python API to control the C++ core directly, without the need for
|
|
|
141
152
|
Java in the loop. Each has its own advantages and disadvantages! With
|
|
142
153
|
pycro-manager you immediately get the entire existing micro-manager ecosystem
|
|
143
154
|
and GUI application. With pymmcore-plus you don't need to install Java, and you
|
|
144
|
-
have direct access to the memory buffers used by the C++ core
|
|
145
|
-
side of things is far less mature.
|
|
155
|
+
have direct access to the memory buffers used by the C++ core.
|
|
146
156
|
|
|
147
157
|
## Quickstart
|
|
148
158
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
pymmcore_plus/__init__.py,sha256=9-vK2P2jkJJ2REhCjFDBbJu0wrZM0jvDcf-d2GsjTk0,1415
|
|
2
|
+
pymmcore_plus/_benchmark.py,sha256=YJICxXleFQVbOluJdq4OujnIcTkkuMVzeB8GJ8nUv5I,6011
|
|
3
|
+
pymmcore_plus/_build.py,sha256=RPTAuwCZWGL5IDJj4JZo1DIIouUsIqS3vnbPbG2_bRE,10993
|
|
4
|
+
pymmcore_plus/_cli.py,sha256=FWdIvr6Rh9DVAItFaz9fWx7CbbF8ikOHWICp5h0NHTw,16393
|
|
5
|
+
pymmcore_plus/_logger.py,sha256=d7ldqxY0rGWORKdIzNUiFc9BW6cFBx57kHWtXyY1HE0,5416
|
|
6
|
+
pymmcore_plus/_pymmcore.py,sha256=QGlCEEx2pz5JsRLy3nQX3afAvV-_rm6ptWsv05U5hxI,328
|
|
7
|
+
pymmcore_plus/_util.py,sha256=mz5fuyzOhoMARyKYeri8FnR6eHwXsOh45WNZblewS1E,20435
|
|
8
|
+
pymmcore_plus/install.py,sha256=OLKkssJbQ9VSU0Rclkke0fb4Ng1YKb3Ij9rYYbQuusM,8705
|
|
9
|
+
pymmcore_plus/mocks.py,sha256=ejB1EEnCZs3P2qtIXDcse8Ew4I-PdahgfZgCeFAk7io,1976
|
|
10
|
+
pymmcore_plus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
pymmcore_plus/seq_tester.py,sha256=PJFQmb-JwGhliwIgje9BOUNcaayDsA-2x278xoumfig,3768
|
|
12
|
+
pymmcore_plus/core/__init__.py,sha256=rYHv5JQVMVDlwYD1wodCc5L9ZbpVld1C_swGx4CRogA,1011
|
|
13
|
+
pymmcore_plus/core/_adapter.py,sha256=eu2BhGe_dnoQrIsh-u3poxWXsiF2Y8pfbKIGWbUgOk8,2857
|
|
14
|
+
pymmcore_plus/core/_config.py,sha256=yWwOnW6f37lLt83MnodNce04az-g8YDjyo7BvMiTc8s,10672
|
|
15
|
+
pymmcore_plus/core/_config_group.py,sha256=R-o4xuPDBPQAC3s-mFsiKwHVKWR38L9qq_aoWdPrAq8,8542
|
|
16
|
+
pymmcore_plus/core/_constants.py,sha256=ugXgCKVHt9E2s8outgA1cVgoB2Ea9Io4mcgxu5o_UAA,12617
|
|
17
|
+
pymmcore_plus/core/_device.py,sha256=Pz9Ekhss2c9IBA3B7WyMU2cCwc19Dp_dGVhMkzqUaIE,7762
|
|
18
|
+
pymmcore_plus/core/_metadata.py,sha256=3vb3d36XgNnUY44dpZ4Ccw0tvn4KCinZ8zrnDllmABI,2645
|
|
19
|
+
pymmcore_plus/core/_mmcore_plus.py,sha256=8tjNxpSRfDLmYbNllLgJ2RVbKLpeUsOMb0hw-MPR9BI,91621
|
|
20
|
+
pymmcore_plus/core/_property.py,sha256=QsQEzqOAedR24zEJ1Ge4kwScfT_7NOApVcgz6QxBJrI,8265
|
|
21
|
+
pymmcore_plus/core/_sequencing.py,sha256=Vb6hbRsb8RxSPUAlNSVWTM4Yvg7YYf9ZbewK7u_b-QM,16692
|
|
22
|
+
pymmcore_plus/core/events/__init__.py,sha256=Bb1Ga97GzY2z3fAeJkPs1wxbTXa1o_p6nIKof_UCvZs,1093
|
|
23
|
+
pymmcore_plus/core/events/_device_signal_view.py,sha256=t-NfBdg3E4rms4vDFxkkR5XtrpLxaBT7mfPwkpIsbVk,1079
|
|
24
|
+
pymmcore_plus/core/events/_norm_slot.py,sha256=8DCBoLHGh7cbB1OB19IJYwL6sFBFmkD8IakfBOvFbw8,2907
|
|
25
|
+
pymmcore_plus/core/events/_prop_event_mixin.py,sha256=FvJJnpEKrOR-_Sp3-NNCwFoUUHwmNKiHruo0Y1vybsY,4042
|
|
26
|
+
pymmcore_plus/core/events/_protocol.py,sha256=V4st91mw6LoogII2c05vJxD5SIQU24va86J0iqJWqXU,7528
|
|
27
|
+
pymmcore_plus/core/events/_psygnal.py,sha256=owaKlW2zpvocXDbAW4kHovBoVv4Fjfn-S5oUJrVWsD4,1646
|
|
28
|
+
pymmcore_plus/core/events/_qsignals.py,sha256=gr-GDiSVLhFhSfaoKrdTz2y3I_2IUg62bYDGuGrB3j0,3018
|
|
29
|
+
pymmcore_plus/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
|
+
pymmcore_plus/experimental/unicore/__init__.py,sha256=OcjUZ4tq-NtWDR5R3JFivsRePliQSIQ7Z92k_8Gfz2Q,361
|
|
31
|
+
pymmcore_plus/experimental/unicore/_device_manager.py,sha256=c5DAMsnK06xOy6G7YjHdUughc7xdFtzeo10woO5G_KE,6418
|
|
32
|
+
pymmcore_plus/experimental/unicore/_proxy.py,sha256=Sl_Jiwd4RlcKgmsrEUNZT38YPFGlQonELAg_n3sfbdo,4020
|
|
33
|
+
pymmcore_plus/experimental/unicore/_unicore.py,sha256=HM1rTpFFAtn5nuO9vJGsYGVkyTzeV-EY2KYdAY7EbWM,29027
|
|
34
|
+
pymmcore_plus/experimental/unicore/devices/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
+
pymmcore_plus/experimental/unicore/devices/_device.py,sha256=PfX4BSpVMPXyNCNWkZ0Xy1-72ZZdME5zm7NgtCRu8ts,9751
|
|
36
|
+
pymmcore_plus/experimental/unicore/devices/_properties.py,sha256=yqVyoXb3VSbHahN2mXOIgeKOS7pUQeiJIZ_Y2d55dTI,15387
|
|
37
|
+
pymmcore_plus/experimental/unicore/devices/_stage.py,sha256=Ab4uibYq1cjIBtwcthCxH2FudGq9UMjub-qVeRpApQY,7892
|
|
38
|
+
pymmcore_plus/mda/__init__.py,sha256=RXI4ubqV71lLTFVrj62UpGzXVwOOQfJSiXR0k5tRXdk,298
|
|
39
|
+
pymmcore_plus/mda/_engine.py,sha256=UsnyYmxj1EDPaP2lDiRuYpm2SUNsqlE0514w9hxgrVk,29258
|
|
40
|
+
pymmcore_plus/mda/_protocol.py,sha256=10CDJ9H57oX1z0oqK3eShXyQhufHvvu3_8wdaCYpPIg,3254
|
|
41
|
+
pymmcore_plus/mda/_runner.py,sha256=IeZ34e4rcjRoPayCYJo_xn33yB4kPFltt23ntHE9TVI,16679
|
|
42
|
+
pymmcore_plus/mda/_thread_relay.py,sha256=Ww-9gyvLEzwRhnpL1dpze71wL7IRlhH8K3Q1dmJIxgs,6193
|
|
43
|
+
pymmcore_plus/mda/events/__init__.py,sha256=rHTyhQZJ54dz-KtetvN22GvAY2ilR03x8v4H0qUR070,1191
|
|
44
|
+
pymmcore_plus/mda/events/_protocol.py,sha256=9Q7LjYOgEWQGS8gHMV97UXM9bhoVW2OeyoPyNsQbwzw,1659
|
|
45
|
+
pymmcore_plus/mda/events/_psygnal.py,sha256=TdN1mFGpTPXmEs9iwFKSC1svv87PDZkT2JZvl0tEGrQ,640
|
|
46
|
+
pymmcore_plus/mda/events/_qsignals.py,sha256=tULQg-e_NX197DxJXaWHn1zLJ-4tzc9QyOAnsobEDtA,554
|
|
47
|
+
pymmcore_plus/mda/handlers/_5d_writer_base.py,sha256=c9cA0n8DOBoZcy9asue5eV7jW8hFVC0XEewroFgDNHA,11925
|
|
48
|
+
pymmcore_plus/mda/handlers/__init__.py,sha256=LdO3jf47fb4gXmbP9I8f5xC9Mrfd_-shf86OAaN9LdA,305
|
|
49
|
+
pymmcore_plus/mda/handlers/_img_sequence_writer.py,sha256=fAj6CB90RXYJ2jJIRDFxZgQb-TfwuRPWGCPFopCijRI,11549
|
|
50
|
+
pymmcore_plus/mda/handlers/_ome_tiff_writer.py,sha256=pqqdl3KQd0tH5Gp4rHVgYqqh2Y8iwoKRXTjwq1JLy1E,6239
|
|
51
|
+
pymmcore_plus/mda/handlers/_ome_zarr_writer.py,sha256=cKg3kJR7TId6M2qC1nJMLlxkv5vlfA5XEAlTIr9kt_E,12275
|
|
52
|
+
pymmcore_plus/mda/handlers/_tensorstore_handler.py,sha256=_xaUkDEYoTO29u4iHPQK8ygcCy8CSCXYi1xu5QF8B8E,14829
|
|
53
|
+
pymmcore_plus/mda/handlers/_util.py,sha256=pZydpKAXtQ_gjq5x1yNK1D0hfS7NUL2nH9ivOBg4abc,1600
|
|
54
|
+
pymmcore_plus/metadata/__init__.py,sha256=0o_v53kwR4U_RLlCnr7GD1G6OdFlVuUByIqXiaaM5uk,699
|
|
55
|
+
pymmcore_plus/metadata/functions.py,sha256=EjwB-6UO8c8AUriawhbE7x6ZAR1vJAxc72iYqyes5PQ,12506
|
|
56
|
+
pymmcore_plus/metadata/schema.py,sha256=j7nMwjCBXaAC0zKA2OsF201dsOB_3b2ggjqIa7EiVPQ,17368
|
|
57
|
+
pymmcore_plus/metadata/serialize.py,sha256=hpXJm0tzILELf6OYECMg0sQhuf-h25ob6_DDl-TUUME,3805
|
|
58
|
+
pymmcore_plus/model/__init__.py,sha256=zKZkkSpNK4ERu-VMdi9gvRrj1aXAjNaYxlYB5PdYSg0,479
|
|
59
|
+
pymmcore_plus/model/_config_file.py,sha256=Cw3bF1DLQUbMXVz59ZEUjfSaXcw8Lz6StIagReIKB-k,13280
|
|
60
|
+
pymmcore_plus/model/_config_group.py,sha256=vL_-EWH-Nsb8xTgFqpYIFaJzBk_RDBFchBnQ61DMSvI,3407
|
|
61
|
+
pymmcore_plus/model/_core_device.py,sha256=viwMgrCTZn1XYIyjC8w4xj1XAmoowZmCb93isGbG8BE,2722
|
|
62
|
+
pymmcore_plus/model/_core_link.py,sha256=dsbT0gncfa3TAORSaWUrZR9rcI_nOLX9e5BTmyo-UYo,2737
|
|
63
|
+
pymmcore_plus/model/_device.py,sha256=-0s3NkonDoaMrNy_hn5EDz-c4o33ZiJSQkV_kdBteoo,16115
|
|
64
|
+
pymmcore_plus/model/_microscope.py,sha256=69VV6cuevinOK_LhYEkQygHGesvCZefdn9YNt3mV618,11353
|
|
65
|
+
pymmcore_plus/model/_pixel_size_config.py,sha256=smoOmT54nSkg52RaSQzTFG0YwyMR_SEq_lkS-JyJW9U,3514
|
|
66
|
+
pymmcore_plus/model/_property.py,sha256=NQzNtnEzSCR9ogwx1cfi8X-qbJ_cBSJKdSBAaoKoPQ0,3720
|
|
67
|
+
pymmcore_plus-0.13.0.dist-info/METADATA,sha256=z9fR4Z8rz5jq8Mr8xhuxXyECVKrzdCxhm2_4MiNZgRo,9594
|
|
68
|
+
pymmcore_plus-0.13.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
69
|
+
pymmcore_plus-0.13.0.dist-info/entry_points.txt,sha256=NtFyndrQzBpUNJyil-8e5hMGke2utAf7mkGavTLcLOY,51
|
|
70
|
+
pymmcore_plus-0.13.0.dist-info/licenses/LICENSE,sha256=OHJjRpOPKKRc7FEnpehNWdR5LRBdBhUtIFG-ZI0dCEA,1522
|
|
71
|
+
pymmcore_plus-0.13.0.dist-info/RECORD,,
|