Fix nested jsonschema construction
This commit is contained in:
parent
665b1d8c37
commit
7cdb7f1843
@ -1,4 +1,4 @@
|
||||
from jsonschema import validate, ValidationError
|
||||
from jsonschema import validate, ValidationError, SchemaError
|
||||
|
||||
|
||||
def schema_input_type(schema):
|
||||
@ -13,38 +13,64 @@ def schema_input_type(schema):
|
||||
return 'simple'
|
||||
|
||||
|
||||
def construct_jsonschema(schema):
|
||||
def _construct_jsonschema(schema, definition_base=''):
|
||||
"""Construct jsonschema from our metadata input schema.
|
||||
|
||||
:param schema:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if schema == 'str':
|
||||
return {'type': 'string'}
|
||||
return {'type': 'string'}, {}
|
||||
|
||||
if schema == 'str!':
|
||||
return {'type': 'string', 'minLength': 1}
|
||||
return {'type': 'string', 'minLength': 1}, {}
|
||||
|
||||
if schema == 'int' or schema == 'int!':
|
||||
return {'type': 'number'}
|
||||
return {'type': 'number'}, {}
|
||||
|
||||
if isinstance(schema, list):
|
||||
items, definitions = _construct_jsonschema(schema[0], definition_base=definition_base)
|
||||
|
||||
return {
|
||||
'type': 'array',
|
||||
'items': construct_jsonschema(schema[0]),
|
||||
}
|
||||
'items': items,
|
||||
}, definitions
|
||||
|
||||
if isinstance(schema, dict):
|
||||
return {
|
||||
properties = {}
|
||||
definitions = {}
|
||||
|
||||
for k, v in schema.items():
|
||||
if isinstance(v, dict) or isinstance(v, list):
|
||||
key = '{}_{}'.format(definition_base, k)
|
||||
properties[k] = {'$ref': '#/definitions/{}'.format(key)}
|
||||
definitions[key], new_definitions = _construct_jsonschema(v, definition_base=key)
|
||||
else:
|
||||
properties[k], new_definitions = _construct_jsonschema(v, definition_base=definition_base)
|
||||
|
||||
definitions.update(new_definitions)
|
||||
|
||||
required = [k for k, v in schema.items() if
|
||||
isinstance(v, basestring) and v.endswith('!')]
|
||||
|
||||
ret = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
k: construct_jsonschema(v) for k, v in schema.items()
|
||||
},
|
||||
'required': [k for k, v in schema.items() if
|
||||
isinstance(v, basestring) and v.endswith('!')],
|
||||
'properties': properties,
|
||||
}
|
||||
|
||||
if required:
|
||||
ret['required'] = required
|
||||
|
||||
return ret, definitions
|
||||
|
||||
|
||||
def construct_jsonschema(schema):
|
||||
jsonschema, definitions = _construct_jsonschema(schema)
|
||||
|
||||
jsonschema['definitions'] = definitions
|
||||
|
||||
return jsonschema
|
||||
|
||||
|
||||
def validate_input(value, jsonschema=None, schema=None):
|
||||
"""Validate single input according to schema.
|
||||
@ -54,13 +80,16 @@ def validate_input(value, jsonschema=None, schema=None):
|
||||
:param schema: Our custom, simplified schema
|
||||
:return: list with errors
|
||||
"""
|
||||
if jsonschema is None:
|
||||
jsonschema = construct_jsonschema(schema)
|
||||
try:
|
||||
if jsonschema:
|
||||
validate(value, jsonschema)
|
||||
else:
|
||||
validate(value, construct_jsonschema(schema))
|
||||
validate(value, jsonschema)
|
||||
except ValidationError as e:
|
||||
return [e.message]
|
||||
except:
|
||||
print 'jsonschema', jsonschema
|
||||
print 'value', value
|
||||
raise
|
||||
|
||||
|
||||
def validate_resource(r):
|
||||
|
@ -102,5 +102,73 @@ input:
|
||||
errors = sv.validate_resource(r)
|
||||
self.assertListEqual(errors.keys(), ['values'])
|
||||
|
||||
def test_complex_input(self):
|
||||
sample_meta_dir = self.make_resource_meta("""
|
||||
id: sample
|
||||
handler: ansible
|
||||
version: 1.0.0
|
||||
input:
|
||||
values:
|
||||
schema: {l: [{a: int}]}
|
||||
value: {l: [{a: 1}]}
|
||||
""")
|
||||
|
||||
r = self.create_resource(
|
||||
'r', sample_meta_dir, {
|
||||
'values': {
|
||||
'l': [{'a': 1}],
|
||||
}
|
||||
}
|
||||
)
|
||||
errors = sv.validate_resource(r)
|
||||
self.assertEqual(errors, {})
|
||||
|
||||
r.update({
|
||||
'values': {
|
||||
'l': [{'a': 'x'}],
|
||||
}
|
||||
})
|
||||
errors = sv.validate_resource(r)
|
||||
self.assertListEqual(errors.keys(), ['values'])
|
||||
|
||||
r.update({'values': {'l': [{'a': 1, 'c': 3}]}})
|
||||
errors = sv.validate_resource(r)
|
||||
self.assertEqual(errors, {})
|
||||
|
||||
def test_more_complex_input(self):
|
||||
sample_meta_dir = self.make_resource_meta("""
|
||||
id: sample
|
||||
handler: ansible
|
||||
version: 1.0.0
|
||||
input:
|
||||
values:
|
||||
schema: {l: [{a: int}], d: {x: [int]}}
|
||||
value: {l: [{a: 1}], d: {x: [1, 2]}}
|
||||
""")
|
||||
|
||||
r = self.create_resource(
|
||||
'r', sample_meta_dir, {
|
||||
'values': {
|
||||
'l': [{'a': 1}],
|
||||
'd': {'x': [1, 2]}
|
||||
}
|
||||
}
|
||||
)
|
||||
errors = sv.validate_resource(r)
|
||||
self.assertEqual(errors, {})
|
||||
|
||||
r.update({
|
||||
'values': {
|
||||
'l': [{'a': 1}],
|
||||
'd': []
|
||||
}
|
||||
})
|
||||
errors = sv.validate_resource(r)
|
||||
self.assertListEqual(errors.keys(), ['values'])
|
||||
|
||||
r.update({'values': {'a': 1, 'c': 3}})
|
||||
errors = sv.validate_resource(r)
|
||||
self.assertEqual(errors, {})
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user