pymmcore-plus 0.16.0__tar.gz → 0.17.1__tar.gz
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-0.16.0 → pymmcore_plus-0.17.1}/PKG-INFO +5 -3
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/pyproject.toml +7 -4
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/_ipy_completion.py +1 -1
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/_logger.py +2 -2
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/_device.py +37 -6
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/_mmcore_plus.py +4 -15
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/_property.py +1 -1
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/_sequencing.py +2 -0
- pymmcore_plus-0.17.1/src/pymmcore_plus/experimental/simulate/__init__.py +88 -0
- pymmcore_plus-0.17.1/src/pymmcore_plus/experimental/simulate/_objects.py +670 -0
- pymmcore_plus-0.17.1/src/pymmcore_plus/experimental/simulate/_render.py +510 -0
- pymmcore_plus-0.17.1/src/pymmcore_plus/experimental/simulate/_sample.py +156 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/__init__.py +2 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/_device_manager.py +26 -0
- pymmcore_plus-0.17.1/src/pymmcore_plus/experimental/unicore/core/_config.py +706 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/core/_unicore.py +832 -20
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/devices/_device_base.py +13 -0
- pymmcore_plus-0.17.1/src/pymmcore_plus/experimental/unicore/devices/_hub.py +50 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/devices/_stage.py +46 -1
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/devices/_state.py +6 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/handlers/_5d_writer_base.py +16 -5
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/handlers/_tensorstore_handler.py +7 -1
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/metadata/_ome.py +75 -21
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/metadata/functions.py +2 -1
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/00_unicore/test_camera.py +16 -1
- pymmcore_plus-0.17.1/tests/00_unicore/test_pydevice_config.py +249 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/00_unicore/test_slm.py +1 -1
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/00_unicore/test_state.py +35 -0
- pymmcore_plus-0.17.1/tests/00_unicore/test_unicore.py +1190 -0
- pymmcore_plus-0.17.1/tests/00_unicore/test_z_stage.py +86 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_config_group_class.py +1 -1
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_core.py +9 -2
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_device_class.py +98 -2
- pymmcore_plus-0.17.1/tests/test_metadata_to_ome.py +354 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_sequencing.py +18 -0
- pymmcore_plus-0.17.1/tests/test_simulate.py +552 -0
- pymmcore_plus-0.16.0/tests/00_unicore/test_unicore.py +0 -291
- pymmcore_plus-0.16.0/tests/test_metadata_to_ome.py +0 -169
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/.gitignore +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/LICENSE +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/README.md +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/_accumulator.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/_benchmark.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/_build.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/_cli.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/_discovery.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/_pymmcore.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/_util.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/_adapter.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/_config.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/_config_group.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/_constants.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/_metadata.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/events/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/events/_deprecated.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/events/_device_signal_view.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/events/_norm_slot.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/events/_prop_event_mixin.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/events/_protocol.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/events/_psygnal.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/core/events/_qsignals.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/_proxy.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/core/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/core/_sequence_buffer.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/devices/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/devices/_camera.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/devices/_generic_device.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/devices/_properties.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/devices/_shutter.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/experimental/unicore/devices/_slm.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/install.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/_engine.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/_protocol.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/_runner.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/_thread_relay.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/events/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/events/_protocol.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/events/_psygnal.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/events/_qsignals.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/handlers/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/handlers/_img_sequence_writer.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/handlers/_ome_tiff_writer.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/handlers/_ome_zarr_writer.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mda/handlers/_util.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/metadata/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/metadata/schema.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/metadata/serialize.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/mocks.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/model/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/model/_config_file.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/model/_config_group.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/model/_core_device.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/model/_core_link.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/model/_device.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/model/_microscope.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/model/_pixel_size_config.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/model/_property.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/py.typed +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/src/pymmcore_plus/seq_tester.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/00_unicore/conftest.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/00_unicore/test_sequence_buffer.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/00_unicore/test_shutter.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/00_unicore/test_xy_stage.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/__init__.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/conftest.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/io/test_image_sequence_writer.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/io/test_ome_tiff.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/io/test_zarr_writers.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/local_config.cfg +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_accumulators.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_adapter_class.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_bench.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_cli.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_core_references.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_events.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_install.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_ipy_completions.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_mda.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_metadata.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_misc.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_model.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_pixel_config_class.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_property_class.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_slm_image.py +0 -0
- {pymmcore_plus-0.16.0 → pymmcore_plus-0.17.1}/tests/test_thread_relay.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pymmcore-plus
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.17.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
|
|
@@ -35,12 +35,12 @@ Requires-Dist: pymmcore>=11.10.0.74.0
|
|
|
35
35
|
Requires-Dist: rich>=10.2.0
|
|
36
36
|
Requires-Dist: tensorstore!=0.1.72,>=0.1.67
|
|
37
37
|
Requires-Dist: tensorstore!=0.1.72,>=0.1.71; python_version >= '3.13'
|
|
38
|
-
Requires-Dist: typer>=0.
|
|
38
|
+
Requires-Dist: typer>=0.13.0
|
|
39
39
|
Requires-Dist: typing-extensions>=4
|
|
40
40
|
Requires-Dist: useq-schema>=0.7.2
|
|
41
41
|
Provides-Extra: cli
|
|
42
42
|
Requires-Dist: rich>=10.2.0; extra == 'cli'
|
|
43
|
-
Requires-Dist: typer>=0.
|
|
43
|
+
Requires-Dist: typer>=0.13.0; extra == 'cli'
|
|
44
44
|
Provides-Extra: io
|
|
45
45
|
Requires-Dist: tifffile>=2021.6.14; extra == 'io'
|
|
46
46
|
Requires-Dist: zarr<3,>=2.15; extra == 'io'
|
|
@@ -52,6 +52,8 @@ Provides-Extra: pyside2
|
|
|
52
52
|
Requires-Dist: pyside2>=5.15.2.1; extra == 'pyside2'
|
|
53
53
|
Provides-Extra: pyside6
|
|
54
54
|
Requires-Dist: pyside6==6.7.3; extra == 'pyside6'
|
|
55
|
+
Provides-Extra: simulate
|
|
56
|
+
Requires-Dist: pillow>=11.0; extra == 'simulate'
|
|
55
57
|
Description-Content-Type: text/markdown
|
|
56
58
|
|
|
57
59
|
# pymmcore-plus
|
|
@@ -46,7 +46,7 @@ dependencies = [
|
|
|
46
46
|
"tensorstore >=0.1.71,!=0.1.72; python_version >= '3.13'",
|
|
47
47
|
"tensorstore >=0.1.67,!=0.1.72",
|
|
48
48
|
# cli requirements included by default for now
|
|
49
|
-
"typer >=0.
|
|
49
|
+
"typer >=0.13.0",
|
|
50
50
|
"rich >=10.2.0",
|
|
51
51
|
"ome-types >=0.6.0",
|
|
52
52
|
]
|
|
@@ -54,8 +54,9 @@ dependencies = [
|
|
|
54
54
|
# extras
|
|
55
55
|
# https://peps.python.org/pep-0621/#dependencies-optional-dependencies
|
|
56
56
|
[project.optional-dependencies]
|
|
57
|
-
cli = ["typer >=0.
|
|
57
|
+
cli = ["typer >=0.13.0", "rich >=10.2.0"]
|
|
58
58
|
io = ["tifffile >=2021.6.14", "zarr >=2.15,<3"]
|
|
59
|
+
simulate = ["pillow >=11.0"]
|
|
59
60
|
PySide2 = ["PySide2 >=5.15.2.1"]
|
|
60
61
|
PySide6 = ["PySide6 ==6.7.3"]
|
|
61
62
|
PyQt5 = ["PyQt5 >=5.15.4"]
|
|
@@ -72,7 +73,7 @@ docs = [
|
|
|
72
73
|
"mkdocs-typer ==0.0.3",
|
|
73
74
|
]
|
|
74
75
|
test = [
|
|
75
|
-
"pymmcore-plus[io]",
|
|
76
|
+
"pymmcore-plus[io,simulate]",
|
|
76
77
|
"msgspec >= 0.19",
|
|
77
78
|
"msgpack >=1",
|
|
78
79
|
"pytest-cov >=7",
|
|
@@ -95,6 +96,8 @@ dev = [
|
|
|
95
96
|
"pre-commit>=4.1.0",
|
|
96
97
|
"ruff>=0.9.4",
|
|
97
98
|
"pydantic >2.7.4; python_version >= '3.13'",
|
|
99
|
+
"opencv-python>=4.11.0.86",
|
|
100
|
+
"pytest-xdist>=3.8.0",
|
|
98
101
|
]
|
|
99
102
|
|
|
100
103
|
[tool.uv.sources]
|
|
@@ -229,4 +232,4 @@ ignore = [
|
|
|
229
232
|
]
|
|
230
233
|
|
|
231
234
|
[tool.typos.default]
|
|
232
|
-
extend-ignore-identifiers-re = ["(?i)nd2?.*", "(?i)ome", "anager", "ba"]
|
|
235
|
+
extend-ignore-identifiers-re = ["(?i)nd2?.*", "(?i)ome", "anager", "ba", "(?:FOVs?)"]
|
|
@@ -291,7 +291,7 @@ LABEL_COMPLETERS: dict[tuple[str, int], tuple[int, CoreLabelCompleter]] = {
|
|
|
291
291
|
# fmt: on
|
|
292
292
|
|
|
293
293
|
|
|
294
|
-
@context_matcher() # type: ignore[
|
|
294
|
+
@context_matcher() # type: ignore[untyped-decorator]
|
|
295
295
|
def cmmcoreplus_matcher(ctx: CompletionContext) -> SimpleMatcherResult:
|
|
296
296
|
"""
|
|
297
297
|
Offer string completions for CMMCorePlus calls such as.
|
|
@@ -54,7 +54,7 @@ class CustomFormatter(logging.Formatter):
|
|
|
54
54
|
return formatter.format(record)
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
_FILE_FORMATTER = logging.Formatter(
|
|
58
58
|
"%(asctime)s.%(msecs)03d tid0x%(thread)x [%(levelname)s,%(name)s] %(message)s",
|
|
59
59
|
datefmt="%Y-%m-%dT%H:%M:%S",
|
|
60
60
|
)
|
|
@@ -141,7 +141,7 @@ def configure_logging(
|
|
|
141
141
|
log_file, maxBytes=file_rotation * 1_000_000, backupCount=file_retention
|
|
142
142
|
)
|
|
143
143
|
file_handler.setLevel(file_level)
|
|
144
|
-
file_handler.setFormatter(
|
|
144
|
+
file_handler.setFormatter(_FILE_FORMATTER)
|
|
145
145
|
logger.addHandler(file_handler)
|
|
146
146
|
|
|
147
147
|
|
|
@@ -35,6 +35,12 @@ class Device:
|
|
|
35
35
|
Device label assigned to this device.
|
|
36
36
|
mmcore : CMMCorePlus
|
|
37
37
|
CMMCorePlus instance that owns this device.
|
|
38
|
+
device_type : DeviceType or Device subclass, optional
|
|
39
|
+
The type of device to create. If not specified, the type will be inferred
|
|
40
|
+
from the core if the device is already loaded. If the device is not loaded,
|
|
41
|
+
an error will be raised. This parameter is mainly intended for usage when
|
|
42
|
+
calling from `CMMCorePlus.getDeviceObject()`. Otherwise, prefer using
|
|
43
|
+
`[SpecificDeviceSubclass].create()`.
|
|
38
44
|
|
|
39
45
|
Examples
|
|
40
46
|
--------
|
|
@@ -57,14 +63,39 @@ class Device:
|
|
|
57
63
|
propertyChanged: PSignalInstance
|
|
58
64
|
|
|
59
65
|
@classmethod
|
|
60
|
-
def create(
|
|
61
|
-
|
|
66
|
+
def create(
|
|
67
|
+
cls,
|
|
68
|
+
device_label: str,
|
|
69
|
+
mmcore: CMMCorePlus,
|
|
70
|
+
device_type: type[Device] | DeviceType = DeviceType.Any,
|
|
71
|
+
) -> Self:
|
|
72
|
+
if device_type in {DeviceType.Any, DeviceType.Unknown}:
|
|
73
|
+
try:
|
|
74
|
+
sub_cls = cls.get_subclass(device_label, mmcore)
|
|
75
|
+
except RuntimeError as e:
|
|
76
|
+
raise RuntimeError(
|
|
77
|
+
f"Could not determine device type for {device_label}. "
|
|
78
|
+
"If you are preloading a device object, "
|
|
79
|
+
"please specify `device_type` as a `pymmcore_plus.DeviceType`."
|
|
80
|
+
) from e
|
|
81
|
+
else:
|
|
82
|
+
if isinstance(device_type, type) and issubclass(device_type, Device):
|
|
83
|
+
sub_cls = device_type
|
|
84
|
+
elif isinstance(device_type, DeviceType):
|
|
85
|
+
sub_cls = _TYPE_MAP[device_type]
|
|
86
|
+
else:
|
|
87
|
+
raise TypeError(
|
|
88
|
+
f"Invalid device_type: {device_type!r}. Must be a "
|
|
89
|
+
"pymmcore_plus `DeviceType` or `Device` subclass."
|
|
90
|
+
)
|
|
91
|
+
|
|
62
92
|
# make sure it's an error to call this class method on a subclass with
|
|
63
93
|
# a non-matching type
|
|
64
|
-
if issubclass(sub_cls, cls):
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
94
|
+
if not issubclass(sub_cls, cls):
|
|
95
|
+
dev_type = mmcore.getDeviceType(device_label).name
|
|
96
|
+
raise TypeError(f"Cannot cast {dev_type} {device_label!r} to {cls}")
|
|
97
|
+
|
|
98
|
+
return sub_cls(device_label, mmcore)
|
|
68
99
|
|
|
69
100
|
@classmethod
|
|
70
101
|
def get_subclass(cls, device_label: str, mmcore: CMMCorePlus) -> type[Device]:
|
|
@@ -1268,18 +1268,7 @@ class CMMCorePlus(pymmcore.CMMCore):
|
|
|
1268
1268
|
}
|
|
1269
1269
|
}
|
|
1270
1270
|
"""
|
|
1271
|
-
|
|
1272
|
-
if (isinstance(device_type, type) and not isinstance(dev, device_type)) or (
|
|
1273
|
-
isinstance(device_type, DeviceType)
|
|
1274
|
-
and device_type not in {DeviceType.Any, DeviceType.Unknown}
|
|
1275
|
-
and dev.type() != device_type
|
|
1276
|
-
):
|
|
1277
|
-
raise TypeError(
|
|
1278
|
-
f"{device_type!r} requested but device with label "
|
|
1279
|
-
f"{device_label!r} is a {dev.type()}."
|
|
1280
|
-
)
|
|
1281
|
-
|
|
1282
|
-
return dev
|
|
1271
|
+
return _device.Device.create(device_label, mmcore=self, device_type=device_type)
|
|
1283
1272
|
|
|
1284
1273
|
def getConfigGroupObject(
|
|
1285
1274
|
self, group_name: str, allow_missing: bool = False
|
|
@@ -2091,13 +2080,13 @@ class CMMCorePlus(pymmcore.CMMCore):
|
|
|
2091
2080
|
super().deleteConfig(*args)
|
|
2092
2081
|
self.events.configDeleted.emit(groupName, configName)
|
|
2093
2082
|
|
|
2094
|
-
def deleteConfigGroup(self,
|
|
2083
|
+
def deleteConfigGroup(self, groupName: str) -> None:
|
|
2095
2084
|
"""Deletes an entire configuration `group`.
|
|
2096
2085
|
|
|
2097
2086
|
**Why Override?** To emit a `configGroupDeleted` event.
|
|
2098
2087
|
"""
|
|
2099
|
-
super().deleteConfigGroup(
|
|
2100
|
-
self.events.configGroupDeleted.emit(
|
|
2088
|
+
super().deleteConfigGroup(groupName)
|
|
2089
|
+
self.events.configGroupDeleted.emit(groupName)
|
|
2101
2090
|
|
|
2102
2091
|
@overload
|
|
2103
2092
|
def defineConfig(self, groupName: str, configName: str) -> None: ...
|
|
@@ -149,7 +149,7 @@ class DeviceProperty:
|
|
|
149
149
|
return self.core.getDeviceType(self.device)
|
|
150
150
|
|
|
151
151
|
def allowedValues(self) -> tuple[str, ...]:
|
|
152
|
-
"""Return allowed values for this property, if
|
|
152
|
+
"""Return allowed values for this property, if constrained."""
|
|
153
153
|
# https://github.com/micro-manager/mmCoreAndDevices/issues/172
|
|
154
154
|
allowed = self.core.getAllowedPropertyValues(self.device, self.name)
|
|
155
155
|
if not allowed and self.deviceType() is DeviceType.StateDevice:
|
|
@@ -348,6 +348,8 @@ class EventCombiner:
|
|
|
348
348
|
z_pos=first_event.z_pos,
|
|
349
349
|
exposure=first_event.exposure,
|
|
350
350
|
channel=first_event.channel,
|
|
351
|
+
min_start_time=first_event.min_start_time,
|
|
352
|
+
reset_event_timer=first_event.reset_event_timer,
|
|
351
353
|
)
|
|
352
354
|
|
|
353
355
|
# -------------- helper methods to query props & max lengths ----------------
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Simulated microscope sample for testing and development.
|
|
2
|
+
|
|
3
|
+
This module provides tools for creating virtual microscope samples that
|
|
4
|
+
integrate with CMMCorePlus. When a sample is installed on a core, image
|
|
5
|
+
acquisition returns rendered images based on the sample objects and
|
|
6
|
+
current microscope state (stage position, exposure, pixel size, etc.).
|
|
7
|
+
|
|
8
|
+
Examples
|
|
9
|
+
--------
|
|
10
|
+
Create a sample with some objects and use it with a core:
|
|
11
|
+
|
|
12
|
+
>>> from pymmcore_plus import CMMCorePlus
|
|
13
|
+
>>> from pymmcore_plus.experimental.simulate import (
|
|
14
|
+
... Sample,
|
|
15
|
+
... Point,
|
|
16
|
+
... Line,
|
|
17
|
+
... Rectangle,
|
|
18
|
+
... RenderConfig,
|
|
19
|
+
... )
|
|
20
|
+
>>>
|
|
21
|
+
>>> # Create core and load config
|
|
22
|
+
>>> core = CMMCorePlus.instance()
|
|
23
|
+
>>> core.loadSystemConfiguration()
|
|
24
|
+
>>>
|
|
25
|
+
>>> # Define sample objects (coordinates in microns)
|
|
26
|
+
>>> sample = Sample(
|
|
27
|
+
... [
|
|
28
|
+
... Point(0, 0, intensity=200, radius=5),
|
|
29
|
+
... Point(50, 50, intensity=150, radius=3),
|
|
30
|
+
... Line((0, 0), (100, 100), intensity=100),
|
|
31
|
+
... Rectangle((20, 20), width=30, height=20, intensity=180, fill=True),
|
|
32
|
+
... ]
|
|
33
|
+
... )
|
|
34
|
+
>>>
|
|
35
|
+
>>> # Use as context manager
|
|
36
|
+
>>> with sample.patch(core):
|
|
37
|
+
... core.snapImage()
|
|
38
|
+
... img = core.getImage() # Returns rendered simulation
|
|
39
|
+
... print(img.shape, img.dtype)
|
|
40
|
+
|
|
41
|
+
Custom render configuration:
|
|
42
|
+
|
|
43
|
+
>>> config = RenderConfig(
|
|
44
|
+
... noise_std=5.0, # More noise
|
|
45
|
+
... defocus_scale=0.2, # More blur with Z
|
|
46
|
+
... shot_noise=False, # Disable shot noise
|
|
47
|
+
... bit_depth=16, # 16-bit output
|
|
48
|
+
... )
|
|
49
|
+
>>> sample = Sample([Point(0, 0)], config=config)
|
|
50
|
+
|
|
51
|
+
Manual install/uninstall:
|
|
52
|
+
|
|
53
|
+
>>> sample.install(core)
|
|
54
|
+
>>> # ... do stuff ...
|
|
55
|
+
>>> sample.uninstall()
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
from ._objects import (
|
|
59
|
+
Arc,
|
|
60
|
+
Bitmap,
|
|
61
|
+
Bounds,
|
|
62
|
+
Ellipse,
|
|
63
|
+
Line,
|
|
64
|
+
Point,
|
|
65
|
+
Polygon,
|
|
66
|
+
Rectangle,
|
|
67
|
+
RegularPolygon,
|
|
68
|
+
SampleObject,
|
|
69
|
+
rects_intersect,
|
|
70
|
+
)
|
|
71
|
+
from ._render import RenderConfig
|
|
72
|
+
from ._sample import Sample
|
|
73
|
+
|
|
74
|
+
__all__ = [
|
|
75
|
+
"Arc",
|
|
76
|
+
"Bitmap",
|
|
77
|
+
"Bounds",
|
|
78
|
+
"Ellipse",
|
|
79
|
+
"Line",
|
|
80
|
+
"Point",
|
|
81
|
+
"Polygon",
|
|
82
|
+
"Rectangle",
|
|
83
|
+
"RegularPolygon",
|
|
84
|
+
"RenderConfig",
|
|
85
|
+
"Sample",
|
|
86
|
+
"SampleObject",
|
|
87
|
+
"rects_intersect",
|
|
88
|
+
]
|