diff --git a/README.md b/README.md index 44d9c5499924fa9f2247c70d82dba57fd3da089e..c9c3548abb373c4db0ec3f7e1b06528196bc5f65 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ This schema defines the properties for projection data in THD JSON format. | Property | Type | Description | Constraints | Required | |-------------------------------|----------|---------------------------------------------------------|---------------------------|----------| +| `header` | header | Header to identify File. | format: Header | Yes | | `focal_spot_position_mm` | array | Position of the focal spot in millimeters | 3 numbers | Yes | | `focal_spot_orientation_quat` | array | Quaternion representing the focal spots orientation | 4 numbers | No | | `detector_center_position_mm` | array | Center position of the detector in millimeters | 3 numbers | Yes | @@ -40,6 +41,13 @@ This schema defines the properties for projection data in THD JSON format. | `image_height_px` | integer | Height of the image in pixels | Minimum 1 | Yes | | `projection_matrix_cera` | array | Projection matrix for CERA, representing transformations | 3 arrays of 4 numbers | No | +### Header + +| Property | Type | Description | Constraints | Required | +|------------|--------|--------------------------------------------------|--------------------------|----------| +| `timestamp`| string | Timestamp, e.g., 2018-11-13T20:20:39+00:00 | format: date-time | Yes | +| `uuid` | string | Unique identifier | format: uuid | Yes | + ### Examples diff --git a/examples/thd_json/test_thd.json b/examples/thd_json/test_thd.json index b8d52333f3530efcea729d73a240833894ef504a..0a345d279d73bf3babac630e30714a6128db9b3c 100644 --- a/examples/thd_json/test_thd.json +++ b/examples/thd_json/test_thd.json @@ -1,4 +1,9 @@ { + "header": + { + "uuid": "b83d81a1-333f-448e-af75-7c7db317fd96", + "timestamp": "2018-11-13T20:20:39+00:00" + }, "focal_spot_position_mm": [ 2724.71682, 1690.5, diff --git a/pyproject.toml b/pyproject.toml index f9e5a085eb94800c9fc0321553379418db43c506..5dda9732d721e27cdd86f11c45e5a7fb453dd5b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ dependencies = [ [project.scripts] projection_validator = "thd_json.projection:projection_cli" +header_validator = "thd_json.header:header_cli" [build-system] requires = ["hatchling"] diff --git a/src/thd_json/header/__init__.py b/src/thd_json/header/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..fcfc2d07132bd9d84ef0c1789896de554414a88f --- /dev/null +++ b/src/thd_json/header/__init__.py @@ -0,0 +1,31 @@ +from thd_json import Validator + +from pathlib import Path +import argparse + + +def get_header_validator(json_suffix: str = '*.json') -> Validator: + return Validator(Path(__file__).parent / Path('header.json'), json_suffix) + +def header_cli(): + parser = argparse.ArgumentParser(description='JSON THD Header Validator CLI with uv.') + parser.add_argument('folder', help='Folder to check.', type=str) + parser.add_argument('suffix', help='Projection suffix.', default='*.json', type=Path, nargs='?') + args = parser.parse_args() + + suffix = str(args.suffix) + if not suffix.startswith('*'): + raise ValueError(f'The suffix must always start with: "*". \nIt is: {suffix}') + + validator = get_header_validator( + suffix) + + folder = Path(args.folder) + if not folder.exists(): + raise FileNotFoundError(f'Folder: {folder} does not exist') + + validator.folder(Path(args.folder)) + + +if __name__ == "__main__": + header_cli() \ No newline at end of file diff --git a/src/thd_json/header/header.json b/src/thd_json/header/header.json new file mode 100644 index 0000000000000000000000000000000000000000..27312ff1b4b0c53ac4c21949833fd92ae2e2dd08 --- /dev/null +++ b/src/thd_json/header/header.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "THD Projection File Schema", + "type": "object", + "version": 0.2, + "date": "14.11.2024", + "properties": { + "timestamp": { + "type": "string", + "description": "Timestamp, e.g. 2018-11-13T20:20:39+00:00", + "format": "date-time" + }, + "uuid": { + "type": "string", + "description": "Unique identifier", + "format": "uuid" + } + }, + "required": [ + "timestamp", + "uuid" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/src/thd_json/projection/projection.json b/src/thd_json/projection/projection.json index 3e0c02562ad4c1fbdc4c3890155e2c04c7aa4f7d..fcafe946b991747f4715d05e49a68ec6853b62f3 100644 --- a/src/thd_json/projection/projection.json +++ b/src/thd_json/projection/projection.json @@ -2,9 +2,12 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "THD Projection File Schema", "type": "object", - "version": 0.2, - "date": "04.11.2024", + "version": 0.3, + "date": "14.11.2024", "properties": { + "header": { + "$ref": "./header/header.json" + }, "focal_spot_position_mm": { "type": "array", "description": "Position of the focal spot in millimeters.", diff --git a/src/thd_json/validation.py b/src/thd_json/validation.py index cc3cd19fe34e5735d569678bce15e78ffc7252f1..754a534f6a5c0dd0bdbad11793540207f61644fc 100644 --- a/src/thd_json/validation.py +++ b/src/thd_json/validation.py @@ -1,6 +1,9 @@ +import os import json from pathlib import Path -from jsonschema import validate, ValidationError +from jsonschema import ValidationError, RefResolver +from jsonschema.validators import Draft202012Validator +import os class Validator(): @@ -14,7 +17,12 @@ class Validator(): schema = json.load(schema_file) data = json.load(data_file) try: - validate(instance=data, schema=schema) + schema_path = self.json_schema.parent.absolute().as_uri() + resolver = RefResolver(base_uri=schema_path, + referrer=schema) + Draft202012Validator(schema=schema, + format_checker=Draft202012Validator.FORMAT_CHECKER, + resolver=resolver).validate(data) print(f"Validate file: {file_path.parent} / {file_path.name}\n") except ValidationError as e: