pymmcore-plus 0.10.2__py3-none-any.whl → 0.11.1__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.
Files changed (33) hide show
  1. pymmcore_plus/__init__.py +4 -1
  2. pymmcore_plus/_build.py +2 -0
  3. pymmcore_plus/_cli.py +49 -14
  4. pymmcore_plus/_util.py +99 -9
  5. pymmcore_plus/core/__init__.py +2 -0
  6. pymmcore_plus/core/_constants.py +109 -8
  7. pymmcore_plus/core/_mmcore_plus.py +69 -49
  8. pymmcore_plus/mda/__init__.py +2 -2
  9. pymmcore_plus/mda/_engine.py +151 -102
  10. pymmcore_plus/mda/_protocol.py +5 -3
  11. pymmcore_plus/mda/_runner.py +16 -21
  12. pymmcore_plus/mda/events/_protocol.py +10 -2
  13. pymmcore_plus/mda/handlers/_5d_writer_base.py +25 -13
  14. pymmcore_plus/mda/handlers/_img_sequence_writer.py +9 -5
  15. pymmcore_plus/mda/handlers/_ome_tiff_writer.py +7 -3
  16. pymmcore_plus/mda/handlers/_ome_zarr_writer.py +9 -4
  17. pymmcore_plus/mda/handlers/_tensorstore_handler.py +19 -19
  18. pymmcore_plus/metadata/__init__.py +36 -0
  19. pymmcore_plus/metadata/functions.py +343 -0
  20. pymmcore_plus/metadata/schema.py +471 -0
  21. pymmcore_plus/metadata/serialize.py +116 -0
  22. pymmcore_plus/model/_config_file.py +2 -4
  23. pymmcore_plus/model/_config_group.py +29 -3
  24. pymmcore_plus/model/_device.py +20 -1
  25. pymmcore_plus/model/_microscope.py +36 -2
  26. pymmcore_plus/model/_pixel_size_config.py +26 -4
  27. {pymmcore_plus-0.10.2.dist-info → pymmcore_plus-0.11.1.dist-info}/METADATA +6 -5
  28. pymmcore_plus-0.11.1.dist-info/RECORD +59 -0
  29. {pymmcore_plus-0.10.2.dist-info → pymmcore_plus-0.11.1.dist-info}/WHEEL +1 -1
  30. pymmcore_plus/core/_state.py +0 -244
  31. pymmcore_plus-0.10.2.dist-info/RECORD +0 -56
  32. {pymmcore_plus-0.10.2.dist-info → pymmcore_plus-0.11.1.dist-info}/entry_points.txt +0 -0
  33. {pymmcore_plus-0.10.2.dist-info → pymmcore_plus-0.11.1.dist-info}/licenses/LICENSE +0 -0
@@ -15,6 +15,7 @@ from ._pixel_size_config import PixelSizeGroup
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from pymmcore_plus import CMMCorePlus
18
+ from pymmcore_plus.metadata.schema import SummaryMetaV1
18
19
 
19
20
  from ._core_link import ErrCallback
20
21
  from ._property import Property
@@ -126,7 +127,7 @@ class Microscope:
126
127
  # ------------- Config-file methods -------------
127
128
 
128
129
  @classmethod
129
- def create_from_config(cls, config_file: str) -> Microscope:
130
+ def create_from_config(cls, config_file: str | Path) -> Microscope:
130
131
  obj = cls()
131
132
  obj.load_config(config_file)
132
133
  obj.mark_clean()
@@ -154,6 +155,39 @@ class Microscope:
154
155
 
155
156
  self.mark_clean()
156
157
 
158
+ @classmethod
159
+ def from_summary_metadata(cls, summary_meta: SummaryMetaV1) -> Microscope:
160
+ """Create a Microscope model from summary metadata.
161
+
162
+ This may be used to load a model from summary metadata, such as as written
163
+ during the course of a Multi-Dimensional Acquisition. This is useful for
164
+ restoring the state of a microscope from a specific experiment, or writing
165
+ out a cfg file that can be used to restore the state of the microscope.
166
+ """
167
+ core_device = next(
168
+ (d for d in summary_meta["devices"] if d["name"] == Keyword.CoreDevice),
169
+ None,
170
+ )
171
+ if core_device is None:
172
+ raise ValueError("CoreDevice not found in metadata")
173
+ return cls(
174
+ core_device=CoreDevice.from_metadata(core_device),
175
+ devices=[
176
+ Device.from_metadata(d)
177
+ for d in summary_meta["devices"]
178
+ if d["name"] != Keyword.CoreDevice
179
+ ],
180
+ config_groups={
181
+ grp["name"]: ConfigGroup.from_metadata(grp)
182
+ for grp in summary_meta["config_groups"]
183
+ },
184
+ pixel_size_group=PixelSizeGroup.from_metadata(
185
+ summary_meta["pixel_size_configs"]
186
+ ),
187
+ config_file=summary_meta["system_info"].get("system_configuration_file")
188
+ or "",
189
+ )
190
+
157
191
  # ------------- Core-interacting methods -------------
158
192
 
159
193
  @classmethod
@@ -178,7 +212,7 @@ class Microscope:
178
212
  self.devices = [
179
213
  Device.create_from_core(core, name=name)
180
214
  for name in core.getLoadedDevices()
181
- if name != Keyword.CoreDevice
215
+ if name != Keyword.CoreDevice # type: ignore [comparison-overlap]
182
216
  ]
183
217
  if "core_device" not in exclude:
184
218
  self.core_device.update_from_core(core)
@@ -1,16 +1,20 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass, field, fields
4
- from typing import TYPE_CHECKING, Any, Container, Iterable, MutableMapping
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 typing import Final
9
+ from typing import Any, Container, Final, Iterable, MutableMapping
10
10
 
11
- from typing_extensions import TypeAlias # py310
11
+ from typing_extensions import (
12
+ Self, # py311
13
+ TypeAlias, # py310
14
+ )
12
15
 
13
16
  from pymmcore_plus import CMMCorePlus
17
+ from pymmcore_plus.metadata.schema import PixelSizeConfigPreset
14
18
 
15
19
  from ._core_link import ErrCallback
16
20
 
@@ -27,6 +31,14 @@ class PixelSizePreset(ConfigPreset):
27
31
  pixel_size_um: float = 0.0
28
32
  affine: AffineTuple = DEFAULT_AFFINE
29
33
 
34
+ @classmethod
35
+ def from_metadata(cls, meta: PixelSizeConfigPreset) -> Self: # type: ignore [override]
36
+ obj = super().from_metadata(meta)
37
+ obj.pixel_size_um = meta["pixel_size_um"]
38
+ if "pixel_size_affine" in meta:
39
+ obj.affine = meta["pixel_size_affine"]
40
+ return obj
41
+
30
42
  def __rich_repr__(self, *, defaults: bool = False) -> Iterable[tuple[str, Any]]:
31
43
  """Make AvailableDevices look a little less verbose."""
32
44
  for f in fields(self):
@@ -45,6 +57,16 @@ class PixelSizeGroup(ConfigGroup):
45
57
  name: str = PIXEL_SIZE_GROUP
46
58
  presets: MutableMapping[str, PixelSizePreset] = field(default_factory=dict) # type: ignore
47
59
 
60
+ @classmethod
61
+ def from_metadata(cls, meta: tuple[PixelSizeConfigPreset, ...]) -> Self: # type: ignore [override]
62
+ """Create a PixelSizeGroup from metadata."""
63
+ return cls(
64
+ presets={
65
+ preset_info["name"]: PixelSizePreset.from_metadata(preset_info)
66
+ for preset_info in meta
67
+ }
68
+ )
69
+
48
70
  @classmethod
49
71
  def create_from_core(
50
72
  cls, core: CMMCorePlus, name: str = PIXEL_SIZE_GROUP
@@ -55,7 +77,7 @@ class PixelSizeGroup(ConfigGroup):
55
77
  preset: PixelSizePreset(
56
78
  name=preset,
57
79
  pixel_size_um=core.getPixelSizeUmByID(preset),
58
- affine=core.getPixelSizeAffineByID(preset), # type: ignore
80
+ affine=core.getPixelSizeAffineByID(preset),
59
81
  settings=[Setting(*d) for d in core.getPixelSizeConfigData(preset)],
60
82
  )
61
83
  for preset in core.getAvailablePixelSizeConfigs()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pymmcore-plus
3
- Version: 0.10.2
3
+ Version: 0.11.1
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
@@ -47,14 +47,16 @@ Requires-Dist: ruff; extra == 'dev'
47
47
  Requires-Dist: tensorstore-stubs; extra == 'dev'
48
48
  Provides-Extra: docs
49
49
  Requires-Dist: mkdocs-material; extra == 'docs'
50
+ Requires-Dist: mkdocs-typer==0.0.3; extra == 'docs'
50
51
  Requires-Dist: mkdocs>=1.4; extra == 'docs'
51
52
  Requires-Dist: mkdocstrings-python==1.1.2; extra == 'docs'
52
53
  Requires-Dist: mkdocstrings==0.22.0; extra == 'docs'
53
54
  Provides-Extra: io
54
55
  Requires-Dist: tifffile>=2021.6.14; extra == 'io'
55
- Requires-Dist: zarr>=2.2; extra == 'io'
56
+ Requires-Dist: zarr<3,>=2.2; extra == 'io'
56
57
  Provides-Extra: test
57
58
  Requires-Dist: msgpack; extra == 'test'
59
+ Requires-Dist: msgspec; extra == 'test'
58
60
  Requires-Dist: pytest-cov>=4; extra == 'test'
59
61
  Requires-Dist: pytest-qt>=4; extra == 'test'
60
62
  Requires-Dist: pytest>=7.3.2; extra == 'test'
@@ -63,7 +65,7 @@ Requires-Dist: rich; extra == 'test'
63
65
  Requires-Dist: tifffile>=2021.6.14; extra == 'test'
64
66
  Requires-Dist: typer>=0.4.2; extra == 'test'
65
67
  Requires-Dist: xarray; extra == 'test'
66
- Requires-Dist: zarr>=2.2; extra == 'test'
68
+ Requires-Dist: zarr<3,>=2.2; extra == 'test'
67
69
  Description-Content-Type: text/markdown
68
70
 
69
71
  # pymmcore-plus
@@ -143,8 +145,7 @@ provides a python API to control the C++ core directly, without the need for
143
145
  Java in the loop. Each has its own advantages and disadvantages! With
144
146
  pycro-manager you immediately get the entire existing micro-manager ecosystem
145
147
  and GUI application. With pymmcore-plus you don't need to install Java, and you
146
- have direct access to the memory buffers used by the C++ core, but the GUI
147
- side of things is far less mature.
148
+ have direct access to the memory buffers used by the C++ core.
148
149
 
149
150
  ## Quickstart
150
151
 
@@ -0,0 +1,59 @@
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=m6OEbKM90lJ6v5429cbsIultyB86iqXaDN0hSSyj810,14258
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=twgVOJ3yF67ljvcWOtU0HexuLCNpQlqsN9yxIqwqdqI,87569
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=gN_F9iJyEzHCIBVBYUCL6fnRlbBcDbpR8cmkwK5d_1I,24372
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=RsXuYS6ytIRicefRF0h7NiGfDhmimKbpgL9Vrp1p548,12188
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=EFhSUBdnVcwZHRFxcTk346Ha0o9WZyjsQzpk1k0JCwc,11321
53
+ pymmcore_plus/model/_pixel_size_config.py,sha256=eoEQrXqOKaRBcdLtaTX15rIWMF3QJ1fNgTrgXEFfvBs,3483
54
+ pymmcore_plus/model/_property.py,sha256=gJM7SFjLB2HnN0E8HOn4qVlB2wAxmkEFxSJFjKauZEk,3328
55
+ pymmcore_plus-0.11.1.dist-info/METADATA,sha256=b8a-4eD6Cn6UhAzBUibyCjSK23_7A422cK3bcXcxXRI,9271
56
+ pymmcore_plus-0.11.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
57
+ pymmcore_plus-0.11.1.dist-info/entry_points.txt,sha256=NtFyndrQzBpUNJyil-8e5hMGke2utAf7mkGavTLcLOY,51
58
+ pymmcore_plus-0.11.1.dist-info/licenses/LICENSE,sha256=OHJjRpOPKKRc7FEnpehNWdR5LRBdBhUtIFG-ZI0dCEA,1522
59
+ pymmcore_plus-0.11.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.24.2
2
+ Generator: hatchling 1.25.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,244 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from contextlib import suppress
4
- from typing import TYPE_CHECKING, Any, Literal, Sequence, TypedDict, cast
5
-
6
- if TYPE_CHECKING:
7
- from pymmcore_plus import CMMCorePlus
8
-
9
-
10
- class SystemInfoDict(TypedDict):
11
- APIVersionInfo: str
12
- BufferFreeCapacity: int
13
- BufferTotalCapacity: int
14
- CircularBufferMemoryFootprint: int
15
- DeviceAdapterSearchPaths: tuple[str, ...]
16
- PrimaryLogFile: str
17
- RemainingImageCount: int
18
- TimeoutMs: int # rarely needed for metadata
19
- VersionInfo: str
20
- # these were removed in mmcore11 and probably shouldn't be used anyway
21
- # HostName: str
22
- # MACAddresses: tuple[str, ...]
23
- # UserId: str
24
-
25
-
26
- class ImageDict(TypedDict):
27
- BytesPerPixel: int
28
- CurrentPixelSizeConfig: str
29
- Exposure: float
30
- ImageBitDepth: int
31
- ImageBufferSize: int
32
- ImageHeight: int
33
- ImageWidth: int
34
- MagnificationFactor: float
35
- MultiROI: tuple[list[int], list[int], list[int], list[int]] | None
36
- NumberOfCameraChannels: int
37
- NumberOfComponents: int
38
- PixelSizeAffine: tuple[float, float, float, float, float, float]
39
- PixelSizeUm: int
40
- ROI: list[int]
41
-
42
-
43
- class PositionDict(TypedDict):
44
- X: float | None
45
- Y: float | None
46
- Focus: float | None
47
-
48
-
49
- class AutoFocusDict(TypedDict):
50
- CurrentFocusScore: float
51
- LastFocusScore: float
52
- AutoFocusOffset: float | None
53
-
54
-
55
- class PixelSizeConfigDict(TypedDict):
56
- Objective: dict[str, str]
57
- PixelSizeUm: float
58
- PixelSizeAffine: tuple[float, float, float, float, float, float]
59
-
60
-
61
- class DeviceTypeDict(TypedDict):
62
- Type: str
63
- Description: str
64
- Adapter: str
65
-
66
-
67
- class SystemStatusDict(TypedDict):
68
- debugLogEnabled: bool
69
- isBufferOverflowed: bool
70
- isContinuousFocusEnabled: bool
71
- isContinuousFocusLocked: bool
72
- isSequenceRunning: bool
73
- stderrLogEnabled: bool
74
- systemBusy: bool
75
- autoShutter: bool
76
- shutterOpen: bool
77
-
78
-
79
- class StateDict(TypedDict, total=False):
80
- Devices: dict[str, dict[str, str]]
81
- SystemInfo: SystemInfoDict
82
- SystemStatus: SystemStatusDict
83
- ConfigGroups: dict[str, dict[str, Any]]
84
- Image: ImageDict
85
- Position: PositionDict
86
- AutoFocus: AutoFocusDict
87
- PixelSizeConfig: dict[str, str | PixelSizeConfigDict]
88
- DeviceTypes: dict[str, DeviceTypeDict]
89
-
90
-
91
- def core_state(
92
- core: CMMCorePlus,
93
- *,
94
- devices: bool = True,
95
- image: bool = True,
96
- system_info: bool = False,
97
- system_status: bool = False,
98
- config_groups: bool | Sequence[str] = True,
99
- position: bool = False,
100
- autofocus: bool = False,
101
- pixel_size_configs: bool = False,
102
- device_types: bool = False,
103
- cached: bool = True,
104
- error_value: Any = None,
105
- ) -> StateDict:
106
- out: StateDict = {}
107
- if devices:
108
- out["Devices"] = get_device_state(core, error_value)
109
- if system_info:
110
- out["SystemInfo"] = get_system_info(core)
111
- if system_status:
112
- out["SystemStatus"] = get_system_status(core)
113
- if config_groups:
114
- out["ConfigGroups"] = get_config_groups(core, config_groups, cached)
115
- if image:
116
- out["Image"] = get_image_info(core, error_value)
117
- if position:
118
- out["Position"] = get_position(core, error_value)
119
- if autofocus:
120
- out["AutoFocus"] = get_autofocus(core, error_value)
121
- if pixel_size_configs:
122
- out["PixelSizeConfig"] = get_pix_size_config(core)
123
- if device_types:
124
- out["DeviceTypes"] = get_device_types(core)
125
- return out
126
-
127
-
128
- def get_device_state(
129
- core: CMMCorePlus, cached: bool = True, error_value: Any = None
130
- ) -> dict[str, dict[str, Any]]:
131
- # this actually appears to be faster than getSystemStateCache
132
- getProp = core.getPropertyFromCache if cached else core.getProperty
133
- device_state: dict = {}
134
- for dev in core.getLoadedDevices():
135
- dd = device_state.setdefault(dev, {})
136
- for prop in core.getDevicePropertyNames(dev):
137
- try:
138
- val = getProp(dev, prop)
139
- except Exception:
140
- val = error_value
141
- dd[prop] = val
142
- return device_state
143
-
144
-
145
- def get_system_info(core: CMMCorePlus) -> SystemInfoDict:
146
- return { # type: ignore
147
- key: getattr(core, f"get{key}")()
148
- for key in sorted(SystemInfoDict.__annotations__)
149
- }
150
-
151
-
152
- def get_system_status(core: CMMCorePlus) -> SystemStatusDict:
153
- out = {
154
- "autoShutter": core.getAutoShutter(),
155
- "shutterOpen": core.getShutterOpen(),
156
- }
157
- out.update(
158
- {
159
- key: getattr(core, key)()
160
- for key in sorted(SystemStatusDict.__annotations__)
161
- if key not in {"autoShutter", "shutterOpen"}
162
- }
163
- )
164
- return cast("SystemStatusDict", out)
165
-
166
-
167
- def get_config_groups(
168
- core: CMMCorePlus,
169
- config_groups: bool | Sequence[str | Literal["[Channel]"]],
170
- cached: bool = True,
171
- ) -> dict[str, dict[str, Any]]:
172
- if not isinstance(config_groups, (list, tuple, set)):
173
- config_groups = core.getAvailableConfigGroups()
174
-
175
- getState = core.getConfigGroupStateFromCache if cached else core.getConfigGroupState
176
- curGrp = core.getCurrentConfigFromCache if cached else core.getCurrentConfig
177
- cfg_group_dict: dict = {}
178
- for grp in config_groups:
179
- if grp == "[Channel]":
180
- # special case for accessing channel group
181
- grp = core.getChannelGroup()
182
-
183
- grp_dict = cfg_group_dict.setdefault(grp, {})
184
- grp_dict["Current"] = curGrp(grp)
185
-
186
- for dev, prop, val in getState(grp):
187
- grp_dict.setdefault(dev, {})[prop] = val
188
- return cfg_group_dict
189
-
190
-
191
- def get_image_info(core: CMMCorePlus, error_value: Any = None) -> ImageDict:
192
- img_dict = {}
193
- for key in sorted(ImageDict.__annotations__):
194
- try:
195
- val = getattr(core, f"get{key}")()
196
- except Exception:
197
- val = error_value
198
- img_dict[key] = val
199
- return cast("ImageDict", img_dict)
200
-
201
-
202
- def get_position(core: CMMCorePlus, error_value: Any = None) -> PositionDict:
203
- pos: PositionDict = {"X": error_value, "Y": error_value, "Focus": error_value}
204
- with suppress(Exception):
205
- pos["X"] = core.getXPosition()
206
- pos["Y"] = core.getYPosition()
207
- with suppress(Exception):
208
- pos["Focus"] = core.getPosition()
209
- return pos
210
-
211
-
212
- def get_autofocus(core: CMMCorePlus, error_value: Any = None) -> AutoFocusDict:
213
- out: AutoFocusDict = {
214
- "CurrentFocusScore": core.getCurrentFocusScore(),
215
- "LastFocusScore": core.getLastFocusScore(),
216
- "AutoFocusOffset": error_value,
217
- }
218
- with suppress(Exception):
219
- out["AutoFocusOffset"] = core.getAutoFocusOffset()
220
- return out
221
-
222
-
223
- def get_pix_size_config(core: CMMCorePlus) -> dict[str, str | PixelSizeConfigDict]:
224
- # the Current value is a string, all the rest are PixelSizeConfigDict
225
- px: dict = {"Current": core.getCurrentPixelSizeConfig()}
226
- for px_cfg_name in core.getAvailablePixelSizeConfigs():
227
- px_cfg_info: dict = {}
228
- for dev, prop, val in core.getPixelSizeConfigData(px_cfg_name):
229
- px_cfg_info.setdefault(dev, {})[prop] = val
230
- px_cfg_info["PixelSizeUm"] = core.getPixelSizeUmByID(px_cfg_name)
231
- px_cfg_info["PixelSizeAffine"] = core.getPixelSizeAffineByID(px_cfg_name)
232
- px[px_cfg_name] = px_cfg_info
233
- return px
234
-
235
-
236
- def get_device_types(core: CMMCorePlus) -> dict[str, DeviceTypeDict]:
237
- return {
238
- dev_name: {
239
- "Type": core.getDeviceType(dev_name).name,
240
- "Description": core.getDeviceDescription(dev_name),
241
- "Adapter": core.getDeviceName(dev_name),
242
- }
243
- for dev_name in core.getLoadedDevices()
244
- }
@@ -1,56 +0,0 @@
1
- pymmcore_plus/__init__.py,sha256=byZeA2-r2pGztxIZgCDZ__Q2DYddc4aQ2alWg2pgQ5I,1337
2
- pymmcore_plus/_build.py,sha256=_jw1e1PWaIejjeghPTweySdgeohle0jhqVDagYNT3k8,10892
3
- pymmcore_plus/_cli.py,sha256=eHKUCGz6l6X3QBnTXzOkRz6odqjaC1_kJ75uAnzzeP0,13115
4
- pymmcore_plus/_logger.py,sha256=IQl--kuEQqUwV9C4P1sY-7J5IW6V7q45wsi2NbfnAbM,5088
5
- pymmcore_plus/_util.py,sha256=FahG2TkIee4SPGruW8D0twEUzS729J2fbK8Yc78ocL4,17171
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=8YNtX8U4PZlEJjmnxoYWbQPY6Y4jHTnYOMO4i5hdrc8,861
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=bIXsi8ff-silrCbkrtBFZYG7i5SvQCz68kzPEOV9fDs,8726
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=wMPf-Wtu2hVpRDox9450R-6B4r7rdD7KgyETV1sl_X0,86477
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/_state.py,sha256=80kr-_x9Z8MwZG0-mgIE0lR4XUSNOnlmKm-zzoH3BJA,7535
20
- pymmcore_plus/core/events/__init__.py,sha256=8NjFkVdRVRiiLUQ_brGQSlTaK3rqNizdNEX17NEXAis,1106
21
- pymmcore_plus/core/events/_device_signal_view.py,sha256=st_di51xOmKKOM9-yY8ouKlTZqG-7NWorRaoaN1sJ44,1065
22
- pymmcore_plus/core/events/_norm_slot.py,sha256=cp6VeH5h98G7bPWrKzTsHJmzCIbi2D4sv6bSdywQbsk,2937
23
- pymmcore_plus/core/events/_prop_event_mixin.py,sha256=XfoXrMjRRXPHv6XkavBmSuz-6nItpJ8oG60DqK2WBEA,3939
24
- pymmcore_plus/core/events/_protocol.py,sha256=Cf9uGZe_uP8nIa8rsaDIX5RCW5pNQQt2juLL-rriRn4,7448
25
- pymmcore_plus/core/events/_psygnal.py,sha256=owaKlW2zpvocXDbAW4kHovBoVv4Fjfn-S5oUJrVWsD4,1646
26
- pymmcore_plus/core/events/_qsignals.py,sha256=gr-GDiSVLhFhSfaoKrdTz2y3I_2IUg62bYDGuGrB3j0,3018
27
- pymmcore_plus/mda/__init__.py,sha256=MrRYE2rYuIw4dQib4KiRgVbTkjdsE-6tcTjns68Grzk,298
28
- pymmcore_plus/mda/_engine.py,sha256=vHkMyrOAj7glNgdvltINOzFVOmhnJ1dSmp-S-GJapBE,21953
29
- pymmcore_plus/mda/_protocol.py,sha256=p98OkG390Q2Rj05Cl5mza6BUTscPol_cgTxXXMkpNcI,3182
30
- pymmcore_plus/mda/_runner.py,sha256=1U39sfI7g29K7fkrNLqDGyWYSjStIWLymVrp2Kj_HF8,15365
31
- pymmcore_plus/mda/_thread_relay.py,sha256=wjP1tag7nN2Sr0RzaPnYRqHl8XjAQg2MpXOt0ONLcQ8,6112
32
- pymmcore_plus/mda/events/__init__.py,sha256=UZFBlIzTmKqgMw_vVSZSSAN1tkAu8qccYb-aXXBRc3I,1192
33
- pymmcore_plus/mda/events/_protocol.py,sha256=Ve4RbjcdHyDob-GZ2ny4gmw46JhahvI4XbXUwVZ-7zc,1315
34
- pymmcore_plus/mda/events/_psygnal.py,sha256=TdN1mFGpTPXmEs9iwFKSC1svv87PDZkT2JZvl0tEGrQ,640
35
- pymmcore_plus/mda/events/_qsignals.py,sha256=tULQg-e_NX197DxJXaWHn1zLJ-4tzc9QyOAnsobEDtA,554
36
- pymmcore_plus/mda/handlers/_5d_writer_base.py,sha256=9hBW8TH9mLh318QQk4knpCJZuhgKZOPv2X_UVZcDH-c,11515
37
- pymmcore_plus/mda/handlers/__init__.py,sha256=yQFRVDdCyu5t2JilobHGPC8lgCY4htNF5dzctrteSZA,305
38
- pymmcore_plus/mda/handlers/_img_sequence_writer.py,sha256=9zIqwTlW1GmgkpSol1V69ADHwAEt-n8E4DkqAiSk5mM,11493
39
- pymmcore_plus/mda/handlers/_ome_tiff_writer.py,sha256=B4MFJzlY5fzOpFv41aEvBv-rfeU9rasJm4qznCkXsvU,6120
40
- pymmcore_plus/mda/handlers/_ome_zarr_writer.py,sha256=R70bWNcYhZ4lytv_UZiCkuxNHSQUS2yVyCBeCfIB1Ag,12133
41
- pymmcore_plus/mda/handlers/_tensorstore_handler.py,sha256=iQOL61ZizcnJIY6cUSB-VpXHHFYdvANioAGxU--yiZI,14573
42
- pymmcore_plus/mda/handlers/_util.py,sha256=p-8Gg5Q2Jo0zyYdniP9a0NirUOnuKNLWzwjhzcKqskg,1601
43
- pymmcore_plus/model/__init__.py,sha256=zKZkkSpNK4ERu-VMdi9gvRrj1aXAjNaYxlYB5PdYSg0,479
44
- pymmcore_plus/model/_config_file.py,sha256=AwUHlCd6PUCCCDJFPBzanhVp7Cv751k6MHVEaUAdsxw,13335
45
- pymmcore_plus/model/_config_group.py,sha256=zpLimXUSaz2dcqfy2GCI0_MqhjN-A022MOi9QmkiOh4,2517
46
- pymmcore_plus/model/_core_device.py,sha256=afNYGIRFunUPYNYJ_yHJwOjo7HO9FW8qGWTMeiKRmNU,2370
47
- pymmcore_plus/model/_core_link.py,sha256=myE0qa2pEWEinbsIhTN4uB_c-lr9dtUG3npLgsHEI_0,2706
48
- pymmcore_plus/model/_device.py,sha256=cQngFxQ6tufrT9G46oO5iX9wh-44zZraaIFNQCyzMLc,15026
49
- pymmcore_plus/model/_microscope.py,sha256=-soGj918ue_71mrROQ5_7cbjexKp41wPn7im0l2BfaY,9822
50
- pymmcore_plus/model/_pixel_size_config.py,sha256=J4qJmPZsN9dwEkoMtct5Ik-8zEC-v0aKxOBKGFH7kOE,2718
51
- pymmcore_plus/model/_property.py,sha256=gJM7SFjLB2HnN0E8HOn4qVlB2wAxmkEFxSJFjKauZEk,3328
52
- pymmcore_plus-0.10.2.dist-info/METADATA,sha256=qUaNdtH932kT10tVTpK_tsOIu52o9j3TVC-33DzKoNI,9220
53
- pymmcore_plus-0.10.2.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
54
- pymmcore_plus-0.10.2.dist-info/entry_points.txt,sha256=NtFyndrQzBpUNJyil-8e5hMGke2utAf7mkGavTLcLOY,51
55
- pymmcore_plus-0.10.2.dist-info/licenses/LICENSE,sha256=OHJjRpOPKKRc7FEnpehNWdR5LRBdBhUtIFG-ZI0dCEA,1522
56
- pymmcore_plus-0.10.2.dist-info/RECORD,,