pymmcore-plus 0.13.0__py3-none-any.whl → 0.13.2__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/core/_constants.py +8 -3
- pymmcore_plus/mda/__init__.py +2 -1
- pymmcore_plus/mda/_engine.py +6 -1
- pymmcore_plus/mda/_runner.py +73 -33
- pymmcore_plus/mda/handlers/__init__.py +29 -0
- pymmcore_plus/mda/handlers/_img_sequence_writer.py +6 -2
- pymmcore_plus/mda/handlers/_tensorstore_handler.py +18 -4
- pymmcore_plus/mocks.py +1 -3
- pymmcore_plus/model/_config_file.py +15 -2
- {pymmcore_plus-0.13.0.dist-info → pymmcore_plus-0.13.2.dist-info}/METADATA +1 -1
- {pymmcore_plus-0.13.0.dist-info → pymmcore_plus-0.13.2.dist-info}/RECORD +14 -14
- {pymmcore_plus-0.13.0.dist-info → pymmcore_plus-0.13.2.dist-info}/WHEEL +0 -0
- {pymmcore_plus-0.13.0.dist-info → pymmcore_plus-0.13.2.dist-info}/entry_points.txt +0 -0
- {pymmcore_plus-0.13.0.dist-info → pymmcore_plus-0.13.2.dist-info}/licenses/LICENSE +0 -0
pymmcore_plus/core/_constants.py
CHANGED
|
@@ -209,10 +209,15 @@ class PortType(IntEnum):
|
|
|
209
209
|
HIDPort = pymmcore.HIDPort
|
|
210
210
|
|
|
211
211
|
|
|
212
|
+
# NB:
|
|
213
|
+
# do *not* use `pymmcore.FocusDirection...` enums here.
|
|
214
|
+
# the MMCore API does not use the device enums (which is what pymmcore exposes)
|
|
215
|
+
# but instead translates MM::FocusDirectionTowardSample into a different number:
|
|
216
|
+
# https://github.com/micro-manager/mmCoreAndDevices/tree/MMCore/MMCore.cpp#L2063-L2074
|
|
212
217
|
class FocusDirection(IntEnum):
|
|
213
|
-
Unknown =
|
|
214
|
-
TowardSample =
|
|
215
|
-
AwayFromSample =
|
|
218
|
+
Unknown = 0
|
|
219
|
+
TowardSample = 1
|
|
220
|
+
AwayFromSample = -1
|
|
216
221
|
# aliases
|
|
217
222
|
FocusDirectionUnknown = Unknown
|
|
218
223
|
FocusDirectionTowardSample = TowardSample
|
pymmcore_plus/mda/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from ._engine import MDAEngine
|
|
2
2
|
from ._protocol import PMDAEngine
|
|
3
|
-
from ._runner import MDARunner
|
|
3
|
+
from ._runner import MDARunner, SupportsFrameReady
|
|
4
4
|
from ._thread_relay import mda_listeners_connected
|
|
5
5
|
from .events import PMDASignaler
|
|
6
6
|
|
|
@@ -9,5 +9,6 @@ __all__ = [
|
|
|
9
9
|
"MDARunner",
|
|
10
10
|
"PMDAEngine",
|
|
11
11
|
"PMDASignaler",
|
|
12
|
+
"SupportsFrameReady",
|
|
12
13
|
"mda_listeners_connected",
|
|
13
14
|
]
|
pymmcore_plus/mda/_engine.py
CHANGED
|
@@ -248,7 +248,12 @@ class MDAEngine(PMDAEngine):
|
|
|
248
248
|
self._mmc.setExposure(event.exposure)
|
|
249
249
|
except Exception as e:
|
|
250
250
|
logger.warning("Failed to set exposure. %s", e)
|
|
251
|
-
|
|
251
|
+
if event.properties is not None:
|
|
252
|
+
try:
|
|
253
|
+
for dev, prop, value in event.properties:
|
|
254
|
+
self._mmc.setProperty(dev, prop, value)
|
|
255
|
+
except Exception as e:
|
|
256
|
+
logger.warning("Failed to set properties. %s", e)
|
|
252
257
|
if (
|
|
253
258
|
# (if autoshutter wasn't set at the beginning of the sequence
|
|
254
259
|
# then it never matters...)
|
pymmcore_plus/mda/_runner.py
CHANGED
|
@@ -5,8 +5,9 @@ import warnings
|
|
|
5
5
|
from collections.abc import Iterable, Iterator, Sequence
|
|
6
6
|
from contextlib import AbstractContextManager, nullcontext
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import TYPE_CHECKING, Any
|
|
8
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
9
9
|
from unittest.mock import MagicMock
|
|
10
|
+
from weakref import WeakSet
|
|
10
11
|
|
|
11
12
|
from useq import MDASequence
|
|
12
13
|
|
|
@@ -17,13 +18,40 @@ from ._thread_relay import mda_listeners_connected
|
|
|
17
18
|
from .events import PMDASignaler, _get_auto_MDA_callback_class
|
|
18
19
|
|
|
19
20
|
if TYPE_CHECKING:
|
|
20
|
-
from typing import TypeAlias
|
|
21
|
+
from typing import Protocol, TypeAlias
|
|
21
22
|
|
|
23
|
+
import numpy as np
|
|
22
24
|
from useq import MDAEvent
|
|
23
25
|
|
|
26
|
+
from pymmcore_plus.metadata.schema import FrameMetaV1
|
|
27
|
+
|
|
24
28
|
from ._engine import MDAEngine
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
class FrameReady0(Protocol):
|
|
31
|
+
"""Data handler with a no-argument `frameReady` method."""
|
|
32
|
+
|
|
33
|
+
def frameReady(self) -> Any: ...
|
|
34
|
+
|
|
35
|
+
class FrameReady1(Protocol):
|
|
36
|
+
"""Data handler with a `frameReady` method that takes `(image,)` ."""
|
|
37
|
+
|
|
38
|
+
def frameReady(self, img: np.ndarray, /) -> Any: ...
|
|
39
|
+
|
|
40
|
+
class FrameReady2(Protocol):
|
|
41
|
+
"""Data handler with a `frameReady` method that takes `(image, event)`."""
|
|
42
|
+
|
|
43
|
+
def frameReady(self, img: np.ndarray, event: MDAEvent, /) -> Any: ...
|
|
44
|
+
|
|
45
|
+
class FrameReady3(Protocol):
|
|
46
|
+
"""Data handler with a `frameReady` method that takes `(image, event, meta)`."""
|
|
47
|
+
|
|
48
|
+
def frameReady(
|
|
49
|
+
self, img: np.ndarray, event: MDAEvent, meta: FrameMetaV1, /
|
|
50
|
+
) -> Any: ...
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
SupportsFrameReady: TypeAlias = "FrameReady0 | FrameReady1 | FrameReady2 | FrameReady3"
|
|
54
|
+
SingleOutput: TypeAlias = "Path | str | SupportsFrameReady"
|
|
27
55
|
|
|
28
56
|
MSG = (
|
|
29
57
|
"This sequence is a placeholder for a generator of events with unknown "
|
|
@@ -67,7 +95,7 @@ class MDARunner:
|
|
|
67
95
|
self._paused = False
|
|
68
96
|
self._paused_time: float = 0
|
|
69
97
|
self._pause_interval: float = 0.1 # sec to wait between checking pause state
|
|
70
|
-
|
|
98
|
+
self._handlers: WeakSet[SupportsFrameReady] = WeakSet()
|
|
71
99
|
self._canceled = False
|
|
72
100
|
self._sequence: MDASequence | None = None
|
|
73
101
|
# timer for the full sequence, reset only once at the beginning of the sequence
|
|
@@ -189,6 +217,10 @@ class MDARunner:
|
|
|
189
217
|
- A handler object that implements the `DataHandler` protocol, currently
|
|
190
218
|
meaning it has a `frameReady` method. See `mda_listeners_connected`
|
|
191
219
|
for more details.
|
|
220
|
+
|
|
221
|
+
During the course of the sequence, the `get_output_handlers` method can be
|
|
222
|
+
used to get the currently connected output handlers (including those that
|
|
223
|
+
were created automatically based on file paths).
|
|
192
224
|
"""
|
|
193
225
|
error = None
|
|
194
226
|
sequence = events if isinstance(events, MDASequence) else GeneratorMDASequence()
|
|
@@ -206,6 +238,31 @@ class MDARunner:
|
|
|
206
238
|
if error is not None:
|
|
207
239
|
raise error
|
|
208
240
|
|
|
241
|
+
def get_output_handlers(self) -> tuple[SupportsFrameReady, ...]:
|
|
242
|
+
"""Return the data handlers that are currently connected.
|
|
243
|
+
|
|
244
|
+
Output handlers are connected by passing them to the `output` parameter of the
|
|
245
|
+
`run` method; the run method accepts objects with a `frameReady` method *or*
|
|
246
|
+
strings representing paths. If a string is passed, a handler will be created
|
|
247
|
+
internally.
|
|
248
|
+
|
|
249
|
+
This method returns a tuple of currently connected handlers, including those
|
|
250
|
+
that were explicitly passed to `run()`, as well as those that were created based
|
|
251
|
+
on file paths. Internally, handlers are held by weak references, so if you want
|
|
252
|
+
the handler to persist, you must keep a reference to it. The only guaranteed
|
|
253
|
+
API that the handler will have is the `frameReady` method, but it could be any
|
|
254
|
+
user-defined object that implements that method.
|
|
255
|
+
|
|
256
|
+
Handlers are cleared each time `run()` is called, (but not at the end
|
|
257
|
+
of the sequence).
|
|
258
|
+
|
|
259
|
+
Returns
|
|
260
|
+
-------
|
|
261
|
+
tuple[SupportsFrameReady, ...]
|
|
262
|
+
Tuple of objects that (minimally) support the `frameReady` method.
|
|
263
|
+
"""
|
|
264
|
+
return tuple(self._handlers)
|
|
265
|
+
|
|
209
266
|
def seconds_elapsed(self) -> float:
|
|
210
267
|
"""Return the number of seconds since the start of the acquisition."""
|
|
211
268
|
return time.perf_counter() - self._sequence_t0
|
|
@@ -228,48 +285,31 @@ class MDARunner:
|
|
|
228
285
|
if isinstance(output, (str, Path)) or not isinstance(output, Sequence):
|
|
229
286
|
output = [output]
|
|
230
287
|
|
|
231
|
-
# convert all items to handler objects
|
|
232
|
-
|
|
288
|
+
# convert all items to handler objects, preserving order
|
|
289
|
+
_handlers: list[SupportsFrameReady] = []
|
|
233
290
|
for item in output:
|
|
234
291
|
if isinstance(item, (str, Path)):
|
|
235
|
-
|
|
292
|
+
_handlers.append(self._handler_for_path(item))
|
|
236
293
|
else:
|
|
237
|
-
|
|
238
|
-
# quick hack for now.
|
|
239
|
-
if not hasattr(item, "frameReady"):
|
|
294
|
+
if not callable(getattr(item, "frameReady", None)):
|
|
240
295
|
raise TypeError(
|
|
241
|
-
"Output handlers must have a frameReady method. "
|
|
296
|
+
"Output handlers must have a callable frameReady method. "
|
|
242
297
|
f"Got {item} with type {type(item)}."
|
|
243
298
|
)
|
|
244
|
-
|
|
299
|
+
_handlers.append(item)
|
|
245
300
|
|
|
246
|
-
|
|
301
|
+
self._handlers.clear()
|
|
302
|
+
self._handlers.update(_handlers)
|
|
303
|
+
return mda_listeners_connected(*_handlers, mda_events=self._signals)
|
|
247
304
|
|
|
248
|
-
def _handler_for_path(self, path: str | Path) ->
|
|
305
|
+
def _handler_for_path(self, path: str | Path) -> SupportsFrameReady:
|
|
249
306
|
"""Convert a string or Path into a handler object.
|
|
250
307
|
|
|
251
308
|
This method picks from the built-in handlers based on the extension of the path.
|
|
252
309
|
"""
|
|
253
|
-
|
|
254
|
-
if path.endswith(".zarr"):
|
|
255
|
-
from pymmcore_plus.mda.handlers import OMEZarrWriter
|
|
256
|
-
|
|
257
|
-
return OMEZarrWriter(path)
|
|
258
|
-
|
|
259
|
-
if path.endswith((".tiff", ".tif")):
|
|
260
|
-
from pymmcore_plus.mda.handlers import OMETiffWriter
|
|
261
|
-
|
|
262
|
-
return OMETiffWriter(path)
|
|
263
|
-
|
|
264
|
-
# FIXME: ugly hack for the moment to represent a non-existent directory
|
|
265
|
-
# there are many features that ImageSequenceWriter supports, and it's unclear
|
|
266
|
-
# how to infer them all from a single string.
|
|
267
|
-
if not (Path(path).suffix or Path(path).exists()):
|
|
268
|
-
from pymmcore_plus.mda.handlers import ImageSequenceWriter
|
|
269
|
-
|
|
270
|
-
return ImageSequenceWriter(path)
|
|
310
|
+
from pymmcore_plus.mda.handlers import handler_for_path
|
|
271
311
|
|
|
272
|
-
|
|
312
|
+
return cast("SupportsFrameReady", handler_for_path(path))
|
|
273
313
|
|
|
274
314
|
def _run(self, engine: PMDAEngine, events: Iterable[MDAEvent]) -> None:
|
|
275
315
|
"""Main execution of events, inside the try/except block of `run`."""
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
1
5
|
from ._img_sequence_writer import ImageSequenceWriter
|
|
2
6
|
from ._ome_tiff_writer import OMETiffWriter
|
|
3
7
|
from ._ome_zarr_writer import OMEZarrWriter
|
|
@@ -8,4 +12,29 @@ __all__ = [
|
|
|
8
12
|
"OMETiffWriter",
|
|
9
13
|
"OMEZarrWriter",
|
|
10
14
|
"TensorStoreHandler",
|
|
15
|
+
"handler_for_path",
|
|
11
16
|
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def handler_for_path(path: str | Path) -> object:
|
|
20
|
+
"""Convert a string or Path into a handler object.
|
|
21
|
+
|
|
22
|
+
This method picks from the built-in handlers based on the extension of the path.
|
|
23
|
+
"""
|
|
24
|
+
if str(path).rstrip("/").rstrip(":").lower() == "memory":
|
|
25
|
+
return TensorStoreHandler(kvstore="memory://")
|
|
26
|
+
|
|
27
|
+
path = str(Path(path).expanduser().resolve())
|
|
28
|
+
if path.endswith(".zarr"):
|
|
29
|
+
return OMEZarrWriter(path)
|
|
30
|
+
|
|
31
|
+
if path.endswith((".tiff", ".tif")):
|
|
32
|
+
return OMETiffWriter(path)
|
|
33
|
+
|
|
34
|
+
# FIXME: ugly hack for the moment to represent a non-existent directory
|
|
35
|
+
# there are many features that ImageSequenceWriter supports, and it's unclear
|
|
36
|
+
# how to infer them all from a single string.
|
|
37
|
+
if not (Path(path).suffix or Path(path).exists()):
|
|
38
|
+
return ImageSequenceWriter(path)
|
|
39
|
+
|
|
40
|
+
raise ValueError(f"Could not infer a writer handler for path: '{path}'")
|
|
@@ -22,6 +22,8 @@ if TYPE_CHECKING:
|
|
|
22
22
|
import useq
|
|
23
23
|
from typing_extensions import TypeAlias # py310
|
|
24
24
|
|
|
25
|
+
from pymmcore_plus.metadata.schema import FrameMetaV1
|
|
26
|
+
|
|
25
27
|
ImgWriter: TypeAlias = Callable[[str, npt.NDArray], Any]
|
|
26
28
|
|
|
27
29
|
FRAME_KEY = "frame"
|
|
@@ -118,7 +120,7 @@ class ImageSequenceWriter:
|
|
|
118
120
|
shutil.rmtree(self._directory)
|
|
119
121
|
|
|
120
122
|
# ongoing dict of frame meta... stored for easy rewrite without reading
|
|
121
|
-
self._frame_metadata: dict[str,
|
|
123
|
+
self._frame_metadata: dict[str, FrameMetaV1] = {}
|
|
122
124
|
self._frame_meta_file = self._directory.joinpath(self.FRAME_META_PATH)
|
|
123
125
|
self._seq_meta_file = self._directory.joinpath(self.SEQ_META_PATH)
|
|
124
126
|
|
|
@@ -186,7 +188,9 @@ class ImageSequenceWriter:
|
|
|
186
188
|
# write final frame metadata to disk
|
|
187
189
|
self._frame_meta_file.write_bytes(json_dumps(self._frame_metadata, indent=2))
|
|
188
190
|
|
|
189
|
-
def frameReady(
|
|
191
|
+
def frameReady(
|
|
192
|
+
self, frame: np.ndarray, event: useq.MDAEvent, meta: FrameMetaV1, /
|
|
193
|
+
) -> None:
|
|
190
194
|
"""Write a frame to disk."""
|
|
191
195
|
frame_idx = next(self._counter)
|
|
192
196
|
if self._name_template:
|
|
@@ -111,6 +111,8 @@ class TensorStoreHandler:
|
|
|
111
111
|
self.delete_existing = delete_existing
|
|
112
112
|
self.spec = spec
|
|
113
113
|
|
|
114
|
+
self._current_sequence: useq.MDASequence | None = None
|
|
115
|
+
|
|
114
116
|
# storage of individual frame metadata
|
|
115
117
|
# maps position key to list of frame metadata
|
|
116
118
|
self.frame_metadatas: list[tuple[useq.MDAEvent, FrameMetaV1]] = []
|
|
@@ -176,13 +178,25 @@ class TensorStoreHandler:
|
|
|
176
178
|
|
|
177
179
|
return cls(path=path, **kwargs)
|
|
178
180
|
|
|
179
|
-
def
|
|
180
|
-
"""
|
|
181
|
+
def reset(self, sequence: useq.MDASequence) -> None:
|
|
182
|
+
"""Reset state to prepare for new `sequence`."""
|
|
181
183
|
self._frame_index = 0
|
|
182
184
|
self._store = None
|
|
183
185
|
self._futures.clear()
|
|
184
186
|
self.frame_metadatas.clear()
|
|
185
|
-
self.
|
|
187
|
+
self._current_sequence = sequence
|
|
188
|
+
|
|
189
|
+
@property
|
|
190
|
+
def current_sequence(self) -> useq.MDASequence | None:
|
|
191
|
+
"""Return current sequence, or none.
|
|
192
|
+
|
|
193
|
+
Use `.reset()` to initialize the handler for a new sequence.
|
|
194
|
+
"""
|
|
195
|
+
return self._current_sequence
|
|
196
|
+
|
|
197
|
+
def sequenceStarted(self, seq: useq.MDASequence, meta: SummaryMetaV1) -> None:
|
|
198
|
+
"""On sequence started, simply store the sequence."""
|
|
199
|
+
self.reset(seq)
|
|
186
200
|
|
|
187
201
|
def sequenceFinished(self, seq: useq.MDASequence) -> None:
|
|
188
202
|
"""On sequence finished, clear the current sequence."""
|
|
@@ -199,7 +213,7 @@ class TensorStoreHandler:
|
|
|
199
213
|
self.finalize_metadata()
|
|
200
214
|
|
|
201
215
|
def frameReady(
|
|
202
|
-
self, frame: np.ndarray, event: useq.MDAEvent, meta: FrameMetaV1
|
|
216
|
+
self, frame: np.ndarray, event: useq.MDAEvent, meta: FrameMetaV1, /
|
|
203
217
|
) -> None:
|
|
204
218
|
"""Write frame to the zarr array for the appropriate position."""
|
|
205
219
|
if self._store is None:
|
pymmcore_plus/mocks.py
CHANGED
|
@@ -28,9 +28,7 @@ class MockSequenceableCore(MagicMock):
|
|
|
28
28
|
self.loadExposureSequence.return_value = None
|
|
29
29
|
self.loadStageSequence.return_value = None
|
|
30
30
|
self.loadXYStageSequence.return_value = None
|
|
31
|
-
|
|
32
|
-
if hasattr(CMMCorePlus, "loadSLMSequence"):
|
|
33
|
-
self.loadSLMSequence.return_value = None
|
|
31
|
+
self.loadSLMSequence.return_value = None
|
|
34
32
|
|
|
35
33
|
self.loadPropertySequence.return_value = None
|
|
36
34
|
|
|
@@ -209,18 +209,28 @@ def run_command(line: str, scope: Microscope) -> None:
|
|
|
209
209
|
return
|
|
210
210
|
|
|
211
211
|
exec_cmd, expected_n_args = COMMAND_EXECUTORS[command]
|
|
212
|
+
should_raise = command in SHOULD_RAISE
|
|
212
213
|
|
|
213
214
|
if (nargs := len(args) + 1) not in expected_n_args:
|
|
214
215
|
exp_str = " or ".join(map(str, expected_n_args))
|
|
215
|
-
|
|
216
|
+
msg = (
|
|
216
217
|
f"Invalid configuration line encountered for command {cmd_name}. "
|
|
217
218
|
f"Expected {exp_str} arguments, got {nargs}: {line!r}"
|
|
218
219
|
)
|
|
220
|
+
if should_raise:
|
|
221
|
+
raise ValueError(msg)
|
|
222
|
+
else:
|
|
223
|
+
warnings.warn(msg, RuntimeWarning, stacklevel=2)
|
|
224
|
+
return
|
|
219
225
|
|
|
220
226
|
try:
|
|
221
227
|
exec_cmd(scope, args)
|
|
222
228
|
except Exception as exc:
|
|
223
|
-
|
|
229
|
+
if should_raise:
|
|
230
|
+
raise ValueError(f"Error executing command {line!r}: {exc}") from exc
|
|
231
|
+
warnings.warn(
|
|
232
|
+
f"Failed to execute command {line!r}: {exc}", RuntimeWarning, stacklevel=2
|
|
233
|
+
)
|
|
224
234
|
|
|
225
235
|
|
|
226
236
|
def _exec_Device(scope: Microscope, args: Sequence[str]) -> None:
|
|
@@ -352,3 +362,6 @@ COMMAND_EXECUTORS: dict[CFGCommand, tuple[Executor, set[int]]] = {
|
|
|
352
362
|
CFGCommand.ParentID: (_exec_ParentID, {3}),
|
|
353
363
|
CFGCommand.FocusDirection: (_exec_FocusDirection, {3}),
|
|
354
364
|
}
|
|
365
|
+
|
|
366
|
+
# Commands that should raise when fail
|
|
367
|
+
SHOULD_RAISE = {CFGCommand.Device, CFGCommand.Property}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pymmcore-plus
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.2
|
|
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
|
|
@@ -6,14 +6,14 @@ pymmcore_plus/_logger.py,sha256=d7ldqxY0rGWORKdIzNUiFc9BW6cFBx57kHWtXyY1HE0,5416
|
|
|
6
6
|
pymmcore_plus/_pymmcore.py,sha256=QGlCEEx2pz5JsRLy3nQX3afAvV-_rm6ptWsv05U5hxI,328
|
|
7
7
|
pymmcore_plus/_util.py,sha256=mz5fuyzOhoMARyKYeri8FnR6eHwXsOh45WNZblewS1E,20435
|
|
8
8
|
pymmcore_plus/install.py,sha256=OLKkssJbQ9VSU0Rclkke0fb4Ng1YKb3Ij9rYYbQuusM,8705
|
|
9
|
-
pymmcore_plus/mocks.py,sha256=
|
|
9
|
+
pymmcore_plus/mocks.py,sha256=jNUfmffD1OArtIvEmqWsy7GCrtTpssVF03flH8cEYx8,1867
|
|
10
10
|
pymmcore_plus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
pymmcore_plus/seq_tester.py,sha256=PJFQmb-JwGhliwIgje9BOUNcaayDsA-2x278xoumfig,3768
|
|
12
12
|
pymmcore_plus/core/__init__.py,sha256=rYHv5JQVMVDlwYD1wodCc5L9ZbpVld1C_swGx4CRogA,1011
|
|
13
13
|
pymmcore_plus/core/_adapter.py,sha256=eu2BhGe_dnoQrIsh-u3poxWXsiF2Y8pfbKIGWbUgOk8,2857
|
|
14
14
|
pymmcore_plus/core/_config.py,sha256=yWwOnW6f37lLt83MnodNce04az-g8YDjyo7BvMiTc8s,10672
|
|
15
15
|
pymmcore_plus/core/_config_group.py,sha256=R-o4xuPDBPQAC3s-mFsiKwHVKWR38L9qq_aoWdPrAq8,8542
|
|
16
|
-
pymmcore_plus/core/_constants.py,sha256=
|
|
16
|
+
pymmcore_plus/core/_constants.py,sha256=6foxGbek3tgnUHYUtQ7NCqwIIqqGYW1W56HjrhZqsA0,12829
|
|
17
17
|
pymmcore_plus/core/_device.py,sha256=Pz9Ekhss2c9IBA3B7WyMU2cCwc19Dp_dGVhMkzqUaIE,7762
|
|
18
18
|
pymmcore_plus/core/_metadata.py,sha256=3vb3d36XgNnUY44dpZ4Ccw0tvn4KCinZ8zrnDllmABI,2645
|
|
19
19
|
pymmcore_plus/core/_mmcore_plus.py,sha256=8tjNxpSRfDLmYbNllLgJ2RVbKLpeUsOMb0hw-MPR9BI,91621
|
|
@@ -35,28 +35,28 @@ pymmcore_plus/experimental/unicore/devices/__init__.py,sha256=47DEQpj8HBSa-_TImW
|
|
|
35
35
|
pymmcore_plus/experimental/unicore/devices/_device.py,sha256=PfX4BSpVMPXyNCNWkZ0Xy1-72ZZdME5zm7NgtCRu8ts,9751
|
|
36
36
|
pymmcore_plus/experimental/unicore/devices/_properties.py,sha256=yqVyoXb3VSbHahN2mXOIgeKOS7pUQeiJIZ_Y2d55dTI,15387
|
|
37
37
|
pymmcore_plus/experimental/unicore/devices/_stage.py,sha256=Ab4uibYq1cjIBtwcthCxH2FudGq9UMjub-qVeRpApQY,7892
|
|
38
|
-
pymmcore_plus/mda/__init__.py,sha256=
|
|
39
|
-
pymmcore_plus/mda/_engine.py,sha256=
|
|
38
|
+
pymmcore_plus/mda/__init__.py,sha256=7VH-MqOcuK1JNSOG9HhES6Ac-Z-LuT8a0f2xPbGEt7w,344
|
|
39
|
+
pymmcore_plus/mda/_engine.py,sha256=m-GsTMCIX2CgyUZb32Cyp52fh3WcUW--evk_yLANu-E,29534
|
|
40
40
|
pymmcore_plus/mda/_protocol.py,sha256=10CDJ9H57oX1z0oqK3eShXyQhufHvvu3_8wdaCYpPIg,3254
|
|
41
|
-
pymmcore_plus/mda/_runner.py,sha256=
|
|
41
|
+
pymmcore_plus/mda/_runner.py,sha256=NSOhpll6_WxDLO19FTs19dASJcHcOoVOCy7q_QzX_Ms,18523
|
|
42
42
|
pymmcore_plus/mda/_thread_relay.py,sha256=Ww-9gyvLEzwRhnpL1dpze71wL7IRlhH8K3Q1dmJIxgs,6193
|
|
43
43
|
pymmcore_plus/mda/events/__init__.py,sha256=rHTyhQZJ54dz-KtetvN22GvAY2ilR03x8v4H0qUR070,1191
|
|
44
44
|
pymmcore_plus/mda/events/_protocol.py,sha256=9Q7LjYOgEWQGS8gHMV97UXM9bhoVW2OeyoPyNsQbwzw,1659
|
|
45
45
|
pymmcore_plus/mda/events/_psygnal.py,sha256=TdN1mFGpTPXmEs9iwFKSC1svv87PDZkT2JZvl0tEGrQ,640
|
|
46
46
|
pymmcore_plus/mda/events/_qsignals.py,sha256=tULQg-e_NX197DxJXaWHn1zLJ-4tzc9QyOAnsobEDtA,554
|
|
47
47
|
pymmcore_plus/mda/handlers/_5d_writer_base.py,sha256=c9cA0n8DOBoZcy9asue5eV7jW8hFVC0XEewroFgDNHA,11925
|
|
48
|
-
pymmcore_plus/mda/handlers/__init__.py,sha256=
|
|
49
|
-
pymmcore_plus/mda/handlers/_img_sequence_writer.py,sha256=
|
|
48
|
+
pymmcore_plus/mda/handlers/__init__.py,sha256=TbgpRdcs3BRdCf6uXJlwo_IIbxM6xXaLocKK1pyhU2Q,1286
|
|
49
|
+
pymmcore_plus/mda/handlers/_img_sequence_writer.py,sha256=XUJovvdWViTkn2VZr4XcovNIuBNZF4J4cCHIdwAs1WE,11639
|
|
50
50
|
pymmcore_plus/mda/handlers/_ome_tiff_writer.py,sha256=pqqdl3KQd0tH5Gp4rHVgYqqh2Y8iwoKRXTjwq1JLy1E,6239
|
|
51
51
|
pymmcore_plus/mda/handlers/_ome_zarr_writer.py,sha256=cKg3kJR7TId6M2qC1nJMLlxkv5vlfA5XEAlTIr9kt_E,12275
|
|
52
|
-
pymmcore_plus/mda/handlers/_tensorstore_handler.py,sha256=
|
|
52
|
+
pymmcore_plus/mda/handlers/_tensorstore_handler.py,sha256=_Hqfgc2I8n97KPT7quU0p4tqSlomtLbTO-e78bIB6hA,15280
|
|
53
53
|
pymmcore_plus/mda/handlers/_util.py,sha256=pZydpKAXtQ_gjq5x1yNK1D0hfS7NUL2nH9ivOBg4abc,1600
|
|
54
54
|
pymmcore_plus/metadata/__init__.py,sha256=0o_v53kwR4U_RLlCnr7GD1G6OdFlVuUByIqXiaaM5uk,699
|
|
55
55
|
pymmcore_plus/metadata/functions.py,sha256=EjwB-6UO8c8AUriawhbE7x6ZAR1vJAxc72iYqyes5PQ,12506
|
|
56
56
|
pymmcore_plus/metadata/schema.py,sha256=j7nMwjCBXaAC0zKA2OsF201dsOB_3b2ggjqIa7EiVPQ,17368
|
|
57
57
|
pymmcore_plus/metadata/serialize.py,sha256=hpXJm0tzILELf6OYECMg0sQhuf-h25ob6_DDl-TUUME,3805
|
|
58
58
|
pymmcore_plus/model/__init__.py,sha256=zKZkkSpNK4ERu-VMdi9gvRrj1aXAjNaYxlYB5PdYSg0,479
|
|
59
|
-
pymmcore_plus/model/_config_file.py,sha256=
|
|
59
|
+
pymmcore_plus/model/_config_file.py,sha256=nCAFh5dA7kYpoWTIwzoG4CHbdLwCYBBDGSOvZosFCFw,13711
|
|
60
60
|
pymmcore_plus/model/_config_group.py,sha256=vL_-EWH-Nsb8xTgFqpYIFaJzBk_RDBFchBnQ61DMSvI,3407
|
|
61
61
|
pymmcore_plus/model/_core_device.py,sha256=viwMgrCTZn1XYIyjC8w4xj1XAmoowZmCb93isGbG8BE,2722
|
|
62
62
|
pymmcore_plus/model/_core_link.py,sha256=dsbT0gncfa3TAORSaWUrZR9rcI_nOLX9e5BTmyo-UYo,2737
|
|
@@ -64,8 +64,8 @@ pymmcore_plus/model/_device.py,sha256=-0s3NkonDoaMrNy_hn5EDz-c4o33ZiJSQkV_kdBteo
|
|
|
64
64
|
pymmcore_plus/model/_microscope.py,sha256=69VV6cuevinOK_LhYEkQygHGesvCZefdn9YNt3mV618,11353
|
|
65
65
|
pymmcore_plus/model/_pixel_size_config.py,sha256=smoOmT54nSkg52RaSQzTFG0YwyMR_SEq_lkS-JyJW9U,3514
|
|
66
66
|
pymmcore_plus/model/_property.py,sha256=NQzNtnEzSCR9ogwx1cfi8X-qbJ_cBSJKdSBAaoKoPQ0,3720
|
|
67
|
-
pymmcore_plus-0.13.
|
|
68
|
-
pymmcore_plus-0.13.
|
|
69
|
-
pymmcore_plus-0.13.
|
|
70
|
-
pymmcore_plus-0.13.
|
|
71
|
-
pymmcore_plus-0.13.
|
|
67
|
+
pymmcore_plus-0.13.2.dist-info/METADATA,sha256=4z6G5lpau1oQJUFSejzKr88yNTWOzStR50mRZvaN6IU,9594
|
|
68
|
+
pymmcore_plus-0.13.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
69
|
+
pymmcore_plus-0.13.2.dist-info/entry_points.txt,sha256=NtFyndrQzBpUNJyil-8e5hMGke2utAf7mkGavTLcLOY,51
|
|
70
|
+
pymmcore_plus-0.13.2.dist-info/licenses/LICENSE,sha256=OHJjRpOPKKRc7FEnpehNWdR5LRBdBhUtIFG-ZI0dCEA,1522
|
|
71
|
+
pymmcore_plus-0.13.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|