polystore 0.2.2__tar.gz → 0.2.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.
- {polystore-0.2.2/src/polystore.egg-info → polystore-0.2.4}/PKG-INFO +1 -1
- {polystore-0.2.2 → polystore-0.2.4}/pyproject.toml +1 -1
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/__init__.py +0 -2
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/bioformats_java.py +30 -7
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/imagej_runtime.py +20 -19
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/omero_tables.py +9 -2
- {polystore-0.2.2 → polystore-0.2.4/src/polystore.egg-info}/PKG-INFO +1 -1
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_bioformats_java.py +19 -2
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_imagej_runtime.py +55 -7
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_omero_tables.py +13 -0
- {polystore-0.2.2 → polystore-0.2.4}/LICENSE +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/README.md +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/setup.cfg +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/array_payload.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/async_init.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/atomic.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/backend_registry.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/base.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/bioformats_storage.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/config.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/constants.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/disk.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/exceptions.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/fiji_stream.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/filemanager.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/formats.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/lazy_imports.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/memory.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/metadata_migration.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/metadata_writer.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/napari_stream.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/ome_zarr_storage.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/omero_local.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/omero_text.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/roi.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/roi_converters.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/__init__.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/_streaming_backend.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/base.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/handlers/__init__.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/handlers/fiji_images.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/handlers/fiji_rois.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/identity.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/__init__.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/batching/__init__.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/core/__init__.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/core/batch_engine.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/core/contracts.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/core/window_projection.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/fiji/__init__.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/fiji/fiji_batch_processor.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/napari/__init__.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/napari/layer_key.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/napari/napari_batch_processor.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/viewer_transport.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming_constants.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/utils.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/virtual_workspace.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/zarr.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/zarr_batch.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore/zmq_config.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore.egg-info/SOURCES.txt +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore.egg-info/dependency_links.txt +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore.egg-info/requires.txt +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/src/polystore.egg-info/top_level.txt +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_array_payload.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_backend_registry.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_basic.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_bioformats_storage.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_disk_backend.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_disk_coverage.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_disk_more.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_filemanager_backends.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_filemanager_extended.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_lazy_package_exports.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_memory_backend.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_memory_coverage.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_memory_type_authority.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_napari_batch_processor.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_ome_zarr_storage.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_omero_image_plane_batch.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_omero_text.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_png_format.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_roi.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_streaming_identity.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_streaming_metadata.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_streaming_receiver_core.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_streaming_shared_memory.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_viewer_transport.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_zarr_backend.py +0 -0
- {polystore-0.2.2 → polystore-0.2.4}/tests/test_zarr_batch.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "polystore"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.4"
|
|
8
8
|
description = "Framework-agnostic multi-backend storage abstraction for ML and scientific computing"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -40,7 +40,6 @@ from .filemanager import FileManager
|
|
|
40
40
|
from .formats import DEFAULT_IMAGE_EXTENSIONS, FileFormat
|
|
41
41
|
from .imagej_runtime import (
|
|
42
42
|
FIJI_IMAGEJ_RUNTIME,
|
|
43
|
-
ImageJJvmTeardown,
|
|
44
43
|
ImageJRuntimePolicy,
|
|
45
44
|
ImageJRuntimeUnavailableError,
|
|
46
45
|
)
|
|
@@ -97,7 +96,6 @@ __all__ = [
|
|
|
97
96
|
"Backend",
|
|
98
97
|
"MemoryType",
|
|
99
98
|
"FileFormat",
|
|
100
|
-
"ImageJJvmTeardown",
|
|
101
99
|
"ImageJRuntimePolicy",
|
|
102
100
|
"ImageJRuntimeUnavailableError",
|
|
103
101
|
"FIJI_IMAGEJ_RUNTIME",
|
|
@@ -93,17 +93,30 @@ class BioFormatsJavaContext:
|
|
|
93
93
|
self.FormatTools = format_tools
|
|
94
94
|
|
|
95
95
|
def dispose(self) -> None:
|
|
96
|
-
"""Dispose the
|
|
96
|
+
"""Dispose the current ImageJ gateway while keeping the JVM reusable."""
|
|
97
97
|
|
|
98
98
|
with self._lifecycle_lock:
|
|
99
|
-
gateway = self.
|
|
100
|
-
self.ij = None
|
|
101
|
-
self.ImageReader = None
|
|
102
|
-
self.MetadataTools = None
|
|
103
|
-
self.FormatTools = None
|
|
99
|
+
gateway = self._detach_gateway()
|
|
104
100
|
if gateway is not None:
|
|
105
101
|
gateway.dispose()
|
|
106
102
|
|
|
103
|
+
def shutdown(self) -> None:
|
|
104
|
+
"""Stop the process-owned ImageJ context and JVM exactly once."""
|
|
105
|
+
|
|
106
|
+
with self._lifecycle_lock:
|
|
107
|
+
gateway = self._detach_gateway()
|
|
108
|
+
FIJI_IMAGEJ_RUNTIME.shutdown(gateway, self.scyjava)
|
|
109
|
+
|
|
110
|
+
def _detach_gateway(self) -> Any | None:
|
|
111
|
+
"""Clear and return the currently owned ImageJ gateway."""
|
|
112
|
+
|
|
113
|
+
gateway = self.ij
|
|
114
|
+
self.ij = None
|
|
115
|
+
self.ImageReader = None
|
|
116
|
+
self.MetadataTools = None
|
|
117
|
+
self.FormatTools = None
|
|
118
|
+
return gateway
|
|
119
|
+
|
|
107
120
|
@classmethod
|
|
108
121
|
def dispose_instance(cls) -> None:
|
|
109
122
|
"""Dispose the initialized process-wide context without creating it."""
|
|
@@ -113,6 +126,16 @@ class BioFormatsJavaContext:
|
|
|
113
126
|
if context is not None:
|
|
114
127
|
context.dispose()
|
|
115
128
|
|
|
129
|
+
@classmethod
|
|
130
|
+
def shutdown_instance(cls) -> None:
|
|
131
|
+
"""Stop and release the initialized process-wide context without creating it."""
|
|
132
|
+
|
|
133
|
+
with cls._lock:
|
|
134
|
+
context = cls._instance
|
|
135
|
+
cls._instance = None
|
|
136
|
+
if context is not None:
|
|
137
|
+
context.shutdown()
|
|
138
|
+
|
|
116
139
|
def open_reader(self, source_path: str | Path) -> BioFormatsOpenedReader:
|
|
117
140
|
self.ensure_initialized()
|
|
118
141
|
metadata = self.MetadataTools.createOMEXMLMetadata()
|
|
@@ -136,7 +159,7 @@ class BioFormatsJavaContext:
|
|
|
136
159
|
reader.close()
|
|
137
160
|
|
|
138
161
|
|
|
139
|
-
register_cleanup_callback(BioFormatsJavaContext.
|
|
162
|
+
register_cleanup_callback(BioFormatsJavaContext.shutdown_instance)
|
|
140
163
|
|
|
141
164
|
|
|
142
165
|
def java_int(value: Any) -> int | None:
|
|
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
import logging
|
|
6
6
|
import time
|
|
7
7
|
from dataclasses import dataclass
|
|
8
|
-
from enum import Enum
|
|
9
8
|
from typing import Any
|
|
10
9
|
|
|
11
10
|
logger = logging.getLogger(__name__)
|
|
@@ -15,29 +14,14 @@ class ImageJRuntimeUnavailableError(RuntimeError):
|
|
|
15
14
|
"""Raised when an ImageJ distribution cannot use its declared Java runtime."""
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
class ImageJJvmTeardown(Enum):
|
|
19
|
-
"""JPype teardown behavior owned by an ImageJ process runtime."""
|
|
20
|
-
|
|
21
|
-
PROCESS_EXIT = False
|
|
22
|
-
DESTROY_JVM = True
|
|
23
|
-
|
|
24
|
-
def configure(self) -> None:
|
|
25
|
-
"""Apply this teardown behavior before the process starts its JVM."""
|
|
26
|
-
|
|
27
|
-
import jpype.config
|
|
28
|
-
|
|
29
|
-
jpype.config.destroy_jvm = self.value
|
|
30
|
-
|
|
31
|
-
|
|
32
17
|
@dataclass(frozen=True, slots=True)
|
|
33
18
|
class ImageJRuntimePolicy:
|
|
34
|
-
"""Own
|
|
19
|
+
"""Own an ImageJ endpoint, managed Java requirement, and process lifecycle."""
|
|
35
20
|
|
|
36
21
|
endpoint: str
|
|
37
22
|
java_fetch: str
|
|
38
23
|
java_vendor: str
|
|
39
24
|
java_version: str
|
|
40
|
-
jvm_teardown: ImageJJvmTeardown
|
|
41
25
|
initialization_retry_delays_seconds: tuple[float, ...] = ()
|
|
42
26
|
|
|
43
27
|
@property
|
|
@@ -82,7 +66,7 @@ class ImageJRuntimePolicy:
|
|
|
82
66
|
def configure_java(self, scyjava_module: Any) -> None:
|
|
83
67
|
"""Select managed Java before startup or validate the active JVM."""
|
|
84
68
|
|
|
85
|
-
self.
|
|
69
|
+
self._configure_controlled_jvm_shutdown()
|
|
86
70
|
if scyjava_module.jvm_started():
|
|
87
71
|
self.require_compatible_active_java(scyjava_module)
|
|
88
72
|
return
|
|
@@ -92,6 +76,24 @@ class ImageJRuntimePolicy:
|
|
|
92
76
|
version=self.java_version,
|
|
93
77
|
)
|
|
94
78
|
|
|
79
|
+
def shutdown(self, gateway: Any | None, scyjava_module: Any) -> None:
|
|
80
|
+
"""Dispose the ImageJ gateway and stop its JVM before Python finalization."""
|
|
81
|
+
|
|
82
|
+
self._configure_controlled_jvm_shutdown()
|
|
83
|
+
try:
|
|
84
|
+
if gateway is not None:
|
|
85
|
+
gateway.dispose()
|
|
86
|
+
finally:
|
|
87
|
+
scyjava_module.shutdown_jvm()
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def _configure_controlled_jvm_shutdown() -> None:
|
|
91
|
+
"""Require explicit JVM destruction while Python runtime state is valid."""
|
|
92
|
+
|
|
93
|
+
import jpype.config
|
|
94
|
+
|
|
95
|
+
jpype.config.destroy_jvm = True
|
|
96
|
+
|
|
95
97
|
def require_compatible_active_java(self, scyjava_module: Any) -> None:
|
|
96
98
|
"""Reject a JVM whose feature version differs from this declaration."""
|
|
97
99
|
|
|
@@ -122,6 +124,5 @@ FIJI_IMAGEJ_RUNTIME = ImageJRuntimePolicy(
|
|
|
122
124
|
java_fetch="always",
|
|
123
125
|
java_vendor="zulu-jre",
|
|
124
126
|
java_version="21",
|
|
125
|
-
jvm_teardown=ImageJJvmTeardown.PROCESS_EXIT,
|
|
126
127
|
initialization_retry_delays_seconds=(1.0, 2.0),
|
|
127
128
|
)
|
|
@@ -122,8 +122,8 @@ class OMEROTableService:
|
|
|
122
122
|
|
|
123
123
|
return bool(connection.c.sf.sharedResources().areTablesEnabled())
|
|
124
124
|
|
|
125
|
-
def
|
|
126
|
-
"""
|
|
125
|
+
def wait_until_available(self, connection: Any) -> Any:
|
|
126
|
+
"""Return shared resources after the declared table capability is ready."""
|
|
127
127
|
|
|
128
128
|
resources = connection.c.sf.sharedResources()
|
|
129
129
|
retry_delays = iter(self.readiness_retry_delays_seconds)
|
|
@@ -139,6 +139,13 @@ class OMEROTableService:
|
|
|
139
139
|
)
|
|
140
140
|
time.sleep(retry_delay)
|
|
141
141
|
|
|
142
|
+
return resources
|
|
143
|
+
|
|
144
|
+
def create_table(self, connection: Any, path: str) -> Any:
|
|
145
|
+
"""Create one table through a ready service and repository declaration."""
|
|
146
|
+
|
|
147
|
+
resources = self.wait_until_available(connection)
|
|
148
|
+
|
|
142
149
|
repository_map = resources.repositories()
|
|
143
150
|
descriptions = repository_map.descriptions
|
|
144
151
|
if not descriptions:
|
|
@@ -23,6 +23,7 @@ class _Gateway:
|
|
|
23
23
|
class _Runtime:
|
|
24
24
|
def __init__(self) -> None:
|
|
25
25
|
self.gateways: list[_Gateway] = []
|
|
26
|
+
self.shutdown_gateways: list[_Gateway | None] = []
|
|
26
27
|
|
|
27
28
|
def initialize(self, imagej_module, scyjava_module, *, mode: str) -> _Gateway:
|
|
28
29
|
assert imagej_module == "imagej"
|
|
@@ -32,11 +33,18 @@ class _Runtime:
|
|
|
32
33
|
self.gateways.append(gateway)
|
|
33
34
|
return gateway
|
|
34
35
|
|
|
36
|
+
def shutdown(self, gateway: _Gateway | None, scyjava_module) -> None:
|
|
37
|
+
self.shutdown_gateways.append(gateway)
|
|
38
|
+
if gateway is not None:
|
|
39
|
+
gateway.dispose()
|
|
40
|
+
scyjava_module.shutdown_jvm()
|
|
41
|
+
|
|
35
42
|
|
|
36
43
|
class _ScyJava:
|
|
37
44
|
def __init__(self, *, failing_import: str | None = None) -> None:
|
|
38
45
|
self.failing_import = failing_import
|
|
39
46
|
self.imports: list[str] = []
|
|
47
|
+
self.shutdown_count = 0
|
|
40
48
|
|
|
41
49
|
def jimport(self, name: str) -> object:
|
|
42
50
|
self.imports.append(name)
|
|
@@ -44,6 +52,9 @@ class _ScyJava:
|
|
|
44
52
|
raise RuntimeError(f"could not import {name}")
|
|
45
53
|
return object()
|
|
46
54
|
|
|
55
|
+
def shutdown_jvm(self) -> None:
|
|
56
|
+
self.shutdown_count += 1
|
|
57
|
+
|
|
47
58
|
|
|
48
59
|
def test_bioformats_context_disposes_and_can_reinitialize(monkeypatch) -> None:
|
|
49
60
|
runtime = _Runtime()
|
|
@@ -98,8 +109,11 @@ def test_dispose_instance_does_not_create_process_context(monkeypatch) -> None:
|
|
|
98
109
|
assert BioFormatsJavaContext._instance is None
|
|
99
110
|
|
|
100
111
|
|
|
101
|
-
def
|
|
102
|
-
|
|
112
|
+
def test_test_runtime_cleanup_stops_process_context(monkeypatch) -> None:
|
|
113
|
+
runtime = _Runtime()
|
|
114
|
+
scyjava = _ScyJava()
|
|
115
|
+
monkeypatch.setattr(bioformats_java, "FIJI_IMAGEJ_RUNTIME", runtime)
|
|
116
|
+
context = BioFormatsJavaContext("imagej", scyjava)
|
|
103
117
|
gateway = _Gateway()
|
|
104
118
|
context.ij = gateway
|
|
105
119
|
monkeypatch.setattr(BioFormatsJavaContext, "_instance", context)
|
|
@@ -108,3 +122,6 @@ def test_test_runtime_cleanup_disposes_process_context(monkeypatch) -> None:
|
|
|
108
122
|
|
|
109
123
|
assert gateway.dispose_count == 1
|
|
110
124
|
assert context.ij is None
|
|
125
|
+
assert runtime.shutdown_gateways == [gateway]
|
|
126
|
+
assert scyjava.shutdown_count == 1
|
|
127
|
+
assert BioFormatsJavaContext._instance is None
|
|
@@ -6,7 +6,6 @@ import pytest
|
|
|
6
6
|
|
|
7
7
|
from polystore.imagej_runtime import (
|
|
8
8
|
FIJI_IMAGEJ_RUNTIME,
|
|
9
|
-
ImageJJvmTeardown,
|
|
10
9
|
ImageJRuntimePolicy,
|
|
11
10
|
ImageJRuntimeUnavailableError,
|
|
12
11
|
)
|
|
@@ -25,6 +24,7 @@ class _ScyJava:
|
|
|
25
24
|
def __init__(self, *, started: bool, java_version: str) -> None:
|
|
26
25
|
self._started = started
|
|
27
26
|
self.constraints: list[dict[str, str]] = []
|
|
27
|
+
self.shutdown_count = 0
|
|
28
28
|
self.config = SimpleNamespace(
|
|
29
29
|
set_java_constraints=lambda **constraints: self.constraints.append(constraints)
|
|
30
30
|
)
|
|
@@ -37,12 +37,27 @@ class _ScyJava:
|
|
|
37
37
|
assert name == "java.lang.System"
|
|
38
38
|
return self._system
|
|
39
39
|
|
|
40
|
+
def shutdown_jvm(self) -> None:
|
|
41
|
+
self.shutdown_count += 1
|
|
42
|
+
self._started = False
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class _Gateway:
|
|
46
|
+
def __init__(self, events: list[str] | None = None) -> None:
|
|
47
|
+
self.dispose_count = 0
|
|
48
|
+
self.events = events
|
|
49
|
+
|
|
50
|
+
def dispose(self) -> None:
|
|
51
|
+
self.dispose_count += 1
|
|
52
|
+
if self.events is not None:
|
|
53
|
+
self.events.append("gateway_disposed")
|
|
54
|
+
|
|
40
55
|
|
|
41
56
|
class _ImageJ:
|
|
42
57
|
def __init__(self, scyjava: _ScyJava) -> None:
|
|
43
58
|
self._scyjava = scyjava
|
|
44
59
|
self.calls: list[tuple[str, str]] = []
|
|
45
|
-
self.gateway =
|
|
60
|
+
self.gateway = _Gateway()
|
|
46
61
|
|
|
47
62
|
def init(self, endpoint: str, *, mode: str) -> object:
|
|
48
63
|
self.calls.append((endpoint, mode))
|
|
@@ -53,7 +68,7 @@ class _ImageJ:
|
|
|
53
68
|
def test_fiji_runtime_selects_managed_java_before_initialization(monkeypatch) -> None:
|
|
54
69
|
import jpype.config
|
|
55
70
|
|
|
56
|
-
monkeypatch.setattr(jpype.config, "destroy_jvm",
|
|
71
|
+
monkeypatch.setattr(jpype.config, "destroy_jvm", False)
|
|
57
72
|
scyjava = _ScyJava(started=False, java_version="21.0.8")
|
|
58
73
|
imagej = _ImageJ(scyjava)
|
|
59
74
|
|
|
@@ -62,7 +77,43 @@ def test_fiji_runtime_selects_managed_java_before_initialization(monkeypatch) ->
|
|
|
62
77
|
assert gateway is imagej.gateway
|
|
63
78
|
assert scyjava.constraints == [{"fetch": "always", "vendor": "zulu-jre", "version": "21"}]
|
|
64
79
|
assert imagej.calls == [("sc.fiji:fiji", "headless")]
|
|
65
|
-
assert jpype.config.destroy_jvm is
|
|
80
|
+
assert jpype.config.destroy_jvm is True
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_fiji_runtime_shuts_down_gateway_before_jvm(monkeypatch) -> None:
|
|
84
|
+
import jpype.config
|
|
85
|
+
|
|
86
|
+
events: list[str] = []
|
|
87
|
+
gateway = _Gateway(events)
|
|
88
|
+
scyjava = _ScyJava(started=True, java_version="21")
|
|
89
|
+
original_shutdown = scyjava.shutdown_jvm
|
|
90
|
+
|
|
91
|
+
def record_shutdown() -> None:
|
|
92
|
+
events.append("jvm_shutdown")
|
|
93
|
+
original_shutdown()
|
|
94
|
+
|
|
95
|
+
scyjava.shutdown_jvm = record_shutdown
|
|
96
|
+
monkeypatch.setattr(jpype.config, "destroy_jvm", False)
|
|
97
|
+
|
|
98
|
+
FIJI_IMAGEJ_RUNTIME.shutdown(gateway, scyjava)
|
|
99
|
+
|
|
100
|
+
assert events == ["gateway_disposed", "jvm_shutdown"]
|
|
101
|
+
assert gateway.dispose_count == 1
|
|
102
|
+
assert scyjava.shutdown_count == 1
|
|
103
|
+
assert jpype.config.destroy_jvm is True
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_fiji_runtime_stops_jvm_after_gateway_disposal_failure() -> None:
|
|
107
|
+
class _FailingGateway:
|
|
108
|
+
def dispose(self) -> None:
|
|
109
|
+
raise RuntimeError("gateway disposal failed")
|
|
110
|
+
|
|
111
|
+
scyjava = _ScyJava(started=True, java_version="21")
|
|
112
|
+
|
|
113
|
+
with pytest.raises(RuntimeError, match="gateway disposal failed"):
|
|
114
|
+
FIJI_IMAGEJ_RUNTIME.shutdown(_FailingGateway(), scyjava)
|
|
115
|
+
|
|
116
|
+
assert scyjava.shutdown_count == 1
|
|
66
117
|
|
|
67
118
|
|
|
68
119
|
def test_runtime_accepts_compatible_active_java_without_reconfiguration() -> None:
|
|
@@ -95,7 +146,6 @@ def test_runtime_reports_an_unparseable_active_java_version() -> None:
|
|
|
95
146
|
java_fetch="always",
|
|
96
147
|
java_vendor="example-jre",
|
|
97
148
|
java_version="21",
|
|
98
|
-
jvm_teardown=ImageJJvmTeardown.PROCESS_EXIT,
|
|
99
149
|
)
|
|
100
150
|
scyjava = _ScyJava(started=True, java_version="unknown")
|
|
101
151
|
|
|
@@ -138,7 +188,6 @@ def test_runtime_retries_initialization_only_before_jvm_start(monkeypatch) -> No
|
|
|
138
188
|
java_fetch="always",
|
|
139
189
|
java_vendor="example-jre",
|
|
140
190
|
java_version="21",
|
|
141
|
-
jvm_teardown=ImageJJvmTeardown.PROCESS_EXIT,
|
|
142
191
|
initialization_retry_delays_seconds=(0.1, 0.2),
|
|
143
192
|
)
|
|
144
193
|
scyjava = _ScyJava(started=False, java_version="21")
|
|
@@ -169,7 +218,6 @@ def test_runtime_preserves_final_failure_after_retry_schedule() -> None:
|
|
|
169
218
|
java_fetch="always",
|
|
170
219
|
java_vendor="example-jre",
|
|
171
220
|
java_version="21",
|
|
172
|
-
jvm_teardown=ImageJJvmTeardown.PROCESS_EXIT,
|
|
173
221
|
initialization_retry_delays_seconds=(0.0, 0.0),
|
|
174
222
|
)
|
|
175
223
|
scyjava = _ScyJava(started=False, java_version="21")
|
|
@@ -142,6 +142,19 @@ def test_table_service_waits_on_capability_instead_of_exception_text(
|
|
|
142
142
|
assert resources.created_tables == [(7, "measurements.h5")]
|
|
143
143
|
|
|
144
144
|
|
|
145
|
+
def test_table_service_exposes_declared_readiness_wait(monkeypatch) -> None:
|
|
146
|
+
observed_delays: list[float] = []
|
|
147
|
+
monkeypatch.setattr("polystore.omero_tables.time.sleep", observed_delays.append)
|
|
148
|
+
resources = _Resources([False, True])
|
|
149
|
+
|
|
150
|
+
ready_resources = OMEROTableService(
|
|
151
|
+
readiness_retry_delays_seconds=(0.1,),
|
|
152
|
+
).wait_until_available(_connection(resources))
|
|
153
|
+
|
|
154
|
+
assert ready_resources is resources
|
|
155
|
+
assert observed_delays == [0.1]
|
|
156
|
+
|
|
157
|
+
|
|
145
158
|
def test_table_service_fails_before_create_when_capability_stays_unavailable() -> None:
|
|
146
159
|
resources = _Resources([False])
|
|
147
160
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/core/window_projection.py
RENAMED
|
File without changes
|
|
File without changes
|
{polystore-0.2.2 → polystore-0.2.4}/src/polystore/streaming/receivers/fiji/fiji_batch_processor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|