pymmcore-plus 0.11.0__tar.gz → 0.12.0__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 (80) hide show
  1. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/PKG-INFO +5 -6
  2. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/pyproject.toml +6 -7
  3. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/_build.py +4 -1
  4. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/_cli.py +7 -7
  5. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/_logger.py +4 -1
  6. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/_util.py +2 -1
  7. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/_config.py +5 -3
  8. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/_config_group.py +2 -1
  9. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/_metadata.py +2 -2
  10. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/_mmcore_plus.py +4 -6
  11. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/_property.py +3 -1
  12. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/_sequencing.py +8 -6
  13. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/events/__init__.py +3 -3
  14. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/events/_device_signal_view.py +8 -6
  15. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/events/_norm_slot.py +2 -4
  16. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/events/_prop_event_mixin.py +7 -4
  17. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/events/_protocol.py +5 -2
  18. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/install.py +4 -2
  19. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/_engine.py +5 -7
  20. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/_protocol.py +1 -1
  21. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/_runner.py +29 -21
  22. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/_thread_relay.py +5 -3
  23. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/handlers/_5d_writer_base.py +3 -1
  24. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/handlers/_img_sequence_writer.py +2 -1
  25. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/handlers/_ome_zarr_writer.py +6 -6
  26. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/handlers/_tensorstore_handler.py +3 -2
  27. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/handlers/_util.py +1 -1
  28. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/metadata/functions.py +2 -2
  29. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/metadata/schema.py +23 -23
  30. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/metadata/serialize.py +5 -1
  31. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/model/_config_file.py +2 -1
  32. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/model/_config_group.py +2 -1
  33. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/model/_core_device.py +3 -1
  34. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/model/_core_link.py +2 -1
  35. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/model/_device.py +2 -1
  36. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/model/_microscope.py +4 -2
  37. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/model/_pixel_size_config.py +3 -2
  38. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/model/_property.py +2 -1
  39. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/conftest.py +3 -1
  40. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/io/test_image_sequence_writer.py +1 -0
  41. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/io/test_ome_tiff.py +1 -0
  42. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/io/test_zarr_writers.py +9 -0
  43. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_bench.py +1 -0
  44. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_cli.py +4 -2
  45. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_config_group_class.py +1 -0
  46. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_core.py +3 -2
  47. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_device_class.py +1 -0
  48. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_events.py +1 -0
  49. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_mda.py +23 -4
  50. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_metadata.py +5 -4
  51. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_misc.py +1 -0
  52. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_model.py +1 -0
  53. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_property_class.py +1 -0
  54. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_sequencing.py +1 -0
  55. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_thread_relay.py +1 -0
  56. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/.gitignore +0 -0
  57. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/LICENSE +0 -0
  58. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/README.md +0 -0
  59. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/__init__.py +0 -0
  60. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/__init__.py +0 -0
  61. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/_adapter.py +0 -0
  62. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/_constants.py +0 -0
  63. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/_device.py +0 -0
  64. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/events/_psygnal.py +0 -0
  65. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/core/events/_qsignals.py +0 -0
  66. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/__init__.py +0 -0
  67. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/events/__init__.py +0 -0
  68. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/events/_protocol.py +0 -0
  69. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/events/_psygnal.py +0 -0
  70. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/events/_qsignals.py +0 -0
  71. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/handlers/__init__.py +0 -0
  72. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/mda/handlers/_ome_tiff_writer.py +0 -0
  73. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/metadata/__init__.py +0 -0
  74. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/model/__init__.py +0 -0
  75. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/py.typed +0 -0
  76. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/src/pymmcore_plus/seq_tester.py +0 -0
  77. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/__init__.py +0 -0
  78. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/local_config.cfg +0 -0
  79. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_adapter_class.py +0 -0
  80. {pymmcore_plus-0.11.0 → pymmcore_plus-0.12.0}/tests/test_pixel_config_class.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pymmcore-plus
3
- Version: 0.11.0
3
+ Version: 0.12.0
4
4
  Summary: pymmcore superset providing improved APIs, event handling, and a pure python acquisition engine
5
5
  Project-URL: Source, https://github.com/pymmcore-plus/pymmcore-plus
6
6
  Project-URL: Tracker, https://github.com/pymmcore-plus/pymmcore-plus/issues
@@ -16,7 +16,6 @@ Classifier: License :: OSI Approved :: BSD License
16
16
  Classifier: Operating System :: OS Independent
17
17
  Classifier: Programming Language :: Python
18
18
  Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.8
20
19
  Classifier: Programming Language :: Python :: 3.9
21
20
  Classifier: Programming Language :: Python :: 3.10
22
21
  Classifier: Programming Language :: Python :: 3.11
@@ -24,7 +23,7 @@ Classifier: Programming Language :: Python :: 3.12
24
23
  Classifier: Topic :: System :: Hardware
25
24
  Classifier: Topic :: System :: Hardware :: Hardware Drivers
26
25
  Classifier: Topic :: Utilities
27
- Requires-Python: >=3.8
26
+ Requires-Python: >=3.9
28
27
  Requires-Dist: numpy>=1.17.3
29
28
  Requires-Dist: platformdirs>=3.0.0
30
29
  Requires-Dist: psygnal>=0.7
@@ -33,7 +32,7 @@ Requires-Dist: rich>=10.2.0
33
32
  Requires-Dist: tensorstore
34
33
  Requires-Dist: typer>=0.4.2
35
34
  Requires-Dist: typing-extensions
36
- Requires-Dist: useq-schema>=0.4.7
35
+ Requires-Dist: useq-schema>=0.5.0
37
36
  Requires-Dist: wrapt>=1.14
38
37
  Provides-Extra: cli
39
38
  Requires-Dist: rich>=10.2.0; extra == 'cli'
@@ -53,7 +52,7 @@ Requires-Dist: mkdocstrings-python==1.1.2; extra == 'docs'
53
52
  Requires-Dist: mkdocstrings==0.22.0; extra == 'docs'
54
53
  Provides-Extra: io
55
54
  Requires-Dist: tifffile>=2021.6.14; extra == 'io'
56
- Requires-Dist: zarr>=2.2; extra == 'io'
55
+ Requires-Dist: zarr<3,>=2.2; extra == 'io'
57
56
  Provides-Extra: test
58
57
  Requires-Dist: msgpack; extra == 'test'
59
58
  Requires-Dist: msgspec; extra == 'test'
@@ -65,7 +64,7 @@ Requires-Dist: rich; extra == 'test'
65
64
  Requires-Dist: tifffile>=2021.6.14; extra == 'test'
66
65
  Requires-Dist: typer>=0.4.2; extra == 'test'
67
66
  Requires-Dist: xarray; extra == 'test'
68
- Requires-Dist: zarr>=2.2; extra == 'test'
67
+ Requires-Dist: zarr<3,>=2.2; extra == 'test'
69
68
  Description-Content-Type: text/markdown
70
69
 
71
70
  # pymmcore-plus
@@ -9,7 +9,7 @@ name = "pymmcore-plus"
9
9
  description = "pymmcore superset providing improved APIs, event handling, and a pure python acquisition engine"
10
10
  keywords = ["microscope", "micro-manager", "smart-microscopy"]
11
11
  readme = "README.md"
12
- requires-python = ">=3.8"
12
+ requires-python = ">=3.9"
13
13
  license = { text = "BSD 3-Clause License" }
14
14
  authors = [
15
15
  { name = "Talley Lambert", email = "talley.lambert@gmail.com" },
@@ -24,7 +24,6 @@ classifiers = [
24
24
  "Operating System :: OS Independent",
25
25
  "Programming Language :: Python",
26
26
  "Programming Language :: Python :: 3",
27
- "Programming Language :: Python :: 3.8",
28
27
  "Programming Language :: Python :: 3.9",
29
28
  "Programming Language :: Python :: 3.10",
30
29
  "Programming Language :: Python :: 3.11",
@@ -40,7 +39,7 @@ dependencies = [
40
39
  "psygnal >=0.7",
41
40
  "pymmcore >=10.7.0.71.0",
42
41
  "typing-extensions", # not actually required at runtime
43
- "useq-schema >=0.4.7",
42
+ "useq-schema >=0.5.0",
44
43
  "wrapt >=1.14",
45
44
  "tensorstore",
46
45
  # cli requirements included by default for now
@@ -52,7 +51,7 @@ dependencies = [
52
51
  # https://peps.python.org/pep-0621/#dependencies-optional-dependencies
53
52
  [project.optional-dependencies]
54
53
  cli = ["typer >=0.4.2", "rich >=10.2.0"]
55
- io = ["tifffile >=2021.6.14", "zarr >=2.2"]
54
+ io = ["tifffile >=2021.6.14", "zarr >=2.2,<3"]
56
55
  test = [
57
56
  "msgspec",
58
57
  "msgpack",
@@ -63,7 +62,7 @@ test = [
63
62
  "rich",
64
63
  "typer >=0.4.2",
65
64
  "tifffile >=2021.6.14",
66
- "zarr >=2.2",
65
+ "zarr >=2.2,<3",
67
66
  "xarray",
68
67
  ]
69
68
  dev = ["ipython", "mypy", "pdbpp", "pre-commit", "ruff", "tensorstore-stubs"]
@@ -72,7 +71,7 @@ docs = [
72
71
  "mkdocs-material",
73
72
  "mkdocstrings ==0.22.0",
74
73
  "mkdocstrings-python ==1.1.2",
75
- "mkdocs-typer ==0.0.3"
74
+ "mkdocs-typer ==0.0.3",
76
75
  # "griffe @ git+https://github.com/tlambert03/griffe@recursion"
77
76
  ]
78
77
 
@@ -102,7 +101,7 @@ sources = ["src"]
102
101
  # https://beta.ruff.rs/docs/rules/
103
102
  [tool.ruff]
104
103
  line-length = 88
105
- target-version = "py38"
104
+ target-version = "py39"
106
105
 
107
106
  [tool.ruff.lint]
108
107
  pydocstyle = { convention = "numpy" }
@@ -11,12 +11,15 @@ import subprocess
11
11
  import tempfile
12
12
  from contextlib import contextmanager
13
13
  from pathlib import Path
14
- from typing import Iterator, Sequence
14
+ from typing import TYPE_CHECKING
15
15
  from urllib.request import Request, urlopen
16
16
 
17
17
  from rich import print
18
18
  from rich.prompt import Prompt
19
19
 
20
+ if TYPE_CHECKING:
21
+ from collections.abc import Iterator, Sequence
22
+
20
23
  MM_REPO = "micro-manager/micro-manager"
21
24
  MMCORE_AND_DEV = "micro-manager/mmCoreAndDevices"
22
25
  MM_REPO_URL = f"https://github.com/{MM_REPO}.git"
@@ -6,7 +6,7 @@ import sys
6
6
  import time
7
7
  from contextlib import suppress
8
8
  from pathlib import Path
9
- from typing import List, Optional, Union, cast
9
+ from typing import Optional, Union, cast
10
10
 
11
11
  try:
12
12
  import typer
@@ -31,7 +31,7 @@ def _show_version_and_exit(value: bool) -> None:
31
31
  import pymmcore
32
32
 
33
33
  typer.echo(f"pymmcore-plus v{pymmcore_plus.__version__}")
34
- typer.echo(f"pymmcore v{pymmcore.__version__}") # type: ignore [attr-defined]
34
+ typer.echo(f"pymmcore v{pymmcore.__version__}")
35
35
  typer.echo(f"MMCore v{pymmcore.CMMCore().getAPIVersionInfo()}")
36
36
  raise typer.Exit()
37
37
 
@@ -53,7 +53,7 @@ def _main(
53
53
  # fix for windows CI encoding and emoji printing
54
54
  if getattr(sys.stdout, "encoding", None) != "utf-8":
55
55
  with suppress(AttributeError):
56
- sys.stdout.reconfigure(encoding="utf-8") # type: ignore [attr-defined]
56
+ sys.stdout.reconfigure(encoding="utf-8") # type: ignore [union-attr]
57
57
 
58
58
 
59
59
  if "mkdocs" in sys.argv[0]: # pragma: no cover
@@ -190,10 +190,10 @@ def run(
190
190
  None, help="Asymmetric range of z-stack below position."
191
191
  ),
192
192
  z_step: Optional[float] = typer.Option(None, help="Step size of z-stack."),
193
- z_relative: Optional[List[float]] = typer.Option(
193
+ z_relative: Optional[list[float]] = typer.Option(
194
194
  None, "-zr", help="Relative z-positions to acquire (may use multiple times)."
195
195
  ),
196
- z_absolute: Optional[List[float]] = typer.Option(
196
+ z_absolute: Optional[list[float]] = typer.Option(
197
197
  None, "-za", help="Absolute z-positions to acquire (may use multiple times)."
198
198
  ),
199
199
  t_interval: Optional[float] = typer.Option(
@@ -207,7 +207,7 @@ def run(
207
207
  axis_order: Optional[str] = typer.Option(
208
208
  None, help="Order of axes to acquire (e.g. 'TPCZ')."
209
209
  ),
210
- channel: Optional[List[str]] = typer.Option(
210
+ channel: Optional[list[str]] = typer.Option(
211
211
  None,
212
212
  help="\bChannel to acquire. Argument is a string of the following form:\n"
213
213
  '\b - name: "DAPI"\n'
@@ -294,7 +294,7 @@ def run(
294
294
 
295
295
  @app.command()
296
296
  def build_dev(
297
- devices: Optional[List[str]] = typer.Argument(
297
+ devices: Optional[list[str]] = typer.Argument(
298
298
  None, help=f"Device adapters to build. Defaults to {DEFAULT_PACKAGES}"
299
299
  ),
300
300
  dest: Path = typer.Option(
@@ -6,7 +6,10 @@ import sys
6
6
  from contextlib import contextmanager
7
7
  from logging.handlers import RotatingFileHandler
8
8
  from pathlib import Path
9
- from typing import ClassVar, Iterator
9
+ from typing import TYPE_CHECKING, ClassVar
10
+
11
+ if TYPE_CHECKING:
12
+ from collections.abc import Iterator
10
13
 
11
14
  __all__ = ["logger"]
12
15
 
@@ -18,8 +18,9 @@ from typing import TYPE_CHECKING, cast, overload
18
18
  from platformdirs import user_data_dir
19
19
 
20
20
  if TYPE_CHECKING:
21
+ from collections.abc import Iterator
21
22
  from re import Pattern
22
- from typing import Any, Callable, Iterator, Literal, TypeVar
23
+ from typing import Any, Callable, Literal, TypeVar
23
24
 
24
25
  QtConnectionType = Literal["AutoConnection", "DirectConnection", "QueuedConnection"]
25
26
 
@@ -3,15 +3,17 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from collections import defaultdict
6
- from typing import TYPE_CHECKING, Any, Iterable, Iterator, Tuple, overload
6
+ from typing import TYPE_CHECKING, Any, overload
7
7
 
8
8
  import pymmcore
9
9
 
10
10
  if TYPE_CHECKING:
11
+ from collections.abc import Iterable, Iterator
12
+
11
13
  from typing_extensions import TypeAlias # py310
12
14
 
13
- DevPropValueTuple: TypeAlias = Tuple[str, str, str]
14
- DevPropTuple: TypeAlias = Tuple[str, str]
15
+ DevPropValueTuple: TypeAlias = tuple[str, str, str]
16
+ DevPropTuple: TypeAlias = tuple[str, str]
15
17
 
16
18
 
17
19
  class Configuration(pymmcore.Configuration):
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Iterator, Literal, MutableMapping, overload
3
+ from collections.abc import Iterator, MutableMapping
4
+ from typing import TYPE_CHECKING, Any, Literal, overload
4
5
 
5
6
  import pymmcore
6
7
 
@@ -1,8 +1,8 @@
1
1
  """pythonic wrapper on pymmcore.Metadata object."""
2
2
 
3
- from collections.abc import Mapping
3
+ from collections.abc import ItemsView, Iterator, KeysView, Mapping, ValuesView
4
4
  from types import new_class
5
- from typing import Any, ItemsView, Iterator, KeysView, ValuesView, cast
5
+ from typing import Any, cast
6
6
 
7
7
  import pymmcore
8
8
 
@@ -10,17 +10,14 @@ from collections import defaultdict
10
10
  from contextlib import contextmanager, suppress
11
11
  from datetime import datetime
12
12
  from pathlib import Path
13
+ from re import Pattern
13
14
  from textwrap import dedent
14
15
  from threading import RLock, Thread
15
16
  from typing import (
16
17
  TYPE_CHECKING,
17
18
  Any,
18
19
  Callable,
19
- Iterable,
20
- Iterator,
21
20
  NamedTuple,
22
- Pattern,
23
- Sequence,
24
21
  TypeVar,
25
22
  overload,
26
23
  )
@@ -51,6 +48,7 @@ from ._sequencing import can_sequence_events
51
48
  from .events import CMMCoreSignaler, PCoreSignaler, _get_auto_core_callback_class
52
49
 
53
50
  if TYPE_CHECKING:
51
+ from collections.abc import Iterable, Iterator, Sequence
54
52
  from typing import Literal, TypedDict
55
53
 
56
54
  import numpy as np
@@ -1594,7 +1592,7 @@ class CMMCorePlus(pymmcore.CMMCore):
1594
1592
 
1595
1593
  try:
1596
1594
  channel_group = self.getPropertyFromCache("Core", "ChannelGroup")
1597
- channel = self.getCurrentConfigFromCache(channel_group)
1595
+ channel: str = self.getCurrentConfigFromCache(channel_group)
1598
1596
  except Exception:
1599
1597
  channel = "Default"
1600
1598
  tags["Channel"] = channel
@@ -2010,7 +2008,7 @@ class CMMCorePlus(pymmcore.CMMCore):
2010
2008
 
2011
2009
  :sparkles: *This method is new in `CMMCorePlus`.*
2012
2010
  """
2013
- _current = {
2011
+ _current: dict[str, str] = {
2014
2012
  self.getCameraDevice(): "Camera",
2015
2013
  self.getXYStageDevice(): "XYStage",
2016
2014
  self.getFocusDevice(): "Focus",
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from functools import cached_property
4
- from typing import TYPE_CHECKING, Any, Sequence, TypedDict
4
+ from typing import TYPE_CHECKING, Any, TypedDict
5
5
 
6
6
  from pymmcore import g_Keyword_Label, g_Keyword_State
7
7
 
@@ -9,6 +9,8 @@ from ._constants import DeviceType, PropertyType
9
9
  from .events._device_signal_view import _DevicePropValueSignal
10
10
 
11
11
  if TYPE_CHECKING:
12
+ from collections.abc import Sequence
13
+
12
14
  from ._mmcore_plus import CMMCorePlus
13
15
 
14
16
 
@@ -1,13 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from itertools import product
4
- from typing import TYPE_CHECKING, Literal, Sequence, Tuple, overload
4
+ from typing import TYPE_CHECKING, Literal, overload
5
5
 
6
6
  from useq import AcquireImage, MDAEvent
7
7
 
8
8
  from pymmcore_plus.core._constants import DeviceType
9
9
 
10
10
  if TYPE_CHECKING:
11
+ from collections.abc import Sequence
12
+
11
13
  from pymmcore_plus import CMMCorePlus
12
14
 
13
15
 
@@ -18,12 +20,12 @@ class SequencedEvent(MDAEvent):
18
20
  calculate sequences for x, y, z, and exposure based on an a sequence of events.
19
21
  """
20
22
 
21
- events: Tuple[MDAEvent, ...] # noqa: UP006
23
+ events: tuple[MDAEvent, ...]
22
24
 
23
- exposure_sequence: Tuple[float, ...] # noqa: UP006
24
- x_sequence: Tuple[float, ...] # noqa: UP006
25
- y_sequence: Tuple[float, ...] # noqa: UP006
26
- z_sequence: Tuple[float, ...] # noqa: UP006
25
+ exposure_sequence: tuple[float, ...]
26
+ x_sequence: tuple[float, ...]
27
+ y_sequence: tuple[float, ...]
28
+ z_sequence: tuple[float, ...]
27
29
 
28
30
  # technically this is more like a field, but it requires a core instance
29
31
  # to getConfigData for channels, so we leave it as a method.
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Any, List, Type
1
+ from typing import TYPE_CHECKING, Any
2
2
 
3
3
  from pymmcore_plus._util import signals_backend
4
4
 
@@ -18,7 +18,7 @@ __all__ = [
18
18
  ]
19
19
 
20
20
 
21
- def _get_auto_core_callback_class() -> Type[PCoreSignaler]:
21
+ def _get_auto_core_callback_class() -> type[PCoreSignaler]:
22
22
  if signals_backend() == "qt":
23
23
  from ._qsignals import QCoreSignaler
24
24
 
@@ -26,7 +26,7 @@ def _get_auto_core_callback_class() -> Type[PCoreSignaler]:
26
26
  return CMMCoreSignaler
27
27
 
28
28
 
29
- def __dir__() -> List[str]: # pragma: no cover
29
+ def __dir__() -> list[str]: # pragma: no cover
30
30
  return [*list(globals()), "QCoreSignaler"]
31
31
 
32
32
 
@@ -1,14 +1,16 @@
1
- from typing import TYPE_CHECKING, Any, Optional
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
2
4
 
3
5
  if TYPE_CHECKING:
4
6
  from pymmcore_plus.core import CMMCorePlus
5
7
 
6
- from ._prop_event_mixin import _C
8
+ from ._prop_event_mixin import _C
7
9
 
8
10
 
9
11
  class _DevicePropValueSignal:
10
12
  def __init__(
11
- self, device_label: str, property_name: Optional[str], mmcore: "CMMCorePlus"
13
+ self, device_label: str, property_name: str | None, mmcore: CMMCorePlus
12
14
  ) -> None:
13
15
  self._dev = device_label
14
16
  self._prop = property_name
@@ -18,13 +20,13 @@ class _DevicePropValueSignal:
18
20
  sig = self._mmc.events.devicePropertyChanged(self._dev, self._prop)
19
21
  return sig.connect(callback) # type: ignore
20
22
 
21
- def disconnect(self, callback: _C) -> None:
23
+ def disconnect(self, callback: _C | None = None) -> None:
22
24
  sig = self._mmc.events.devicePropertyChanged(self._dev, self._prop)
23
- return sig.disconnect(callback) # type: ignore
25
+ sig.disconnect(callback)
24
26
 
25
27
  def emit(self, *args: Any) -> Any:
26
28
  """Emits the signal with the given arguments."""
27
29
  self._mmc.events.devicePropertyChanged(self._dev, self._prop).emit(*args)
28
30
 
29
- def __call__(self, property: str) -> "_DevicePropValueSignal":
31
+ def __call__(self, property: str) -> _DevicePropValueSignal:
30
32
  return _DevicePropValueSignal(self._dev, property, self._mmc)
@@ -8,13 +8,11 @@ from types import MethodType
8
8
  from typing import TYPE_CHECKING, Any, Callable, Union
9
9
 
10
10
  if TYPE_CHECKING:
11
- from typing import Tuple
12
-
13
11
  from typing_extensions import TypeGuard # py310
14
12
 
15
- MethodRef = Tuple[weakref.ReferenceType[object], str, Callable | None]
13
+ MethodRef = tuple[weakref.ReferenceType[object], str, Callable | None]
16
14
  NormedCallback = Union[MethodRef, Callable]
17
- StoredSlot = Tuple[NormedCallback, int | None]
15
+ StoredSlot = tuple[NormedCallback, int | None]
18
16
  ReducerFunc = Callable[[tuple, tuple], tuple]
19
17
 
20
18
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Tuple, TypeVar
3
+ from typing import TYPE_CHECKING, Any, Callable, ClassVar, TypeVar
4
4
 
5
5
  from ._norm_slot import denormalize_slot, normalize_slot
6
6
  from ._protocol import PCoreSignaler
@@ -8,8 +8,8 @@ from ._protocol import PCoreSignaler
8
8
  if TYPE_CHECKING:
9
9
  from ._norm_slot import NormedCallback
10
10
 
11
- PropKey = Tuple[str, str | None, NormedCallback]
12
- PropKeyDict = Dict[PropKey, Callable]
11
+ PropKey = tuple[str, str | None, NormedCallback]
12
+ PropKeyDict = dict[PropKey, Callable]
13
13
 
14
14
 
15
15
  _C = TypeVar("_C", bound=Callable[..., Any])
@@ -64,8 +64,11 @@ class _PropertySignal:
64
64
  self._events.propertyChanged.connect(_wrapper)
65
65
  return callback
66
66
 
67
- def disconnect(self, callback: Callable) -> None:
67
+ def disconnect(self, callback: Callable | None = None) -> None:
68
68
  """Disconnect `callback` from this device and/or property."""
69
+ if callback is None:
70
+ self._events.propertyChanged.disconnect()
71
+ return
69
72
  key = (self._device, self._property, normalize_slot(callback))
70
73
  cb = self._events.property_callbacks.pop(key, None)
71
74
  if cb is None:
@@ -12,8 +12,11 @@ class PSignalInstance(Protocol):
12
12
  def connect(self, slot: Callable) -> Any:
13
13
  """Connect slot to this signal."""
14
14
 
15
- def disconnect(self, slot: Callable) -> Any:
16
- """Disconnect slot from this signal."""
15
+ def disconnect(self, slot: Optional[Callable] = None) -> Any:
16
+ """Disconnect slot from this signal.
17
+
18
+ If `None`, all slots should be disconnected.
19
+ """
17
20
 
18
21
  def emit(self, *args: Any) -> Any:
19
22
  """Emits the signal with the given arguments."""
@@ -10,7 +10,7 @@ import tempfile
10
10
  from contextlib import contextmanager, nullcontext
11
11
  from pathlib import Path
12
12
  from platform import system
13
- from typing import TYPE_CHECKING, Callable, ContextManager, Iterator, Protocol
13
+ from typing import TYPE_CHECKING, Callable, Protocol
14
14
  from urllib.request import urlopen, urlretrieve
15
15
 
16
16
  import typer
@@ -18,6 +18,8 @@ import typer
18
18
  from pymmcore_plus._util import USER_DATA_MM_PATH
19
19
 
20
20
  if TYPE_CHECKING:
21
+ from collections.abc import Iterator
22
+ from contextlib import AbstractContextManager
21
23
 
22
24
  class _MsgLogger(Protocol):
23
25
  def __call__(self, text: str, color: str = "", emoji: str = "") -> None: ...
@@ -70,7 +72,7 @@ def _get_download_name(url: str) -> str:
70
72
  return ""
71
73
 
72
74
 
73
- def _get_spinner(log_msg: _MsgLogger) -> Callable[[str], ContextManager]:
75
+ def _get_spinner(log_msg: _MsgLogger) -> Callable[[str], AbstractContextManager]:
74
76
  if log_msg is _pretty_print:
75
77
  spinner = _spinner
76
78
  else:
@@ -5,10 +5,7 @@ from contextlib import suppress
5
5
  from itertools import product
6
6
  from typing import (
7
7
  TYPE_CHECKING,
8
- Iterable,
9
- Iterator,
10
8
  NamedTuple,
11
- Sequence,
12
9
  cast,
13
10
  )
14
11
 
@@ -29,6 +26,8 @@ from pymmcore_plus.metadata import (
29
26
  from ._protocol import PMDAEngine
30
27
 
31
28
  if TYPE_CHECKING:
29
+ from collections.abc import Iterable, Iterator, Sequence
30
+
32
31
  from numpy.typing import NDArray
33
32
 
34
33
  from pymmcore_plus.core import CMMCorePlus
@@ -54,12 +53,11 @@ class MDAEngine(PMDAEngine):
54
53
  attempt to combine MDAEvents into a single `SequencedEvent` if
55
54
  [`core.canSequenceEvents()`][pymmcore_plus.CMMCorePlus.canSequenceEvents]
56
55
  reports that the events can be sequenced. This can be set after instantiation.
57
- By default, this is `False`, in order to avoid unexpected behavior, particularly
58
- in testing and demo scenarios. But in many "real world" scenarios, this can be
59
- set to `True` to improve performance.
56
+ By default, this is `True`, however in various testing and demo scenarios, you
57
+ may wish to set it to `False` in order to avoid unexpected behavior.
60
58
  """
61
59
 
62
- def __init__(self, mmc: CMMCorePlus, use_hardware_sequencing: bool = False) -> None:
60
+ def __init__(self, mmc: CMMCorePlus, use_hardware_sequencing: bool = True) -> None:
63
61
  self._mmc = mmc
64
62
  self.use_hardware_sequencing = use_hardware_sequencing
65
63
 
@@ -4,7 +4,7 @@ from abc import abstractmethod
4
4
  from typing import TYPE_CHECKING, Protocol, runtime_checkable
5
5
 
6
6
  if TYPE_CHECKING:
7
- from typing import Iterable, Iterator
7
+ from collections.abc import Iterable, Iterator
8
8
 
9
9
  from numpy.typing import NDArray
10
10
  from useq import MDAEvent, MDASequence