Skip to content
Permalink
Browse files

Add semantic-versioning to JSON schemas (#472)

- JSON schemas are now versioned
- workspace.json explicitly requires a version attribute as this is the JSON document that gets preserved/passed around (model.json and measurement.json do not explicitly require it)
- utils.validate and utils.load_schema are updated to handle versioning as well
  • Loading branch information...
kratsg authored and matthewfeickert committed May 8, 2019
1 parent f96d6c9 commit ca1d373cf6262ec1c594ad838a8fcf8e444b660c
@@ -176,9 +176,10 @@ class Model(object):
def __init__(self, spec, **config_kwargs):
self.spec = copy.deepcopy(spec) # may get modified by config
self.schema = config_kwargs.pop('schema', 'model.json')
self.version = config_kwargs.pop('version', None)
# run jsonschema validation of input specification against the (provided) schema
log.info("Validating spec against schema: {0:s}".format(self.schema))
utils.validate(self.spec, self.schema)
utils.validate(self.spec, self.schema, version=self.version)
# build up our representation of the specification
self.config = _ModelConfig(self.spec, **config_kwargs)

@@ -483,9 +484,10 @@ def __init__(self, spec, **config_kwargs):
self.spec = spec

self.schema = config_kwargs.pop('schema', 'workspace.json')
self.version = config_kwargs.pop('version', None)
# run jsonschema validation of input specification against the (provided) schema
log.info("Validating spec against schema: {0:s}".format(self.schema))
utils.validate(self.spec, self.schema)
utils.validate(self.spec, self.schema, version=self.version)

self.measurement_names = []
for measurement in self.spec.get('measurements', []):
@@ -512,7 +514,7 @@ def get_measurement(self, **config_kwargs):
"""
m = self._get_measurement(**config_kwargs)
utils.validate(m, 'measurement.json')
utils.validate(m, 'measurement.json', self.version)
return m

def _get_measurement(self, **config_kwargs):
@@ -270,6 +270,7 @@ def parse(configfile, rootdir, track_progress=False):
'measurements': process_measurements(toplvl),
'channels': [{'name': k, 'samples': v['samples']} for k, v in channels.items()],
'data': {k: v['data'] for k, v in channels.items()},
'version': utils.SCHEMA_VERSION,
}

utils.validate(result, 'workspace.json')
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "https://diana-hep.org/pyhf/schemas/defs.json",
"$id": "https://diana-hep.org/pyhf/schemas/1.0.0/defs.json",
"definitions": {
"measurement": {
"type": "object",
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "https://diana-hep.org/pyhf/schemas/measurement.json",
"$id": "https://diana-hep.org/pyhf/schemas/1.0.0/measurement.json",
"type": "object",
"$ref": "defs.json#/definitions/measurement"
}
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "https://diana-hep.org/pyhf/schemas/model.json",
"$id": "https://diana-hep.org/pyhf/schemas/1.0.0/model.json",
"type": "object",
"properties": {
"channels": { "type": "array", "items": {"$ref": "defs.json#/definitions/channel"} },
@@ -1,12 +1,13 @@
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "https://diana-hep.org/pyhf/schemas/workspace.json",
"$id": "https://diana-hep.org/pyhf/schemas/1.0.0/workspace.json",
"type": "object",
"properties": {
"channels": { "type": "array", "items": {"$ref": "defs.json#/definitions/channel"} },
"measurements": { "type": "array", "items": {"$ref": "defs.json#/definitions/measurement"} },
"data": { "type": "object" }
"data": { "type": "object" },
"version": { "const": "1.0.0" }
},
"additionalProperties": false,
"required": ["channels", "measurements", "data"]
"required": ["channels", "measurements", "data", "version"]
}
@@ -10,16 +10,23 @@

SCHEMA_CACHE = {}
SCHEMA_BASE = "https://diana-hep.org/pyhf/schemas/"
SCHEMA_VERSION = '1.0.0'


def load_schema(schema_id):
def load_schema(schema_id, version=None):
global SCHEMA_CACHE
if not version:
version = SCHEMA_VERSION
try:
return SCHEMA_CACHE["{0:s}{1:s}".format(SCHEMA_BASE, schema_id)]
return SCHEMA_CACHE[
"{0:s}{1:s}".format(SCHEMA_BASE, os.path.join(version, schema_id))
]
except KeyError:
pass

path = pkg_resources.resource_filename(__name__, os.path.join('schemas', schema_id))
path = pkg_resources.resource_filename(
__name__, os.path.join('schemas', version, schema_id)
)
with open(path) as json_schema:
schema = json.load(json_schema)
SCHEMA_CACHE[schema['$id']] = schema
@@ -30,8 +37,8 @@ def load_schema(schema_id):
load_schema('defs.json')


def validate(spec, schema_name):
schema = load_schema(schema_name)
def validate(spec, schema_name, version=None):
schema = load_schema(schema_name, version=version)
try:
resolver = jsonschema.RefResolver(
base_uri='file://{0:s}'.format(

0 comments on commit ca1d373

Please sign in to comment.
You can’t perform that action at this time.