Skip to content

zarr_filenames

anomaly_match.prediction.zarr_filenames

Derive per-image filenames for a Zarr store.

Shared by :mod:subprocess_scripts.prediction_process_zarr (to tag its store_results writes) and :mod:anomaly_match.pipeline.session (to detect when an entire Zarr file is already scored and skip the subprocess spawn entirely). Kept in one place so the two callers agree byte-for-byte on what name a given index resolves to.

derive_filenames(zarr_path)

Return the (filename ↔ zarr index) mapping used by prediction.

Looks for a parquet sidecar — pointed at either by the zarr's metadata_file attribute or by <name>_metadata.parquet next to the store — and pulls per-row filenames from original_filename / filename / source_id (in that order of preference). Falls back to {prefix}__image_{i:06d} when no metadata is found or the row count doesn't match.

Parameters:

Name Type Description Default
zarr_path str | Path

Path to the zarr store (file or directory).

required

Returns:

Type Description
list[str]

List of filename strings, length equal to the zarr's images

list[str]

array length. Empty list if the images array is missing or

list[str]

unreadable.

Source code in anomaly_match/prediction/zarr_filenames.py
def derive_filenames(zarr_path: str | Path) -> list[str]:
    """Return the ``(filename ↔ zarr index)`` mapping used by prediction.

    Looks for a parquet sidecar — pointed at either by the zarr's
    ``metadata_file`` attribute or by ``<name>_metadata.parquet`` next
    to the store — and pulls per-row filenames from
    ``original_filename`` / ``filename`` / ``source_id`` (in that order
    of preference).  Falls back to ``{prefix}__image_{i:06d}`` when no
    metadata is found or the row count doesn't match.

    Args:
        zarr_path: Path to the zarr store (file or directory).

    Returns:
        List of filename strings, length equal to the zarr's ``images``
        array length.  Empty list if the ``images`` array is missing or
        unreadable.
    """
    zarr_path = Path(zarr_path)
    try:
        root = zarr.open_group(str(zarr_path), mode="r")
    except Exception as exc:
        logger.warning("Cannot open Zarr store {} for filename derivation: {}", zarr_path, exc)
        return []

    if "images" not in root:
        logger.warning("Zarr store {} has no 'images' array", zarr_path)
        return []

    num_images = root["images"].shape[0]
    prefix = _zarr_prefix(zarr_path)
    metadata_file = _locate_metadata_file(zarr_path, dict(root.attrs))

    if metadata_file is None:
        return _generated_names(prefix, num_images)

    try:
        metadata_df = pd.read_parquet(metadata_file)
    except Exception as exc:
        logger.warning("Failed to read zarr metadata {}: {}", metadata_file, exc)
        return _generated_names(prefix, num_images)

    for column in _FILENAME_COLUMN_PRIORITY:
        if column in metadata_df.columns:
            filenames = [str(v) for v in metadata_df[column].tolist()]
            break
    else:
        logger.warning("No filename column in {}", metadata_file)
        return _generated_names(prefix, num_images)

    if len(filenames) != num_images:
        logger.warning(
            "Filename count ({}) does not match image count ({}) in {}",
            len(filenames),
            num_images,
            zarr_path,
        )
        return _generated_names(prefix, num_images)

    return filenames