pymmcore-plus 0.13.2__tar.gz → 0.13.4__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.
Files changed (95) hide show
  1. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/PKG-INFO +2 -2
  2. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/pyproject.toml +1 -1
  3. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/_mmcore_plus.py +6 -1
  4. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/events/_protocol.py +14 -2
  5. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/events/_psygnal.py +2 -0
  6. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/events/_qsignals.py +2 -0
  7. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/_engine.py +8 -1
  8. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_events.py +18 -11
  9. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_mda.py +6 -0
  10. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/.gitignore +0 -0
  11. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/LICENSE +0 -0
  12. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/README.md +0 -0
  13. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/__init__.py +0 -0
  14. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/_benchmark.py +0 -0
  15. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/_build.py +0 -0
  16. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/_cli.py +0 -0
  17. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/_logger.py +0 -0
  18. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/_pymmcore.py +0 -0
  19. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/_util.py +0 -0
  20. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/__init__.py +0 -0
  21. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/_adapter.py +0 -0
  22. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/_config.py +0 -0
  23. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/_config_group.py +0 -0
  24. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/_constants.py +0 -0
  25. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/_device.py +0 -0
  26. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/_metadata.py +0 -0
  27. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/_property.py +0 -0
  28. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/_sequencing.py +0 -0
  29. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/events/__init__.py +0 -0
  30. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/events/_device_signal_view.py +0 -0
  31. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/events/_norm_slot.py +0 -0
  32. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/core/events/_prop_event_mixin.py +0 -0
  33. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/experimental/__init__.py +0 -0
  34. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/experimental/unicore/__init__.py +0 -0
  35. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/experimental/unicore/_device_manager.py +0 -0
  36. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/experimental/unicore/_proxy.py +0 -0
  37. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/experimental/unicore/_unicore.py +0 -0
  38. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/experimental/unicore/devices/__init__.py +0 -0
  39. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/experimental/unicore/devices/_device.py +0 -0
  40. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/experimental/unicore/devices/_properties.py +0 -0
  41. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/experimental/unicore/devices/_stage.py +0 -0
  42. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/install.py +0 -0
  43. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/__init__.py +0 -0
  44. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/_protocol.py +0 -0
  45. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/_runner.py +0 -0
  46. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/_thread_relay.py +0 -0
  47. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/events/__init__.py +0 -0
  48. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/events/_protocol.py +0 -0
  49. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/events/_psygnal.py +0 -0
  50. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/events/_qsignals.py +0 -0
  51. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/handlers/_5d_writer_base.py +0 -0
  52. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/handlers/__init__.py +0 -0
  53. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/handlers/_img_sequence_writer.py +0 -0
  54. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/handlers/_ome_tiff_writer.py +0 -0
  55. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/handlers/_ome_zarr_writer.py +0 -0
  56. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/handlers/_tensorstore_handler.py +0 -0
  57. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mda/handlers/_util.py +0 -0
  58. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/metadata/__init__.py +0 -0
  59. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/metadata/functions.py +0 -0
  60. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/metadata/schema.py +0 -0
  61. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/metadata/serialize.py +0 -0
  62. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/mocks.py +0 -0
  63. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/model/__init__.py +0 -0
  64. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/model/_config_file.py +0 -0
  65. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/model/_config_group.py +0 -0
  66. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/model/_core_device.py +0 -0
  67. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/model/_core_link.py +0 -0
  68. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/model/_device.py +0 -0
  69. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/model/_microscope.py +0 -0
  70. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/model/_pixel_size_config.py +0 -0
  71. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/model/_property.py +0 -0
  72. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/py.typed +0 -0
  73. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/src/pymmcore_plus/seq_tester.py +0 -0
  74. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/__init__.py +0 -0
  75. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/conftest.py +0 -0
  76. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/io/test_image_sequence_writer.py +0 -0
  77. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/io/test_ome_tiff.py +0 -0
  78. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/io/test_zarr_writers.py +0 -0
  79. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/local_config.cfg +0 -0
  80. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_adapter_class.py +0 -0
  81. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_bench.py +0 -0
  82. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_cli.py +0 -0
  83. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_config_group_class.py +0 -0
  84. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_core.py +0 -0
  85. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_device_class.py +0 -0
  86. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_metadata.py +0 -0
  87. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_misc.py +0 -0
  88. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_model.py +0 -0
  89. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_pixel_config_class.py +0 -0
  90. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_property_class.py +0 -0
  91. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_sequencing.py +0 -0
  92. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_slm_image.py +0 -0
  93. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/test_thread_relay.py +0 -0
  94. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/unicore/test_unicore.py +0 -0
  95. {pymmcore_plus-0.13.2 → pymmcore_plus-0.13.4}/tests/unicore/test_xy_stage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymmcore-plus
3
- Version: 0.13.2
3
+ Version: 0.13.4
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
@@ -33,7 +33,7 @@ Requires-Dist: rich>=10.2.0
33
33
  Requires-Dist: tensorstore; python_version < '3.13'
34
34
  Requires-Dist: typer>=0.4.2
35
35
  Requires-Dist: typing-extensions
36
- Requires-Dist: useq-schema>=0.6.2
36
+ Requires-Dist: useq-schema>=0.7.0
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'
@@ -40,7 +40,7 @@ dependencies = [
40
40
  "psygnal >=0.7",
41
41
  "pymmcore >=10.7.0.71.0",
42
42
  "typing-extensions", # not actually required at runtime
43
- "useq-schema >=0.6.2",
43
+ "useq-schema >=0.7.0",
44
44
  "tensorstore; python_version < '3.13'",
45
45
  # cli requirements included by default for now
46
46
  "typer >=0.4.2",
@@ -1675,6 +1675,7 @@ class CMMCorePlus(pymmcore.CMMCore):
1675
1675
 
1676
1676
  **Why Override?** To emit a `startContinuousSequenceAcquisition` event.
1677
1677
  """
1678
+ self.events.continuousSequenceAcquisitionStarting.emit()
1678
1679
  super().startContinuousSequenceAcquisition(intervalMs)
1679
1680
  self.events.continuousSequenceAcquisitionStarted.emit()
1680
1681
 
@@ -1703,12 +1704,16 @@ class CMMCorePlus(pymmcore.CMMCore):
1703
1704
 
1704
1705
  **Why Override?** To emit a `startSequenceAcquisition` event.
1705
1706
  """
1706
- super().startSequenceAcquisition(*args, **kwargs)
1707
1707
  if len(args) == 3:
1708
1708
  numImages, intervalMs, stopOnOverflow = args
1709
1709
  cameraLabel = super().getCameraDevice()
1710
1710
  else:
1711
1711
  cameraLabel, numImages, intervalMs, stopOnOverflow = args
1712
+
1713
+ self.events.sequenceAcquisitionStarting.emit(
1714
+ cameraLabel, numImages, intervalMs, stopOnOverflow
1715
+ )
1716
+ super().startSequenceAcquisition(*args, **kwargs)
1712
1717
  self.events.sequenceAcquisitionStarted.emit(
1713
1718
  cameraLabel, numImages, intervalMs, stopOnOverflow
1714
1719
  )
@@ -133,14 +133,26 @@ class PCoreSignaler(Protocol):
133
133
  > :sparkles: This signal is unique to `pymmcore-plus`.
134
134
  """
135
135
 
136
+ continuousSequenceAcquisitionStarting: PSignal
137
+ """Emits with no arguments *before* continuous sequence acquisition is started.
138
+
139
+ > :sparkles: This signal is unique to `pymmcore-plus`.
140
+ """
136
141
  continuousSequenceAcquisitionStarted: PSignal
137
- """Emits with no arguments when continuous sequence acquisition is started.
142
+ """Emits with no arguments *after* continuous sequence acquisition has started.
143
+
144
+ > :sparkles: This signal is unique to `pymmcore-plus`.
145
+ """
146
+ sequenceAcquisitionStarting: PSignal
147
+ """Emits `(str, int, float, bool)` *before* sequence acquisition is started.
138
148
 
149
+ (cameraLabel, numImages, intervalMs, stopOnOverflow)
139
150
  > :sparkles: This signal is unique to `pymmcore-plus`.
140
151
  """
141
152
  sequenceAcquisitionStarted: PSignal
142
- """Emits `(str, int, float, bool)` when sequence acquisition is started.
153
+ """Emits `(str, int, float, bool)` *after* sequence acquisition has started.
143
154
 
155
+ (cameraLabel, numImages, intervalMs, stopOnOverflow)
144
156
  > :sparkles: This signal is unique to `pymmcore-plus`.
145
157
  """
146
158
  sequenceAcquisitionStopped: PSignal
@@ -25,7 +25,9 @@ class CMMCoreSignaler(SignalGroup, _DevicePropertyEventMixin):
25
25
  # added for CMMCorePlus
26
26
  imageSnapped = Signal() # whenever snapImage is called
27
27
  mdaEngineRegistered = Signal(MDAEngine, MDAEngine)
28
+ continuousSequenceAcquisitionStarting = Signal()
28
29
  continuousSequenceAcquisitionStarted = Signal()
30
+ sequenceAcquisitionStarting = Signal(str, int, float, bool)
29
31
  sequenceAcquisitionStarted = Signal(str, int, float, bool)
30
32
  sequenceAcquisitionStopped = Signal(str)
31
33
  autoShutterSet = Signal(bool)
@@ -29,8 +29,10 @@ class QCoreSignaler(QObject):
29
29
  imageSnapped = Signal() # on snapImage()
30
30
  mdaEngineRegistered = Signal(object, object) # new engine, old engine
31
31
  # when continuousSequenceAcquisition is started
32
+ continuousSequenceAcquisitionStarting = Signal()
32
33
  continuousSequenceAcquisitionStarted = Signal()
33
34
  # when SequenceAcquisition is started
35
+ sequenceAcquisitionStarting = Signal(str, int, float, bool)
34
36
  sequenceAcquisitionStarted = Signal(str, int, float, bool)
35
37
  # when (Continuous)SequenceAcquisition is stopped
36
38
  sequenceAcquisitionStopped = Signal(str)
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Literal, NamedTuple, cast
7
7
 
8
8
  import numpy as np
9
9
  import useq
10
- from useq import HardwareAutofocus, MDAEvent, MDASequence
10
+ from useq import AcquireImage, HardwareAutofocus, MDAEvent, MDASequence
11
11
 
12
12
  from pymmcore_plus._logger import logger
13
13
  from pymmcore_plus._util import retry
@@ -195,6 +195,13 @@ class MDAEngine(PMDAEngine):
195
195
  )
196
196
  return
197
197
 
198
+ # don't try to execute any other action types. Mostly, this is just
199
+ # CustomAction, which is a user-defined action that the engine doesn't know how
200
+ # to handle. But may include other actions in the future, and this ensures
201
+ # backwards compatibility.
202
+ if not isinstance(action, (AcquireImage, type(None))):
203
+ return
204
+
198
205
  # if the autofocus was engaged at the start of the sequence AND autofocus action
199
206
  # did not fail, re-engage it. NOTE: we need to do that AFTER the runner calls
200
207
  # `setup_event`, so we can't do it inside the exec_event autofocus action above.
@@ -171,32 +171,39 @@ def test_device_property_events(core: CMMCorePlus) -> None:
171
171
 
172
172
 
173
173
  def test_sequence_acquisition_events(core: CMMCorePlus) -> None:
174
- mock1 = Mock()
175
- mock2 = Mock()
174
+ mock1a = Mock()
175
+ mock1b = Mock()
176
+ mock2a = Mock()
177
+ mock2b = Mock()
176
178
  mock3 = Mock()
177
179
 
178
- core.events.continuousSequenceAcquisitionStarted.connect(mock1)
179
- core.events.sequenceAcquisitionStopped.connect(mock2)
180
- core.events.sequenceAcquisitionStarted.connect(mock3)
180
+ core.events.continuousSequenceAcquisitionStarting.connect(mock1a)
181
+ core.events.continuousSequenceAcquisitionStarted.connect(mock1b)
182
+ core.events.sequenceAcquisitionStarting.connect(mock2a)
183
+ core.events.sequenceAcquisitionStarted.connect(mock2b)
184
+ core.events.sequenceAcquisitionStopped.connect(mock3)
181
185
 
182
186
  core.startContinuousSequenceAcquisition()
183
- mock1.assert_called_once()
187
+ mock1a.assert_called_once()
188
+ mock1b.assert_called_once()
184
189
 
185
190
  core.stopSequenceAcquisition()
186
- mock2.assert_any_call(core.getCameraDevice())
191
+ mock3.assert_any_call(core.getCameraDevice())
187
192
 
188
193
  # without camera label
189
194
  core.startSequenceAcquisition(5, 100.0, True)
190
- mock3.assert_any_call(core.getCameraDevice(), 5, 100.0, True)
195
+ mock2a.assert_any_call(core.getCameraDevice(), 5, 100.0, True)
196
+ mock2b.assert_any_call(core.getCameraDevice(), 5, 100.0, True)
191
197
  core.stopSequenceAcquisition()
192
- mock2.assert_any_call(core.getCameraDevice())
198
+ mock3.assert_any_call(core.getCameraDevice())
193
199
 
194
200
  # with camera label
195
201
  cam = core.getCameraDevice()
196
202
  core.startSequenceAcquisition(cam, 5, 100.0, True)
197
- mock3.assert_any_call(cam, 5, 100.0, True)
203
+ mock2a.assert_any_call(cam, 5, 100.0, True)
204
+ mock2b.assert_any_call(cam, 5, 100.0, True)
198
205
  core.stopSequenceAcquisition(cam)
199
- mock2.assert_any_call(cam)
206
+ mock3.assert_any_call(cam)
200
207
 
201
208
 
202
209
  def test_shutter_device_events(core: CMMCorePlus) -> None:
@@ -490,3 +490,9 @@ def test_get_handlers(core: CMMCorePlus) -> None:
490
490
  # but they should have been available during start and finish events
491
491
  assert on_start_names == ["TensorStoreHandler"]
492
492
  assert on_finish_names == ["TensorStoreHandler"]
493
+
494
+
495
+ def test_custom_action(core: CMMCorePlus) -> None:
496
+ """Make sure we can handle custom actions gracefully"""
497
+
498
+ core.mda.run([MDAEvent(action=useq.CustomAction())])
File without changes
File without changes