Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ missing or false feature flags leave them disabled. Within enabled shallow
storage, remote normalization is preferred; set `BIOMERO_REMOTE_SHALLOW_ZARR=false`
to use importer-side normalization. NL-BIOMERO's demo enables these features.

Canonical indexing records the backing store's actual OME-Zarr profile: 0.4/v2
or 0.5/v3. Existing v2 stores are reused as v2, and importing an existing v3
Image or Plate does not require conversion to v2. V3 indexing requires the
generic semantic-guard API from the matching v3-capable shallower/importer;
older installations retain v2-only indexing. Mixed-format Plate inventories
are rejected rather than recorded under an incorrect profile.

Result file attachments use the existing on-disk paths. Workflow-qualified
attachment names are stored in OMERO metadata, so in-place image registrations
and attachment links remain valid. Directory-backed Zarr stores are available
Expand Down
2 changes: 1 addition & 1 deletion __workflows/SLURM_CellPose_Segmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
import logging

# Version constant for easy version management
VERSION = "2.9.0"
VERSION = "2.9.0b15"

logger = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion __workflows/SLURM_Run_Workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
constants.workflow.OUTPUT_CSV_TABLE,
constants.workflow.OUTPUT_ATTACH_FILE_OUTPUTS,
constants.workflow.OUTPUT_CREATE_ROIS]
VERSION = "2.9.0"
VERSION = "2.9.0b15"
CANONICAL_INPUTS_OUTPUT = "Canonical_Inputs"


Expand Down
2 changes: 1 addition & 1 deletion __workflows/SLURM_Run_Workflow_Batched.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
constants.workflow.OUTPUT_CREATE_ROIS]

# Version constant for easy version management
VERSION = "2.9.0"
VERSION = "2.9.0b15"

# Batched runs are queued the same way single runs are: this script resolves
# the batches and records them in a launcher task, and the supervisor spawns
Expand Down
2 changes: 1 addition & 1 deletion _data/SLURM_Get_Results.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
from omero_metadata.populate import ParsingContext

# Version constant for easy version management
VERSION = "2.9.0"
VERSION = "2.9.0b15"


def get_images_by_ids(conn, image_ids):
Expand Down
2 changes: 1 addition & 1 deletion _data/SLURM_Get_Update.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
import sys

# Version constant for easy version management
VERSION = "2.9.0"
VERSION = "2.9.0b15"

logger = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion _data/SLURM_Import_Results.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ def _mask_url(url): return url # Fallback function if import fails
)

# Version constant for easy version management
VERSION = "2.9.0"
VERSION = "2.9.0b15"


def load_canonical_input_snapshot(slurm_client, workflow_id):
Expand Down
2 changes: 1 addition & 1 deletion _data/SLURM_Remote_Conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
CONV_OPTIONS_TARGET = ['tiff', 'zarr']

# Version constant for easy version management
VERSION = "2.9.0"
VERSION = "2.9.0b15"


def resolve_log_fallback_target(client, conn):
Expand Down
2 changes: 1 addition & 1 deletion _data/_SLURM_File_Transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

logger = logging.getLogger(__name__)

VERSION = "2.9.0"
VERSION = "2.9.0b15"


# ---------------------------------------------------------------------------
Expand Down
44 changes: 34 additions & 10 deletions _data/_SLURM_Image_Transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@
pixel_identities_match,
read_zarr_v2_semantic_guard,
)
try:
from biomero_importer.utils.pixel_identity import read_zarr_semantic_guard
except ImportError:
# Older deployments retain their v2-only behavior until upgraded.
read_zarr_semantic_guard = read_zarr_v2_semantic_guard
from biomero_importer.utils.result_zarr import (
discover_ngff_nodes,
)
Expand All @@ -140,7 +145,7 @@
)

# Version constant for easy version management
VERSION = "2.9.0"
VERSION = "2.9.0b15"
BIOMERO_CONFIG_FILE = os.getenv(
"OMERO_BIOMERO_CONFIG_FILE",
os.getenv("BIOMERO_CONFIG_FILE", "/opt/omero/server/biomero-config.json"),
Expand Down Expand Up @@ -684,6 +689,18 @@ def discover_canonical_inputs(objects, object_type):
return sources, tuple(canonical_inputs) if complete else ()


def canonical_interchange_profile(guard):
"""Record the supported format actually backing this canonical node."""
profiles = {
("0.4", 2): "ngff-0.4-zarr-v2",
("0.5", 3): "ngff-0.5-zarr-v3",
}
try:
return profiles[(guard.ngff_version, guard.zarr_format)]
except KeyError as exc:
raise ValueError("Unsupported canonical OME-Zarr format") from exc


def discover_canonical_label_components(
source,
storage_roots,
Expand All @@ -703,7 +720,7 @@ def discover_canonical_label_components(
or node.parent_image_node_path != source.node_path
):
continue
guard = read_zarr_v2_semantic_guard(root, node.node_path)
guard = read_zarr_semantic_guard(root, node.node_path)
identity = provider.generate(
root,
node_path=node.node_path,
Expand Down Expand Up @@ -761,7 +778,8 @@ def build_canonical_plate_source(
raise ValueError("Identity workers must be a positive integer")

def generate_identity(node):
guard = read_zarr_v2_semantic_guard(root, node.node_path)
guard = read_zarr_semantic_guard(root, node.node_path)
profile = canonical_interchange_profile(guard)
logger.info(
"Calculating ISCC-BIO pixel identity for Plate %s %s node %s",
plate.getId(),
Expand All @@ -787,18 +805,20 @@ def generate_identity(node):
identity.data_code,
identity.instance_code,
)
return node.node_path, identity
return node.node_path, identity, profile

identities = {}
profiles = set()
last_keepalive = monotonic()
with ThreadPoolExecutor(
max_workers=min(identity_workers, len(nodes)),
thread_name_prefix="biomero-iscc",
) as executor:
# map preserves discovery order in the canonical manifest even though
# the identity work and its diagnostic logging happen concurrently.
for node_path, identity in executor.map(generate_identity, nodes):
for node_path, identity, profile in executor.map(generate_identity, nodes):
identities[node_path] = identity
profiles.add(profile)
if (
keepalive is not None
and monotonic() - last_keepalive >= keepalive_interval
Expand All @@ -817,6 +837,9 @@ def generate_identity(node):
"Lost the OMERO connection while indexing the canonical Plate Zarr"
)

if len(profiles) != 1:
raise ValueError("Canonical Plate image/label nodes use different Zarr formats")
profile = profiles.pop()
relative_path = Path(relative_path).as_posix()
images = []
for image_node in image_nodes:
Expand All @@ -827,7 +850,7 @@ def generate_identity(node):
source_object_type="Plate",
source_object_id=int(plate.getId()),
source_generation=source_generation,
interchange_profile="ngff-0.4-zarr-v2",
interchange_profile=profile,
pixel_identity=identities[image_node.node_path],
pixel_identity_origin="canonical-bootstrap",
canonical_pixel_verified=False,
Expand Down Expand Up @@ -858,7 +881,7 @@ def generate_identity(node):
relative_path=relative_path,
source_object_id=int(plate.getId()),
source_generation=source_generation,
interchange_profile="ngff-0.4-zarr-v2",
interchange_profile=profile,
images=tuple(images),
)

Expand Down Expand Up @@ -1307,7 +1330,7 @@ def promote_exported_image_zarr(
image, storage_roots)
source_directory = derive_canonical_source_directory(image, storage_root)
semantic_guard_reader = (
semantic_guard_reader or read_zarr_v2_semantic_guard
semantic_guard_reader or read_zarr_semantic_guard
)
guard = semantic_guard_reader(export_path, ".")
validate_omero_image_semantics(image, guard)
Expand Down Expand Up @@ -1380,6 +1403,7 @@ def promote_exported_image_zarr(
original_identity=original_identity,
exported_identity=exported_identity,
pixel_identity_origin="omero-pixels",
interchange_profile=canonical_interchange_profile(guard),
)
logger.info(
"ISCC-BIO verification matched OMERO Pixels and exported Zarr for "
Expand Down Expand Up @@ -1428,7 +1452,7 @@ def index_existing_image_zarr(
storage_roots,
)
semantic_guard_reader = (
semantic_guard_reader or read_zarr_v2_semantic_guard
semantic_guard_reader or read_zarr_semantic_guard
)
guard = semantic_guard_reader(existing_path, ".")
validate_omero_image_semantics(image, guard)
Expand Down Expand Up @@ -1466,7 +1490,7 @@ def index_existing_image_zarr(
source_object_id=int(image.getId()),
source_generation=source_generation,
node_path=".",
interchange_profile="ngff-0.4-zarr-v2",
interchange_profile=canonical_interchange_profile(guard),
pixel_identity=existing_identity,
pixel_identity_origin="canonical-bootstrap",
canonical_pixel_verified=True,
Expand Down
2 changes: 1 addition & 1 deletion admin/BIOMERO_Migrate_Shallow_Storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@


logger = logging.getLogger(__name__)
VERSION = "2.9.0"
VERSION = "2.9.0b15"

OBJECT_TYPE = "Object Type"
OBJECT_IDS = "Object IDs (optional)"
Expand Down
2 changes: 1 addition & 1 deletion admin/Example_Minimal_Slurm_Script.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def _check_command_safety(cmd: str) -> str | None:
_SCMD = "Linux_Command"
_DEFAULT_SCMD = "ls -la"

VERSION = "2.9.0"
VERSION = "2.9.0b15"


def runScript():
Expand Down
2 changes: 1 addition & 1 deletion admin/SLURM_Cownary.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

logger = logging.getLogger(__name__)

VERSION = "2.9.0"
VERSION = "2.9.0b15"

_LOLCOW_IMAGE = "docker://godlovedc/lolcow"
_COWNARY_SBATCH_COMMAND = (
Expand Down
2 changes: 1 addition & 1 deletion admin/SLURM_Init_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
from queue import Queue, Empty

logger = logging.getLogger(__name__)
VERSION = "2.9.0"
VERSION = "2.9.0b15"


def format_metadata_summary(report):
Expand Down
2 changes: 1 addition & 1 deletion admin/SLURM_check_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
import pkg_resources

# Version constant for easy version management
VERSION = "2.9.0"
VERSION = "2.9.0b15"

logger = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion admin/Tail_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
_DEFAULT_TAIL_LINES = 5000

# Version constant for easy version management
VERSION = "2.9.0"
VERSION = "2.9.0b15"

logger = logging.getLogger(__name__)

Expand Down
Loading