Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
xgui3783 committed May 15, 2024
0 parents commit b573b5a
Show file tree
Hide file tree
Showing 23 changed files with 508 additions and 0 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/validate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: '[validate] json schema validation'
on:
push:
branches: ["main"]
workflow_dispatch:
inputs:
use-cfg:
description: "branch of siibra-configuration to be checkout"
required: false
type: string
default: 'expmt_attr'
jobs:
validate:
- name: Set up Python 3.11
uses: actions/setup-python@v4
with:
python-version: '3.11'
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: FZJ-INM1-BDA/siibra-configurations
path: siibra-configurations
fetch-depth: 1
clean: True
ref: ${{ inputs.use-cfg }}
- run: |
pip install -r requirements.txt
- run: |
python code/validate.py ./siibra-configurations/features/
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
venv
124 changes: 124 additions & 0 deletions code/validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import sys
import os
from pathlib import Path
from logging import getLogger, DEBUG, INFO, StreamHandler
from jsonschema import ValidationError, Draft202012Validator
import referencing
import json
from enum import Enum


class ValidationResult(Enum):
SKIPPED = "SKIPPED"
PASSED = "PASSED"
FAILED = "FAILED"

logger = getLogger(__name__)
logger.setLevel(INFO)
logger.addHandler(StreamHandler())

ROOT_DIR = os.path.abspath(f"{os.path.dirname(os.path.realpath(__file__))}/..")

skip_path = ("venv", )

skip_types = (
"siibra/feature/timeseries/activity/v0.1",
"siibra/feature/connectivitymatrix/v0.3",
)

def populate_jsonschema_reg():
registry = referencing.Registry()
walk_path = Path(ROOT_DIR) / "siibra"
for dirpath, dirnames, filenames in os.walk(walk_path):
for filename in filenames:
if not filename.endswith(".json"):
continue

filepath = Path(dirpath) / filename
with open(filepath, "r") as fp:
uri = f"urn:siibra-local:{str(filepath.relative_to(ROOT_DIR))}"
resource = referencing.Resource.from_contents(json.load(fp=fp))
registry = registry.with_resource(uri=uri, resource=resource)

return registry

def validate_json(path_to_json, registry, fail_fast=False):
if any([path_fragment in path_to_json for path_fragment in skip_path]):
return (
path_to_json,
ValidationResult.SKIPPED,
None,
)
with open(path_to_json, "r") as fp:
json_obj = json.load(fp)

# skip list
if isinstance(json_obj, list):
return (path_to_json, ValidationResult.SKIPPED, None)
_type = json_obj.get("@type", None)
if not _type:
# TODO consolidate how error are raied
if fail_fast:
raise ValidationError(f"type does not exist: {path_to_json}")
return (path_to_json, ValidationResult.FAILED, None)

# assert _schema is None
if not _type or not _type.startswith("siibra"):
return (path_to_json, ValidationResult.SKIPPED, None)
if _type in skip_types:
return (path_to_json, ValidationResult.SKIPPED, None)
abspath = os.path.join(ROOT_DIR, (_type + ".json"))
path_to_schema = os.path.abspath(abspath)
with open(path_to_schema, "r") as fp:
schema = json.load(fp)
try:
validator = Draft202012Validator(schema, registry=registry)
validator.validate(json_obj)
except ValidationError as e:
if fail_fast:
# TODO consolidate how error are raied
raise e from e
return (path_to_json, ValidationResult.FAILED, e)
return (path_to_json, ValidationResult.PASSED, None)

def main(dir_to_validate: str=None, *args, debug=False):

if debug:
logger.setLevel(DEBUG)

jsonschema_reg = populate_jsonschema_reg()
# resolver = jsonschema_reg.resolver()

if dir_to_validate is None:
raise RuntimeError(f"pass the directory that needs to validated")

result = []
for dirpath, dirnames, filenames in os.walk(dir_to_validate):
for filename in filenames:
if not filename.endswith(".json"):
logger.debug(f"Skipping {path_to_file} because it does not end in .json")
continue
path_to_file = Path(dirpath) / filename
logger.debug(f"Processing {path_to_file}")
result.append(
validate_json(str(path_to_file), jsonschema_reg, fail_fast=False)
)

passed = [r for r in result if r[1] == ValidationResult.PASSED]
failed = [r for r in result if r[1] == ValidationResult.FAILED]
skipped = [r for r in result if r[1] == ValidationResult.SKIPPED]
print(
f"Validation results: PASSED: {len(passed)} SKIPPED: {len(skipped)} FAILED: {len(failed)}"
)

if len(failed) > 0:
print(failed)
# TODO consolidate how error are raied
raise ValidationError(
message="\n-----\n".join([f"{f[0]}: {str(f[2])}" for f in failed])
)



if __name__ == "__main__":
main(*sys.argv[1:])
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
jsonschema
36 changes: 36 additions & 0 deletions siibra/attr/data/image/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"@type": {
"const": "siibra/attr/data/image/v0.1"
},
"format": {
"$ref": "#/definitions/format"
},
"fetcher": {
"type": "string"
},
"key": {
"type": "string"
}
},
"required": [
"@type",
"format",
"fetcher"
],
"definitions": {
"format": {
"oneOf": [
{
"const": "neuroglancer/precomputed"
},
{
"const": "nii"
}
]
}
},
"additionalProperties": false
}
39 changes: 39 additions & 0 deletions siibra/attr/data/tabular/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"@type": {
"const": "siibra/attr/data/tabular/v0.1"
},
"format": {
"$ref": "#/definitions/format"
},
"parse_options": {
"$ref": "#/definitions/parse_options"
},
"plot_options": {
"$ref": "#/definitions/plot_options"
}
},
"required": [
"@type",
"format"
],
"definitions": {
"format": {
"anyOf": [
{
"const": "csv"
}
]
},
"parse_options": {
"type": "object",
"description": "Passed directly to [pandas.read_csv](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html) as keyword arguments"
},
"plot_options": {
"type": "object",
"description": "Passed directly to [pandas.DataFrame.plot](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.plot.html) as keyword arguments"
}
}
}
11 changes: 11 additions & 0 deletions siibra/attr/data/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"oneOf": [
{
"$ref": "urn:siibra-local:siibra/attr/data/image/v0.1.json"
},
{
"$ref": "urn:siibra-local:siibra/attr/data/tabular/v0.1.json"
}
]
}
21 changes: 21 additions & 0 deletions siibra/attr/desc/ebrains/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"@type": {
"const": "siibra/attr/desc/ebrains/v0.1"
},
"ids": {
"type": "object",
"patternProperties": {
"^.+$": {
"type": "string"
}
}
}
},
"required": [
"ids",
"@type"
]
}
15 changes: 15 additions & 0 deletions siibra/attr/desc/modality/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"allOf": [
{
"$ref": "urn:siibra-local:siibra/attr/util/humanreadable/v0.1.json"
}
],
"properties": {
"@type": {
"const": "siibra/attr/desc/modality/v0.1"
}
},
"required": ["@type"]
}
15 changes: 15 additions & 0 deletions siibra/attr/desc/name/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"allOf": [
{
"$ref": "urn:siibra-local:siibra/attr/util/humanreadable/v0.1.json"
}
],
"properties": {
"@type": {
"const": "siibra/attr/desc/name/v0.1"
}
},
"required": ["@type"]
}
15 changes: 15 additions & 0 deletions siibra/attr/desc/regionspec/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"allOf": [
{
"$ref": "urn:siibra-local:siibra/attr/util/humanreadable/v0.1.json"
}
],
"properties": {
"@type": {
"const": "siibra/attr/desc/regionspec/v0.1"
}
},
"required": ["@type"]
}
15 changes: 15 additions & 0 deletions siibra/attr/desc/speciesspec/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"allOf": [
{
"$ref": "urn:siibra-local:siibra/attr/util/humanreadable/v0.1.json"
}
],
"properties": {
"@type": {
"const": "siibra/attr/desc/speciesspec/v0.1"
}
},
"required": ["@type"]
}
20 changes: 20 additions & 0 deletions siibra/attr/desc/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"oneOf": [
{
"$ref": "urn:siibra-local:siibra/attr/desc/ebrains/v0.1.json"
},
{
"$ref": "urn:siibra-local:siibra/attr/desc/modality/v0.1.json"
},
{
"$ref": "urn:siibra-local:siibra/attr/desc/name/v0.1.json"
},
{
"$ref": "urn:siibra-local:siibra/attr/desc/regionspec/v0.1.json"
},
{
"$ref": "urn:siibra-local:siibra/attr/desc/speciesspec/v0.1.json"
}
]
}
11 changes: 11 additions & 0 deletions siibra/attr/extra/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"description": "Experimental attributes",
"properties": {
"@type": {
"type": "string",
"pattern": "^x-"
}
}
}
12 changes: 12 additions & 0 deletions siibra/attr/loc/layerboundary/v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"@type": {
"const": "siibra/attr/loc/layerboundary/v0.1"
},
"url": {
"type": "string"
}
}
}
Loading

0 comments on commit b573b5a

Please sign in to comment.