From f5aa76f4350e51c5e881ec645a569dcd60e571c9 Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 13:36:38 +0100 Subject: [PATCH 01/16] Extract plate snippets under plate_strict --- 0.4/examples/plate_strict/plate_2wells.json | 91 +++++++++++ 0.4/examples/plate_strict/plate_6wells.json | 72 +++++++++ 0.4/index.bs | 171 +------------------- 3 files changed, 171 insertions(+), 163 deletions(-) create mode 100644 0.4/examples/plate_strict/plate_2wells.json create mode 100644 0.4/examples/plate_strict/plate_6wells.json diff --git a/0.4/examples/plate_strict/plate_2wells.json b/0.4/examples/plate_strict/plate_2wells.json new file mode 100644 index 00000000..dbc3197d --- /dev/null +++ b/0.4/examples/plate_strict/plate_2wells.json @@ -0,0 +1,91 @@ +{ + "plate": { + "acquisitions": [ + { + "id": 1, + "maximumfieldcount": 1, + "name": "single acquisition", + "starttime": 1343731272000 + } + ], + "columns": [ + { + "name": "1" + }, + { + "name": "2" + }, + { + "name": "3" + }, + { + "name": "4" + }, + { + "name": "5" + }, + { + "name": "6" + }, + { + "name": "7" + }, + { + "name": "8" + }, + { + "name": "9" + }, + { + "name": "10" + }, + { + "name": "11" + }, + { + "name": "12" + } + ], + "field_count": 1, + "name": "sparse test", + "rows": [ + { + "name": "A" + }, + { + "name": "B" + }, + { + "name": "C" + }, + { + "name": "D" + }, + { + "name": "E" + }, + { + "name": "F" + }, + { + "name": "G" + }, + { + "name": "H" + } + ], + "version": "0.4", + "wells": [ + { + "path": "C/5", + "rowIndex": 2, + "columnIndex": 4 + }, + { + "path": "D/7", + "rowIndex": 3, + "columnIndex": 6 + } + ] + } +} \ No newline at end of file diff --git a/0.4/examples/plate_strict/plate_6wells.json b/0.4/examples/plate_strict/plate_6wells.json new file mode 100644 index 00000000..cc082af5 --- /dev/null +++ b/0.4/examples/plate_strict/plate_6wells.json @@ -0,0 +1,72 @@ +{ + "plate": { + "acquisitions": [ + { + "id": 1, + "maximumfieldcount": 2, + "name": "Meas_01(2012-07-31_10-41-12)", + "starttime": 1343731272000 + }, + { + "id": 2, + "maximumfieldcount": 2, + "name": "Meas_02(201207-31_11-56-41)", + "starttime": 1343735801000 + } + ], + "columns": [ + { + "name": "1" + }, + { + "name": "2" + }, + { + "name": "3" + } + ], + "field_count": 4, + "name": "test", + "rows": [ + { + "name": "A" + }, + { + "name": "B" + } + ], + "version": "0.4", + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + }, + { + "path": "A/2", + "rowIndex": 0, + "columnIndex": 1 + }, + { + "path": "A/3", + "rowIndex": 0, + "columnIndex": 2 + }, + { + "path": "B/1", + "rowIndex": 1, + "columnIndex": 0 + }, + { + "path": "B/2", + "rowIndex": 1, + "columnIndex": 1 + }, + { + "path": "B/3", + "rowIndex": 1, + "columnIndex": 2 + } + ] + } +} \ No newline at end of file diff --git a/0.4/index.bs b/0.4/index.bs index 8dcb5cc2..d0a07ff2 100644 --- a/0.4/index.bs +++ b/0.4/index.bs @@ -494,173 +494,18 @@ custom attributes of the plate group under the `plate` key. For example the following JSON object defines a plate with two acquisitions and 6 wells (2 rows and 3 columns), containing up to 2 fields of view per acquisition. -```json -"plate": { - "acquisitions": [ - { - "id": 1, - "maximumfieldcount": 2, - "name": "Meas_01(2012-07-31_10-41-12)", - "starttime": 1343731272000 - }, - { - "id": 2, - "maximumfieldcount": 2, - "name": "Meas_02(201207-31_11-56-41)", - "starttime": 1343735801000 - } - ], - "columns": [ - { - "name": "1" - }, - { - "name": "2" - }, - { - "name": "3" - } - ], - "field_count": 4, - "name": "test", - "rows": [ - { - "name": "A" - }, - { - "name": "B" - } - ], - "version": "0.4", - "wells": [ - { - "path": "A/1", - "rowIndex": 0, - "columnIndex": 0 - }, - { - "path": "A/2" - "rowIndex": 0, - "columnIndex": 1 - }, - { - "path": "A/3" - "rowIndex": 0, - "columnIndex": 2 - }, - { - "path": "B/1" - "rowIndex": 1, - "columnIndex": 0 - }, - { - "path": "B/2" - "rowIndex": 1, - "columnIndex": 1 - }, - { - "path": "B/3" - "rowIndex": 1, - "columnIndex": 2 - } - ] - } -``` +
+path: examples/plate_strict/plates_6wells.json
+highlight: json
+
The following JSON object defines a sparse plate with one acquisition and 2 wells in a 96 well plate, containing one field of view per acquisition. -```json -"plate": { - "acquisitions": [ - { - "id": 1, - "maximumfieldcount": 1, - "name": "single acquisition", - "starttime": 1343731272000 - }, - ], - "columns": [ - { - "name": "1" - }, - { - "name": "2" - }, - { - "name": "3" - }, - { - "name": "4" - }, - { - "name": "5" - }, - { - "name": "6" - }, - { - "name": "7" - }, - { - "name": "8" - }, - { - "name": "9" - }, - { - "name": "10" - }, - { - "name": "11" - }, - { - "name": "12" - } - ], - "field_count": 1, - "name": "sparse test", - "rows": [ - { - "name": "A" - }, - { - "name": "B" - }, - { - "name": "C" - }, - { - "name": "D" - }, - { - "name": "E" - }, - { - "name": "F" - }, - { - "name": "G" - }, - { - "name": "H" - } - ], - "version": "0.1", - "wells": [ - { - "path": "C/5" - "rowIndex": 2, - "columnIndex": 4 - }, - { - "path": "D/7" - "rowIndex": 3, - "columnIndex": 6 - } - ] - } -``` +
+path: examples/plate_strict/plates_2wells.json
+highlight: json
+
"well" metadata {#well-md} -------------------------- From 6852d5e16a28acaf93874f10e05790e6053d897f Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 14:30:29 +0100 Subject: [PATCH 02/16] Add first version of plate JSON schema --- 0.4/schemas/plate.schema | 122 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 0.4/schemas/plate.schema diff --git a/0.4/schemas/plate.schema b/0.4/schemas/plate.schema new file mode 100644 index 00000000..50b08e21 --- /dev/null +++ b/0.4/schemas/plate.schema @@ -0,0 +1,122 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://ngff.openmicroscopy.org/0.4/schemas/plate.schema", + "title": "OME-NGFF plate schema", + "description": "JSON from OME-NGFF .zattrs", + "type": "object", + "properties": { + "acquisitions": { + "description": "The acquisitions for this plate", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "description": "A unique identifier within the context of the plate", + "type": "integer" + }, + "maximumfieldcount": { + "description": "The maximum number of fields of view for the acquisition", + "type": "integer" + }, + "name": { + "description": "The name of the acquisition", + "type": "string" + }, + "starttime": { + "description": "The start timestamp of the acquisition", + "type": "string" + }, + "endtime": { + "description": "The end timestamp of the acquisition", + "type": "string" + } + } + }, + "required": [ + "id" + ] + }, + "version": { + "description": "The version of the specification", + "type": "string", + "enum": [ + "0.4" + ] + }, + "field_count": { + "description": "The maximum number of fields per view across all well", + "type": "integer", + "exclusiveMinimum": 0 + }, + "name": { + "description": "The name of the plate", + "type": "string" + }, + "columns": { + "description": "The columns of the plate", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "The column name", + "type": "string", + "pattern": "^[A-Za-z0-9]+$" + } + }, + "required": [ + "name" + ] + } + }, + "rows": { + "description": "The rows of the plate", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "The row name", + "type": "string", + "pattern": "^[A-Za-z0-9]+$" + } + }, + "required": [ + "name" + ] + } + }, + "wells": { + "description": "The wells of the plate", + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "description": "The path to the well subgroup", + "type": "string", + "pattern": "^[A-Za-z0-9]+/[A-Za-z0-9]+$" + }, + "rowIndex": { + "description": "The index of the well in the rows list", + "type": "integer", + "exclusiveMinimum": 0 + }, + "columnIndex": { + "description": "The index of the well in the columns list", + "type": "integer", + "exclusiveMinimum": 0 + } + }, + "required": [ + "path", "rowIndex", "columnIndex" + ] + + } + }, + "required": [ + "columns", "rows", "wells" + ] + } +} From e49f12628499b3eeabb34625e8cfa72fcadaa242 Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 14:31:06 +0100 Subject: [PATCH 03/16] Only test the examples in the same folder as .config.json --- 0.4/tests/test_validation.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/0.4/tests/test_validation.py b/0.4/tests/test_validation.py index 83f49911..a9ce858e 100644 --- a/0.4/tests/test_validation.py +++ b/0.4/tests/test_validation.py @@ -1,5 +1,6 @@ import json import glob +import os from dataclasses import dataclass from typing import List @@ -63,7 +64,8 @@ def pytest_generate_tests(metafunc): schema = data["schema"] with open(schema) as f: schema = json.load(f) - for filename in glob.glob("examples/*/*.json"): + example_folder = os.path.dirname(config_filename) + for filename in glob.glob(f"{example_folder}/*.json"): with open(filename) as f: # Strip comments data = ''.join(line for line in f if not line.lstrip().startswith('//')) From 0cdc99aa52ddb259c7940ac7e7274c899ef6239d Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 14:13:49 +0100 Subject: [PATCH 04/16] Add first version of strict plate JSON schema --- 0.4/examples/plate_strict/.config.json | 3 +++ 0.4/schemas/strict_plate.schema | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 0.4/examples/plate_strict/.config.json create mode 100644 0.4/schemas/strict_plate.schema diff --git a/0.4/examples/plate_strict/.config.json b/0.4/examples/plate_strict/.config.json new file mode 100644 index 00000000..5a8990d6 --- /dev/null +++ b/0.4/examples/plate_strict/.config.json @@ -0,0 +1,3 @@ +{ + "schema": "schemas/plate.schema" +} diff --git a/0.4/schemas/strict_plate.schema b/0.4/schemas/strict_plate.schema new file mode 100644 index 00000000..56c8817c --- /dev/null +++ b/0.4/schemas/strict_plate.schema @@ -0,0 +1,25 @@ +{ + "$id": "https://ngff.openmicroscopy.org/0.4/schemas/strict_plate.schema", + "allOf": [ + { + "$ref": "https://ngff.openmicroscopy.org/0.4/schemas/plate.schema" + }, + { + "properties": { + "plate": { + "items": { + "required": [ + "acquisitions", + "columns", + "field_count", + "name", + "rows", + "version", + "wells" + ] + } + } + } + } + ] +} \ No newline at end of file From 949a3528b58fd78cb7c970da99222ad856def179 Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 14:21:50 +0100 Subject: [PATCH 05/16] test_validation: construct global schema store At the moment, each test suite is creating its own internal schema store with a single schema. This prevents the testing combined schemas like the strict schemas either when the parent schema is unpublished or simply offline. This commit migrates the logic to create a single global schema store --- 0.4/tests/test_validation.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/0.4/tests/test_validation.py b/0.4/tests/test_validation.py index a9ce858e..9e441fad 100644 --- a/0.4/tests/test_validation.py +++ b/0.4/tests/test_validation.py @@ -10,11 +10,15 @@ from jsonschema import RefResolver, Draft202012Validator as Validator from jsonschema.exceptions import ValidationError +schema_store = {} +for schema_filename in glob.glob("schemas/*"): + with open(schema_filename) as f: + schema = json.load(f) + schema_store[schema["$id"]] = schema @dataclass class Suite: schema: dict - schema_store: dict data: dict valid: bool = True @@ -55,7 +59,7 @@ def pytest_generate_tests(metafunc): schema = json.load(f) for test in suite["tests"]: ids.append("validate_" + str(test["formerly"]).split("/")[-1][0:-5]) - suites.append(Suite(schema, {schema["$id"]: schema}, test["data"], test["valid"])) + suites.append(Suite(schema, test["data"], test["valid"])) # Examples for config_filename in glob.glob("examples/*/.config.json"): @@ -71,7 +75,7 @@ def pytest_generate_tests(metafunc): data = ''.join(line for line in f if not line.lstrip().startswith('//')) data = json.loads(data) ids.append("example_" + str(filename).split("/")[-1][0:-5]) - suites.append(Suite(schema, {schema["$id"]: schema}, data, True)) # Assume true + suites.append(Suite(schema, data, True)) # Assume true metafunc.parametrize("suite", suites, ids=ids, indirect=True) @@ -82,6 +86,6 @@ def suite(request): def test_run(suite): - resolver = RefResolver.from_schema(suite.schema, store=suite.schema_store) + resolver = RefResolver.from_schema(suite.schema, store=schema_store) validator = Validator(suite.schema, resolver=resolver) suite.validate(validator) From 448bc5934b67073a32b3cfea7299dbdbd565f5bd Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 15:21:01 +0100 Subject: [PATCH 06/16] Add suite of test for plate schema --- 0.4/schemas/plate.schema | 219 +++++++++-------- 0.4/tests/plate_suite.json | 490 +++++++++++++++++++++++++++++++++++++ 2 files changed, 602 insertions(+), 107 deletions(-) create mode 100644 0.4/tests/plate_suite.json diff --git a/0.4/schemas/plate.schema b/0.4/schemas/plate.schema index 50b08e21..d6fc1a54 100644 --- a/0.4/schemas/plate.schema +++ b/0.4/schemas/plate.schema @@ -5,118 +5,123 @@ "description": "JSON from OME-NGFF .zattrs", "type": "object", "properties": { - "acquisitions": { - "description": "The acquisitions for this plate", - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "description": "A unique identifier within the context of the plate", - "type": "integer" - }, - "maximumfieldcount": { - "description": "The maximum number of fields of view for the acquisition", - "type": "integer" - }, - "name": { - "description": "The name of the acquisition", - "type": "string" - }, - "starttime": { - "description": "The start timestamp of the acquisition", - "type": "string" - }, - "endtime": { - "description": "The end timestamp of the acquisition", - "type": "string" - } - } - }, - "required": [ - "id" - ] - }, - "version": { - "description": "The version of the specification", - "type": "string", - "enum": [ - "0.4" - ] - }, - "field_count": { - "description": "The maximum number of fields per view across all well", - "type": "integer", - "exclusiveMinimum": 0 - }, - "name": { - "description": "The name of the plate", - "type": "string" - }, - "columns": { - "description": "The columns of the plate", - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "description": "The column name", - "type": "string", - "pattern": "^[A-Za-z0-9]+$" + "plate": { + "type": "object", + "properties": { + "acquisitions": { + "description": "The acquisitions for this plate", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "description": "A unique identifier within the context of the plate", + "type": "integer" + }, + "maximumfieldcount": { + "description": "The maximum number of fields of view for the acquisition", + "type": "integer", + "exclusiveMinimum": 0 + }, + "name": { + "description": "The name of the acquisition", + "type": "string" + }, + "starttime": { + "description": "The start timestamp of the acquisition", + "type": "integer" + }, + "endtime": { + "description": "The end timestamp of the acquisition", + "type": "integer" + } + }, + "required": [ + "id" + ] } }, - "required": [ - "name" - ] - } - }, - "rows": { - "description": "The rows of the plate", - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "description": "The row name", - "type": "string", - "pattern": "^[A-Za-z0-9]+$" + "version": { + "description": "The version of the specification", + "type": "string", + "enum": [ + "0.4" + ] + }, + "field_count": { + "description": "The maximum number of fields per view across all well", + "type": "integer", + "exclusiveMinimum": 0 + }, + "name": { + "description": "The name of the plate", + "type": "string" + }, + "columns": { + "description": "The columns of the plate", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "The column name", + "type": "string", + "pattern": "^[A-Za-z0-9]+$" + } + }, + "required": [ + "name" + ] } }, - "required": [ - "name" - ] - } - }, - "wells": { - "description": "The wells of the plate", - "type": "array", - "items": { - "type": "object", - "properties": { - "path": { - "description": "The path to the well subgroup", - "type": "string", - "pattern": "^[A-Za-z0-9]+/[A-Za-z0-9]+$" - }, - "rowIndex": { - "description": "The index of the well in the rows list", - "type": "integer", - "exclusiveMinimum": 0 - }, - "columnIndex": { - "description": "The index of the well in the columns list", - "type": "integer", - "exclusiveMinimum": 0 + "rows": { + "description": "The rows of the plate", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "The row name", + "type": "string", + "pattern": "^[A-Za-z0-9]+$" + } + }, + "required": [ + "name" + ] } }, - "required": [ - "path", "rowIndex", "columnIndex" - ] - - } - }, - "required": [ - "columns", "rows", "wells" - ] + "wells": { + "description": "The wells of the plate", + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "description": "The path to the well subgroup", + "type": "string", + "pattern": "^[A-Za-z0-9]+/[A-Za-z0-9]+$" + }, + "rowIndex": { + "description": "The index of the well in the rows list", + "type": "integer", + "minimum": 0 + }, + "columnIndex": { + "description": "The index of the well in the columns list", + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "path", "rowIndex", "columnIndex" + ] + } + } + }, + "required": [ + "columns", "rows", "wells" + ] + } } } diff --git a/0.4/tests/plate_suite.json b/0.4/tests/plate_suite.json new file mode 100644 index 00000000..b23ca474 --- /dev/null +++ b/0.4/tests/plate_suite.json @@ -0,0 +1,490 @@ +{ + "description": "TBD", + "schema": { + "id": "schemas/plate.schema" + }, + "tests": [ + { + "formerly": "plate/minimal", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": true + }, + { + "formerly": "plate/missing_rows", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/missing_columns", + "data": { + "plate": { + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/missing_wells", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/missing_column_name", + "data": { + "plate": { + "columns": [ + { + "concentration": 10 + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/missing_row_name", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "concentration": 10 + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/missing_well_path", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/missing_well_rowIndex", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/missing_well_columnIndex", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/well_1group", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A1", + "rowIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/well_3groups", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "plate/A/1", + "rowIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/invalid_version", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ], + "version": "foo" + } + }, + "valid": false + }, + { + "formerly": "plate/non_alphanumeric_column", + "data": { + "plate": { + "columns": [ + { + "name": "A-1" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A-1/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/non_alphanumeric_row", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "A1" + } + ], + "wells": [ + { + "path": "A/A1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": true + }, + { + "formerly": "plate/missing_acquisition_id", + "data": { + "plate": { + "acquisitions": [ + { + "maximumfieldcount": 0 + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/non_integer_acquisition_id", + "data": { + "plate": { + "acquisitions": [ + { + "id": "0" + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/non_integer_acquisition_maximumfieldcount", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "maximumfieldcount": "0" + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/acquisition_noninteger_starttime", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "starttime": "2022-05-13T13:48:06+00:00" + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/acquisition_noninteger_endtime", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "endtime": "2022-05-13T13:48:06+00:00" + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + } + ] +} From 8a807f728a055c69049407e182706217bd8bb0e3 Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 15:35:24 +0100 Subject: [PATCH 07/16] Add tests for strict plate JSON schema --- 0.4/schemas/strict_plate.schema | 25 ++-- 0.4/tests/plate_suite.json | 2 +- 0.4/tests/strict_plate_suite.json | 187 ++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 12 deletions(-) create mode 100644 0.4/tests/strict_plate_suite.json diff --git a/0.4/schemas/strict_plate.schema b/0.4/schemas/strict_plate.schema index 56c8817c..a49ce517 100644 --- a/0.4/schemas/strict_plate.schema +++ b/0.4/schemas/strict_plate.schema @@ -7,17 +7,20 @@ { "properties": { "plate": { - "items": { - "required": [ - "acquisitions", - "columns", - "field_count", - "name", - "rows", - "version", - "wells" - ] - } + "properties": { + "acquisitions": { + "items": { + "required": [ + "name", + "maximumfieldcount" + ] + } + } + }, + "required": [ + "name", + "version" + ] } } } diff --git a/0.4/tests/plate_suite.json b/0.4/tests/plate_suite.json index b23ca474..8c679f1e 100644 --- a/0.4/tests/plate_suite.json +++ b/0.4/tests/plate_suite.json @@ -1,5 +1,5 @@ { - "description": "TBD", + "description": "Tests for the plate JSON schema", "schema": { "id": "schemas/plate.schema" }, diff --git a/0.4/tests/strict_plate_suite.json b/0.4/tests/strict_plate_suite.json new file mode 100644 index 00000000..09d95253 --- /dev/null +++ b/0.4/tests/strict_plate_suite.json @@ -0,0 +1,187 @@ +{ + "description": "Tests for the strict plate JSON schema", + "schema": { + "id": "schemas/strict_plate.schema" + }, + "tests": [ + { + "formerly": "plate/strict", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "name": "test plate", + "rows": [ + { + "name": "1" + } + ], + "version": "0.4", + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": true + }, + { + "formerly": "plate/missing_name", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "version": "0.4", + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/missing_version", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "name": "test plate", + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/strict_acquisition", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "name": "0", + "maximumfieldcount": 1 + } + ], + "columns": [ + { + "name": "A" + } + ], + "name": "test plate", + "rows": [ + { + "name": "1" + } + ], + "version": "0.4", + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": true + }, + { + "formerly": "plate/missing_acquisition_name", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "maximumfieldcount": 1 + } + ], + "columns": [ + { + "name": "A" + } + ], + "name": "test plate", + "rows": [ + { + "name": "1" + } + ], + "version": "0.4", + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/missing_acquisition_maximumfieldcount", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "name": "0" + } + ], + "columns": [ + { + "name": "A" + } + ], + "name": "test plate", + "rows": [ + { + "name": "1" + } + ], + "version": "0.4", + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + } + ] +} \ No newline at end of file From c97eddcc2ae1e04e08baad9d27e9482aaa364ca6 Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 15:51:51 +0100 Subject: [PATCH 08/16] Test examples with strict plate schema --- 0.4/examples/plate_strict/.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/0.4/examples/plate_strict/.config.json b/0.4/examples/plate_strict/.config.json index 5a8990d6..a49b1743 100644 --- a/0.4/examples/plate_strict/.config.json +++ b/0.4/examples/plate_strict/.config.json @@ -1,3 +1,3 @@ { - "schema": "schemas/plate.schema" + "schema": "schemas/strict_plate.schema" } From bf021038f7b02a44765fc91ee1b2e6fd337cc511 Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 16:33:57 +0100 Subject: [PATCH 09/16] Fix internal reference --- 0.4/index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/0.4/index.bs b/0.4/index.bs index d0a07ff2..db983695 100644 --- a/0.4/index.bs +++ b/0.4/index.bs @@ -495,7 +495,7 @@ For example the following JSON object defines a plate with two acquisitions and 6 wells (2 rows and 3 columns), containing up to 2 fields of view per acquisition.
-path: examples/plate_strict/plates_6wells.json
+path: examples/plate_strict/plate_6wells.json
 highlight: json
 
@@ -503,7 +503,7 @@ The following JSON object defines a sparse plate with one acquisition and 2 wells in a 96 well plate, containing one field of view per acquisition.
-path: examples/plate_strict/plates_2wells.json
+path: examples/plate_strict/plate_2wells.json
 highlight: json
 
From 95a5162add1c2b3e4892f538afbb9685085c7506 Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 22:38:17 +0100 Subject: [PATCH 10/16] Disallow empty rows/columns/wells --- 0.4/schemas/plate.schema | 9 +- 0.4/tests/plate_suite.json | 152 +++++++++++++++++++++++++++++- 0.4/tests/strict_plate_suite.json | 36 ++++++- 3 files changed, 191 insertions(+), 6 deletions(-) diff --git a/0.4/schemas/plate.schema b/0.4/schemas/plate.schema index d6fc1a54..5a5ea779 100644 --- a/0.4/schemas/plate.schema +++ b/0.4/schemas/plate.schema @@ -72,7 +72,8 @@ "required": [ "name" ] - } + }, + "minItems": 1 }, "rows": { "description": "The rows of the plate", @@ -89,7 +90,8 @@ "required": [ "name" ] - } + }, + "minItems": 1 }, "wells": { "description": "The wells of the plate", @@ -116,7 +118,8 @@ "required": [ "path", "rowIndex", "columnIndex" ] - } + }, + "minItems": 1 } }, "required": [ diff --git a/0.4/tests/plate_suite.json b/0.4/tests/plate_suite.json index 8c679f1e..0821a7e0 100644 --- a/0.4/tests/plate_suite.json +++ b/0.4/tests/plate_suite.json @@ -5,7 +5,7 @@ }, "tests": [ { - "formerly": "plate/minimal", + "formerly": "plate/minimal_no_acquisitions", "data": { "plate": { "columns": [ @@ -29,6 +29,36 @@ }, "valid": true }, + { + "formerly": "plate/minimal_acquisitions", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0 + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": true + }, { "formerly": "plate/missing_rows", "data": { @@ -49,6 +79,27 @@ }, "valid": false }, + { + "formerly": "plate/empty_rows", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, { "formerly": "plate/missing_columns", "data": { @@ -69,6 +120,27 @@ }, "valid": false }, + { + "formerly": "plate/empty_columns", + "data": { + "plate": { + "columns": [], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, { "formerly": "plate/missing_wells", "data": { @@ -87,6 +159,25 @@ }, "valid": false }, + { + "formerly": "plate/empty_wells", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": {} + } + }, + "valid": false + }, { "formerly": "plate/missing_column_name", "data": { @@ -339,7 +430,7 @@ "plate": { "acquisitions": [ { - "maximumfieldcount": 0 + "maximumfieldcount": 1 } ], "columns": [ @@ -424,6 +515,37 @@ }, "valid": false }, + { + "formerly": "plate/acquisition_zero_maximumfieldcount", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "maximumfieldcount": 0 + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, { "formerly": "plate/acquisition_noninteger_starttime", "data": { @@ -485,6 +607,32 @@ } }, "valid": false + }, + { + "formerly": "plate/zero_field_count", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "field_count": 0, + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false } ] } diff --git a/0.4/tests/strict_plate_suite.json b/0.4/tests/strict_plate_suite.json index 09d95253..0453fe64 100644 --- a/0.4/tests/strict_plate_suite.json +++ b/0.4/tests/strict_plate_suite.json @@ -5,7 +5,7 @@ }, "tests": [ { - "formerly": "plate/strict", + "formerly": "plate/strict_no_acquisitions", "data": { "plate": { "columns": [ @@ -31,6 +31,40 @@ }, "valid": true }, + { + "formerly": "plate/strict_acquisitions", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "name": "0", + "maximumfieldcount": 1 + } + ], + "columns": [ + { + "name": "A" + } + ], + "name": "test plate", + "rows": [ + { + "name": "1" + } + ], + "version": "0.4", + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": true + }, { "formerly": "plate/missing_name", "data": { From 1bb8a07aa15d87e258c8b014c4940b92da1992dc Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 22:41:06 +0100 Subject: [PATCH 11/16] Disallow non-unique rows/columns/wells --- 0.4/schemas/plate.schema | 9 ++-- 0.4/tests/plate_suite.json | 89 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/0.4/schemas/plate.schema b/0.4/schemas/plate.schema index 5a5ea779..ed2a756e 100644 --- a/0.4/schemas/plate.schema +++ b/0.4/schemas/plate.schema @@ -73,7 +73,8 @@ "name" ] }, - "minItems": 1 + "minItems": 1, + "uniqueItems": true }, "rows": { "description": "The rows of the plate", @@ -91,7 +92,8 @@ "name" ] }, - "minItems": 1 + "minItems": 1, + "uniqueItems": true }, "wells": { "description": "The wells of the plate", @@ -119,7 +121,8 @@ "path", "rowIndex", "columnIndex" ] }, - "minItems": 1 + "minItems": 1, + "uniqueItems": true } }, "required": [ diff --git a/0.4/tests/plate_suite.json b/0.4/tests/plate_suite.json index 0821a7e0..51abec06 100644 --- a/0.4/tests/plate_suite.json +++ b/0.4/tests/plate_suite.json @@ -100,6 +100,34 @@ }, "valid": false }, + { + "formerly": "plate/duplicate_rows", + "data": { + "plate": { + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + }, + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, { "formerly": "plate/missing_columns", "data": { @@ -141,6 +169,34 @@ }, "valid": false }, + { + "formerly": "plate/duplicate_columns", + "data": { + "plate": { + "columns": [ + { + "name": "A" + }, + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, { "formerly": "plate/missing_wells", "data": { @@ -178,6 +234,39 @@ }, "valid": false }, + { + "formerly": "plate/duplicate_rows", + "data": { + "plate": { + "columns": [ + { + "name": "A" + }, + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + }, + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, { "formerly": "plate/missing_column_name", "data": { From d745d71712493a7f037fbf77b49b6d0f68b521ce Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Fri, 13 May 2022 22:46:38 +0100 Subject: [PATCH 12/16] Add trailing newlines --- 0.4/examples/plate_strict/plate_2wells.json | 2 +- 0.4/examples/plate_strict/plate_6wells.json | 2 +- 0.4/schemas/strict_plate.schema | 2 +- 0.4/tests/strict_plate_suite.json | 38 ++------------------- 4 files changed, 5 insertions(+), 39 deletions(-) diff --git a/0.4/examples/plate_strict/plate_2wells.json b/0.4/examples/plate_strict/plate_2wells.json index dbc3197d..2f963bd3 100644 --- a/0.4/examples/plate_strict/plate_2wells.json +++ b/0.4/examples/plate_strict/plate_2wells.json @@ -88,4 +88,4 @@ } ] } -} \ No newline at end of file +} diff --git a/0.4/examples/plate_strict/plate_6wells.json b/0.4/examples/plate_strict/plate_6wells.json index cc082af5..6bc262c6 100644 --- a/0.4/examples/plate_strict/plate_6wells.json +++ b/0.4/examples/plate_strict/plate_6wells.json @@ -69,4 +69,4 @@ } ] } -} \ No newline at end of file +} diff --git a/0.4/schemas/strict_plate.schema b/0.4/schemas/strict_plate.schema index a49ce517..5a88ab72 100644 --- a/0.4/schemas/strict_plate.schema +++ b/0.4/schemas/strict_plate.schema @@ -25,4 +25,4 @@ } } ] -} \ No newline at end of file +} diff --git a/0.4/tests/strict_plate_suite.json b/0.4/tests/strict_plate_suite.json index 0453fe64..49eeb3fc 100644 --- a/0.4/tests/strict_plate_suite.json +++ b/0.4/tests/strict_plate_suite.json @@ -31,40 +31,6 @@ }, "valid": true }, - { - "formerly": "plate/strict_acquisitions", - "data": { - "plate": { - "acquisitions": [ - { - "id": 0, - "name": "0", - "maximumfieldcount": 1 - } - ], - "columns": [ - { - "name": "A" - } - ], - "name": "test plate", - "rows": [ - { - "name": "1" - } - ], - "version": "0.4", - "wells": [ - { - "path": "A/1", - "rowIndex": 0, - "columnIndex": 0 - } - ] - } - }, - "valid": true - }, { "formerly": "plate/missing_name", "data": { @@ -118,7 +84,7 @@ "valid": false }, { - "formerly": "plate/strict_acquisition", + "formerly": "plate/strict_acquisitions", "data": { "plate": { "acquisitions": [ @@ -218,4 +184,4 @@ "valid": false } ] -} \ No newline at end of file +} From 295971de2bf33f2bce191c4d9e310490d25bcbb5 Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Sat, 14 May 2022 16:19:48 +0100 Subject: [PATCH 13/16] Extract well specification snippets under examples --- 0.4/examples/well_strict/well_2fields.json | 15 +++++++ 0.4/examples/well_strict/well_4fields.json | 23 +++++++++++ 0.4/index.bs | 46 ++++------------------ 3 files changed, 46 insertions(+), 38 deletions(-) create mode 100644 0.4/examples/well_strict/well_2fields.json create mode 100644 0.4/examples/well_strict/well_4fields.json diff --git a/0.4/examples/well_strict/well_2fields.json b/0.4/examples/well_strict/well_2fields.json new file mode 100644 index 00000000..5dca0af6 --- /dev/null +++ b/0.4/examples/well_strict/well_2fields.json @@ -0,0 +1,15 @@ +{ + "well": { + "images": [ + { + "acquisition": 0, + "path": "0" + }, + { + "acquisition": 3, + "path": "1" + } + ], + "version": "0.4" + } +} \ No newline at end of file diff --git a/0.4/examples/well_strict/well_4fields.json b/0.4/examples/well_strict/well_4fields.json new file mode 100644 index 00000000..e2f0890a --- /dev/null +++ b/0.4/examples/well_strict/well_4fields.json @@ -0,0 +1,23 @@ +{ + "well": { + "images": [ + { + "acquisition": 1, + "path": "0" + }, + { + "acquisition": 1, + "path": "1" + }, + { + "acquisition": 2, + "path": "2" + }, + { + "acquisition": 2, + "path": "3" + } + ], + "version": "0.4" + } +} \ No newline at end of file diff --git a/0.4/index.bs b/0.4/index.bs index db983695..d4f4b88e 100644 --- a/0.4/index.bs +++ b/0.4/index.bs @@ -530,49 +530,19 @@ For example the following JSON object defines a well with four fields of view. The first two fields of view were part of the first acquisition while the last two fields of view were part of the second acquisition. -```json -"well": { - "images": [ - { - "acquisition": 1, - "path": "0" - }, - { - "acquisition": 1, - "path": "1" - }, - { - "acquisition": 2, - "path": "2" - }, - { - "acquisition": 2, - "path": "3" - } - ], - "version": "0.4" - } -``` +
+path: examples/well_strict/well_4fields.json
+highlight: json
+
The following JSON object defines a well with two fields of view in a plate with four acquisitions. The first field is part of the first acquisition, and the second field is part of the last acquisition. -```json -"well": { - "images": [ - { - "acquisition": 0, - "path": "0" - }, - { - "acquisition": 3, - "path": "1" - } - ], - "version": "0.1" -} -``` +
+path: examples/well_strict/well_2fields.json
+highlight: json
+
Specification naming style {#naming-style} ========================================== From 495ac5dab312493bf6f4c1c72718ea2af5a7890b Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Sat, 14 May 2022 16:20:03 +0100 Subject: [PATCH 14/16] Add JSON schemas and JSON tests for well specification --- 0.4/examples/well_strict/.config.json | 3 + 0.4/schemas/strict_well.schema | 17 ++++++ 0.4/schemas/well.schema | 47 ++++++++++++++ 0.4/tests/strict_well_suite.json | 50 +++++++++++++++ 0.4/tests/well_suite.json | 88 +++++++++++++++++++++++++++ 5 files changed, 205 insertions(+) create mode 100644 0.4/examples/well_strict/.config.json create mode 100644 0.4/schemas/strict_well.schema create mode 100644 0.4/schemas/well.schema create mode 100644 0.4/tests/strict_well_suite.json create mode 100644 0.4/tests/well_suite.json diff --git a/0.4/examples/well_strict/.config.json b/0.4/examples/well_strict/.config.json new file mode 100644 index 00000000..129ac69c --- /dev/null +++ b/0.4/examples/well_strict/.config.json @@ -0,0 +1,3 @@ +{ + "schema": "schemas/strict_well.schema" +} diff --git a/0.4/schemas/strict_well.schema b/0.4/schemas/strict_well.schema new file mode 100644 index 00000000..1e200294 --- /dev/null +++ b/0.4/schemas/strict_well.schema @@ -0,0 +1,17 @@ +{ + "$id": "https://ngff.openmicroscopy.org/0.4/schemas/strict_well.schema", + "allOf": [ + { + "$ref": "https://ngff.openmicroscopy.org/0.4/schemas/well.schema" + }, + { + "properties": { + "well": { + "required": [ + "version" + ] + } + } + } + ] +} diff --git a/0.4/schemas/well.schema b/0.4/schemas/well.schema new file mode 100644 index 00000000..971a0102 --- /dev/null +++ b/0.4/schemas/well.schema @@ -0,0 +1,47 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://ngff.openmicroscopy.org/0.4/schemas/well.schema", + "title": "OME-NGFF well schema", + "description": "JSON from OME-NGFF .zattrs", + "type": "object", + "properties": { + "well": { + "type": "object", + "properties": { + "images": { + "description": "The fields of view for this well", + "type": "array", + "items": { + "type": "object", + "properties": { + "acquisition": { + "description": "A unique identifier within the context of the plate", + "type": "integer" + }, + "path": { + "description": "The path for this field of view subgroup", + "type": "string", + "pattern": "^[A-Za-z0-9]+$" + } + }, + "required": [ + "path" + ] + }, + "minItems": 1, + "uniqueItems": true + }, + "version": { + "description": "The version of the specification", + "type": "string", + "enum": [ + "0.4" + ] + } + }, + "required": [ + "images" + ] + } + } +} diff --git a/0.4/tests/strict_well_suite.json b/0.4/tests/strict_well_suite.json new file mode 100644 index 00000000..b4f8fe71 --- /dev/null +++ b/0.4/tests/strict_well_suite.json @@ -0,0 +1,50 @@ +{ + "description": "Tests for the strict well JSON schema", + "schema": { + "id": "schemas/strict_well.schema" + }, + "tests": [ + { + "formerly": "well/strict_no_acquisitions", + "data": { + "well": { + "images": [ + { + "path": "0" + } + ], + "version": "0.4" + } + }, + "valid": true + }, + { + "formerly": "plate/missing_version", + "data": { + "well": { + "images": [ + { + "path": "0" + } + ] + } + }, + "valid": false + }, + { + "formerly": "plate/strict_acquisitions", + "data": { + "well": { + "images": [ + { + "acquisition": 0, + "path": "0" + } + ], + "version": "0.4" + } + }, + "valid": true + } + ] +} diff --git a/0.4/tests/well_suite.json b/0.4/tests/well_suite.json new file mode 100644 index 00000000..0f752551 --- /dev/null +++ b/0.4/tests/well_suite.json @@ -0,0 +1,88 @@ +{ + "description": "Tests for the well JSON schema", + "schema": { + "id": "schemas/well.schema" + }, + "tests": [ + { + "formerly": "well/minimal_no_acquisition", + "data": { + "well": { + "images": [ + { + "path": "0" + } + ] + } + }, + "valid": true + }, + { + "formerly": "well/minimal_acquisitions", + "data": { + "well": { + "images": [ + { + "acquisition": 1, + "path": "0" + } + ] + } + }, + "valid": true + }, + { + "formerly": "well/empty_images", + "data": { + "well": { + "images": [] + } + }, + "valid": false + }, + { + "formerly": "well/duplicate_images", + "data": { + "well": { + "images": [ + { + "path": "0" + }, + { + "path": "0" + } + ] + } + }, + "valid": false + }, + { + "formerly": "well/invalid_version", + "data": { + "well": { + "images": [ + { + "path": "0" + } + ], + "version": "foo" + } + }, + "valid": false + }, + { + "formerly": "well/non_integer_acquisition_id", + "data": { + "well": { + "images": [ + { + "acquisition": "0", + "path": "0" + } + ] + } + }, + "valid": false + } + ] +} From 30d0156ac773c43d79c5892c29a6ae063dc7aeeb Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Tue, 17 May 2022 20:12:53 +0100 Subject: [PATCH 15/16] Ensure acquisition id, starttime and endtime are positive integers --- 0.4/schemas/plate.schema | 9 ++-- 0.4/tests/plate_suite.json | 92 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/0.4/schemas/plate.schema b/0.4/schemas/plate.schema index ed2a756e..5f19e637 100644 --- a/0.4/schemas/plate.schema +++ b/0.4/schemas/plate.schema @@ -16,7 +16,8 @@ "properties": { "id": { "description": "A unique identifier within the context of the plate", - "type": "integer" + "type": "integer", + "minimum": 0 }, "maximumfieldcount": { "description": "The maximum number of fields of view for the acquisition", @@ -29,11 +30,13 @@ }, "starttime": { "description": "The start timestamp of the acquisition", - "type": "integer" + "type": "integer", + "minimum": 0 }, "endtime": { "description": "The end timestamp of the acquisition", - "type": "integer" + "type": "integer", + "minimum": 0 } }, "required": [ diff --git a/0.4/tests/plate_suite.json b/0.4/tests/plate_suite.json index 51abec06..c19ad60e 100644 --- a/0.4/tests/plate_suite.json +++ b/0.4/tests/plate_suite.json @@ -573,6 +573,36 @@ }, "valid": false }, + { + "formerly": "plate/negative_acquisition_id", + "data": { + "plate": { + "acquisitions": [ + { + "id": -1 + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, { "formerly": "plate/non_integer_acquisition_maximumfieldcount", "data": { @@ -666,6 +696,37 @@ }, "valid": false }, + { + "formerly": "plate/acquisition_negative_starttime", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "starttime": -1 + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, { "formerly": "plate/acquisition_noninteger_endtime", "data": { @@ -697,6 +758,37 @@ }, "valid": false }, + { + "formerly": "plate/negative_endtime", + "data": { + "plate": { + "acquisitions": [ + { + "id": 0, + "endtime": -1 + } + ], + "columns": [ + { + "name": "A" + } + ], + "rows": [ + { + "name": "1" + } + ], + "wells": [ + { + "path": "A/1", + "rowIndex": 0, + "columnIndex": 0 + } + ] + } + }, + "valid": false + }, { "formerly": "plate/zero_field_count", "data": { From 38c3eb27722269a7f7bee2f49eb2172f63a2592f Mon Sep 17 00:00:00 2001 From: Sebastien Besson Date: Tue, 17 May 2022 20:21:24 +0100 Subject: [PATCH 16/16] Clarify that timestamps are epoch times --- 0.4/schemas/plate.schema | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/0.4/schemas/plate.schema b/0.4/schemas/plate.schema index 5f19e637..d23d7e52 100644 --- a/0.4/schemas/plate.schema +++ b/0.4/schemas/plate.schema @@ -29,12 +29,12 @@ "type": "string" }, "starttime": { - "description": "The start timestamp of the acquisition", + "description": "The start timestamp of the acquisition, expressed as epoch time i.e. the number seconds since the Epoch", "type": "integer", "minimum": 0 }, "endtime": { - "description": "The end timestamp of the acquisition", + "description": "The end timestamp of the acquisition, expressed as epoch time i.e. the number seconds since the Epoch", "type": "integer", "minimum": 0 } @@ -52,7 +52,7 @@ ] }, "field_count": { - "description": "The maximum number of fields per view across all well", + "description": "The maximum number of fields per view across all wells", "type": "integer", "exclusiveMinimum": 0 },