Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
397cf85
omero fields optional
will-moore Feb 5, 2026
a5f44f9
Apply suggestion from @jo-mueller
will-moore Feb 5, 2026
390dfb5
Apply suggestion from @jo-mueller
will-moore Feb 5, 2026
e0c81bc
dictionaries renamed to objects
will-moore Feb 5, 2026
da24b78
Merge branch 'main' into omero_metadata_optional
will-moore Feb 5, 2026
4b0582e
Merge branch 'main' into omero_metadata_optional
jo-mueller Feb 10, 2026
e9141d3
Update index.md
jo-mueller Feb 12, 2026
0886492
align schema and spec text
jo-mueller Feb 12, 2026
87b04ae
Merge pull request #1 from jo-mueller/omero_metadata_optional
will-moore Feb 12, 2026
4387a7a
Merge branch 'main' into omero_metadata_optional
jo-mueller Feb 13, 2026
2f449c3
Merge remote-tracking branch 'upstream/main' into omero_metadata_schemas
jo-mueller Feb 13, 2026
03568f4
Merge branch 'omero_metadata_optional' of https://github.com/will-moo…
jo-mueller Feb 13, 2026
1ecf820
chore: json example code style
jo-mueller Feb 13, 2026
16eda06
fix: added missing fields to spec text
jo-mueller Feb 13, 2026
b6d5807
chore: semantic line break and text style
jo-mueller Feb 13, 2026
cd4509b
fix: adding missing `coefficient` to schema
jo-mueller Feb 13, 2026
362a988
test: added test cases
jo-mueller Feb 13, 2026
facbf73
Added note to changelog
jo-mueller Feb 13, 2026
c0c1121
Merge pull request #2 from jo-mueller/omero_metadata_optional
will-moore Mar 3, 2026
20fc097
Merge remote-tracking branch 'origin/main' into omero_metadata_optional
will-moore Mar 3, 2026
96dad79
Merge branch 'main' into omero_metadata_optional
lubianat Mar 4, 2026
3fbe3f0
Merge branch 'main' into omero_metadata_optional
jo-mueller Mar 12, 2026
9446d58
Merge remote-tracking branch 'origin/main' into omero_metadata_optional
will-moore Jul 22, 2026
8d19fd3
Remove 'family' and 'coefficient' from 'omero' schema, docs and samples
will-moore Jul 22, 2026
ec207e4
Remove # from color strings
will-moore Jul 22, 2026
71caad2
Update full_omero_metadata.json to 0.6rc0
will-moore Jul 22, 2026
e69e118
Remove link to omero docs WebGateway.html since this has no extra info
will-moore Jul 22, 2026
77e66df
refactor: move examples to _static subdirectory
jo-mueller Aug 19, 2026
9e09930
feat: added function to replace version key in `examples`
jo-mueller Aug 19, 2026
4cc7570
feat: ignore built json files
jo-mueller Aug 19, 2026
5aba3e8
Merge pull request #87 from will-moore/omero_metadata_optional
joshmoore Aug 20, 2026
845f672
Remove strict schemas
clbarnes Aug 5, 2026
a983c75
Remove strict test cases
clbarnes Aug 20, 2026
6c7218d
Add color, remove strict from conformance tester
clbarnes Aug 5, 2026
9a6aeb3
Rename strict examples
clbarnes Aug 5, 2026
4e7cd93
Remove strict examples from index.md
clbarnes Aug 5, 2026
947bdaa
Remove strictness handling from scripts
clbarnes Aug 5, 2026
2610883
rebase on https://github.com/ome/ngff-spec/pull/176
jo-mueller Aug 24, 2026
014d33f
rebase on https://github.com/ome/ngff-spec/pull/176 p2
jo-mueller Aug 24, 2026
dca429f
docs: update references to non-strict examples from _build
jo-mueller Aug 24, 2026
51bcb32
docs: update links to built docs
jo-mueller Aug 24, 2026
bde75cc
Merge branch 'main' into version-placeholders-in-examples
jo-mueller Aug 25, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ schemas/**/*.md
schemas/**/*.html
schemas/**/*.css
schemas/**/*.js
examples/_build

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
108 changes: 82 additions & 26 deletions conformance/ome_zarr_conformance.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,73 @@
"""

from __future__ import annotations
from concurrent.futures import Future, ThreadPoolExecutor

import json
import logging
import os
import re
import subprocess as sp
from argparse import ArgumentParser
from pathlib import Path
import sys
import re
import json
from argparse import ArgumentParser
from collections.abc import Iterable
from concurrent.futures import Future, ThreadPoolExecutor
from dataclasses import dataclass
from typing import Any, Iterable, Literal, Self
import logging
from pathlib import Path
from typing import Any, Literal, Self

logger = logging.getLogger("ome_zarr_conformance")

here = Path(__file__).resolve().parent.parent
tests_dir = here / "tests"

Status = Literal["pass", "fail", "error"]


def color(s: str, num: int, is_bright=False, is_background=False) -> str:
match (is_bright, is_background):
case (False, False):
pref = "3"
case (False, True):
pref = "4"
case (True, False):
pref = "9"
case (True, True):
pref = "10"
return f"\x1b[{pref}{num}m{s}\x1b[0m"


class Colorer:
def __init__(self) -> None:
self.is_term = sys.stdout.isatty()

def _colour(self, s: str, num: int, is_bright=False, is_background=False) -> str:
if not self.is_term:
return s
return color(s, num, is_bright, is_background)

def r(self, s: str) -> str:
return self._colour(s, 1)

def g(self, s: str) -> str:
return self._colour(s, 2)

def y(self, s: str) -> str:
return self._colour(s, 3)

def m(self, s: str) -> str:
return self._colour(s, 5)

def status(self, s: Status) -> str:
match s:
case "pass":
return self.g(s)
case "fail":
return self.r(s)
case "error":
return self.m(s)
case other:
raise ValueError(f"Unknown status '{other}'")


@dataclass
class CommandOutput:
Expand All @@ -39,7 +89,7 @@ def from_jso(cls, jso: dict[str, Any]) -> Self:
@dataclass
class TestResult:
test_name: str
status: Literal["pass", "fail", "error"]
status: Status
message: str | None
stderr: str
return_code: int
Expand All @@ -48,14 +98,12 @@ class TestResult:

@dataclass
class Conformance:
strict: bool
valid: bool
description: bool | None

@classmethod
def from_jso(cls, jso: dict[str, Any]) -> Self:
return cls(
strict=jso.get("strict", False),
valid=jso.get("valid", True),
description=jso.get("description"),
)
Expand All @@ -80,25 +128,21 @@ def __init__(
self,
exclude_patterns: list[re.Pattern] | None = None,
include_patterns: list[re.Pattern] | None = None,
exclude_strict=False,
exclude_invalid=False,
) -> None:
self.exclude_patterns = exclude_patterns or []
self.include_patterns = include_patterns or []

if exclude_strict:
self.exclude_patterns.append(re.compile(r"^strict/"))
if exclude_invalid:
self.exclude_patterns.append(re.compile(r"^\w+/invalid/"))

def include(self, name: str) -> bool:
if self.exclude_patterns and any(p.search(name) for p in self.exclude_patterns):
return False
if self.include_patterns and not any(
p.search(name) for p in self.include_patterns
):
return False
return True

if not self.include_patterns:
return True
return any(p.search(name) for p in self.include_patterns)


def test_path_to_name(fpath: Path, root: Path) -> str:
Expand All @@ -110,7 +154,9 @@ def run_test(dingus_cmd: list[str], fpath: Path, test_name: str) -> TestResult:
test_logger = logger.getChild(test_name)

strictness, validity, *_ = test_name.split("/")
if strictness not in ("strict", "spec"):
# previously there were "strict" tests which treated schema SHOULDs as MUSTs;
# these have since been removed
if strictness != "spec":
raise RuntimeError(f"cannot determine strictness from name: {test_name}")

if validity == "invalid":
Expand All @@ -124,6 +170,7 @@ def run_test(dingus_cmd: list[str], fpath: Path, test_name: str) -> TestResult:
dingus_cmd + [os.fspath(fpath)],
text=True,
capture_output=True,
check=False,
)

if res.returncode:
Expand Down Expand Up @@ -205,7 +252,7 @@ def main(raw_args=None):
"--exclude-strict",
"-S",
action="store_true",
help="exclude strict tests",
help="DEPRECATED: exclude strict tests",
)
parser.add_argument(
"--exclude-invalid",
Expand Down Expand Up @@ -241,7 +288,12 @@ def main(raw_args=None):
3: logging.DEBUG,
}.get(args.verbose, logging.DEBUG)
logging.basicConfig(level=lvl)
logging.debug("Got args: %s", args)
logger.debug("Got args: %s", args)

if args.exclude_strict:
logger.warning(
"Strict test cases are deprecated; -S/--exclude-strict argument is implicit and will soon be removed."
)

if dingus_args is None:
print(
Expand All @@ -267,28 +319,32 @@ def main(raw_args=None):
req = Requested(
exclude_patterns=args.exclude_pattern,
include_patterns=args.include_pattern,
exclude_strict=bool(args.exclude_strict),
exclude_invalid=bool(args.exclude_invalid),
)

test_paths = ((test_path_to_name(p, dpath), p) for p in dpath.rglob(rglob))
cases = dict(sorted((n, p) for n, p in test_paths if req.include(n)))

c = Colorer()

for res in run_all_tests(
dingus_args,
cases,
):
row = [
res.test_name,
res.status,
]
if res.status == "pass":
passes += 1
elif res.status == "fail":
failures += 1
elif res.status == "error":
errors += 1

row = [
res.test_name,
c.status(res.status),
]
if res.message:
row.append(" ".join(res.message.split()))

print("\t".join(row))

logger.info("Got %s passes, %s failures, %s errors", passes, failures, errors)
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"bioformats2raw.layout": 3
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"bioformats2raw.layout": 3,
"plate": {
"columns": [
Expand Down
3 changes: 3 additions & 0 deletions examples/_static/label/.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"schema": "schemas/label.schema"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"multiscales": [
{
"coordinateSystems": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"multiscales": [
{
"name": "example",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"multiscales": [
{
"version": "0.6rc0",
"version": "{{ VERSION }}",
"name": "example",
"coordinateSystems" : [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"multiscales": [
{
"name": "Image",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"multiscales": [
{
"coordinateSystems": [
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"series": ["0", "1"]
}
}
Expand Down
3 changes: 3 additions & 0 deletions examples/_static/plate/.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"schema": "schemas/plate.schema"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"plate": {
"acquisitions": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"plate": {
"acquisitions": [
{
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"scene": {
"coordinateTransformations": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"scene": {
"coordinateTransformations": [
{
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"multiscales": [
{
"name": "multiscales",
Expand Down
3 changes: 3 additions & 0 deletions examples/_static/transformations/displacements/.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"schema": "schemas/image.schema"
}
3 changes: 3 additions & 0 deletions examples/_static/well/.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"schema": "schemas/well.schema"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"well": {
"images": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
"version": "0.6rc0",
"version": "{{ VERSION }}",
"well": {
"images": [
{
Expand Down
3 changes: 0 additions & 3 deletions examples/label_strict/.config.json

This file was deleted.

3 changes: 0 additions & 3 deletions examples/multiscales_strict/.config.json

This file was deleted.

3 changes: 0 additions & 3 deletions examples/plate_strict/.config.json

This file was deleted.

3 changes: 0 additions & 3 deletions examples/well_strict/.config.json

This file was deleted.

Loading
Loading