Skip to content

Instantly share code, notes, and snippets.

@timtadh
Created August 15, 2012 21:36
Show Gist options
  • Save timtadh/3363913 to your computer and use it in GitHub Desktop.
Save timtadh/3363913 to your computer and use it in GitHub Desktop.
Validate Json
*.pyc
*.swp
env
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author: Tim Henderson
#Email: [email protected]
#Copyright (C) 2012 All Rights Reserved
#For licensing see the LICENSE file in the top level directory.
class Checker(object):
def __init__(self, checker):
self.checker = checker
def __call__(self, data):
return self.checker(data)
def __and__(a, b):
if not isinstance(b, Checker): return NotImplemented
def a_and_b(data):
a_ok, a_err = a(data)
b_ok, b_err = b(data)
if a_err is None: a_err = list()
if b_err is None: b_err = list()
assert isinstance(a_ok, bool)
assert isinstance(b_ok, bool)
return (a_ok and b_ok), (a_err + b_err)
return Checker(a_and_b)
def __or__(a, b):
if not isinstance(b, Checker): return NotImplemented
def a_or_b(data):
a_ok, a_err = a(data)
b_ok, b_err = b(data)
if a_err is None: a_err = list()
if b_err is None: b_err = list()
if a_ok: return True, list()
if b_ok: return True, list()
return False, (a_err + b_err)
return Checker(a_or_b)
def checker(f):
def decorator(*args, **kwargs):
def wrapper(data):
return f(data, *args, **kwargs)
return Checker(wrapper)
return decorator
@checker
def value_checker(data, value):
if data != value:
return False, [
"'%s' is not equal to '%s'" % (str(data), str(value))]
return True, list()
@checker
def type_checker(data, type):
if not isinstance(data, type):
return False, [
"Object, '%s', not of type %s" % (repr(data), str(type))]
return True, list()
@checker
def length_checker(data, length):
if not hasattr(data, '__len__'):
return False, ["Object, '%s', doesn't have a length" % (repr(data))]
if len(data) != length:
return False, [
"Sequence, '%s', is not %d items long" % (str(data), int(length))]
return True, list()
@checker
def max_length_checker(data, length):
if not hasattr(data, '__len__'):
return False, ["Object, '%s', doesn't have a length" % (repr(data))]
if len(data) > length:
return False, [
"Sequence, '%s', greater than %d items long" % (str(data), int(length))]
return True, list()
@checker
def min_length_checker(data, length):
if not hasattr(data, '__len__'):
return False, ["Object, '%s', doesn't have a length" % (repr(data))]
if len(data) < length:
return False, [
"Sequence, '%s', less than %d items long" % (str(data), int(length))]
return True, list()
def validate_json(schema, json_data):
''' Assert that d matches the schema
@param d = the dictionary
@param allow_none = allow Nones in d '''
errors = list()
def proc(v1, v2):
'''process 2 values assert they are of the same type'''
#print 'proc>', v1, v2
if isinstance(v1, dict):
return procdict(v1, v2)
elif isinstance(v1, list):
return proclist(v1, v2)
else:
validator = v1
if not hasattr(validator, '__call__'):
errors.append(
"Expected schema item to be a callable got %s" % str(v1))
return False
ret = validator(v2)
if not isinstance(ret, tuple):
errors.append(
"Expected item validator to return a tuple got %s" %
str(ret))
return False
if len(ret) != 2:
errors.append(
"Expected item validator to return 2 items got %s" %
str(ret))
return False
ok, err = ret
#print ok, err
if not ok:
errors.extend(err)
return False
return True
def proclist(t, d):
'''process a list type'''
if not isinstance(d, list):
msg = ("Expected a <type 'list'> got %s" % type(d))
errors.append(err)
return False
if len(t) != 1:
errors.append(
"Expected schema item to contain one element got %s" % str(t))
return False
v1 = t[0]
acc = True
for v2 in d:
#print v1, v2
r = proc(v1, v2)
acc = acc and r
return acc
def procdict(t, d):
'''process a dictionary type'''
if not isinstance(d, dict):
raise AssertionError, "Expected a <type 'dict'> got %s, '%s'"\
% (type(d), str(d))
tkeys = set(t.keys());
dkeys = set(d.keys());
acc = True
if '__undefinedkeys__' in tkeys:
v1 = t['__undefinedkeys__']
for v2 in d.values():
r = proc(v1, v2)
acc = acc and r
else:
for k in tkeys:
if k not in dkeys:
msg = (
'Expected name, "%s", in %s'
) % (str(k), str(d))
errors.append(msg)
acc = False
for k in dkeys:
if k not in tkeys:
msg = (
'Unexpected name, "%s". The name must be in %s'
) % (str(k), str(tkeys))
errors.append(msg)
acc = False
else:
v1 = t[k]
v2 = d[k]
r = proc(v1, v2)
acc = acc and r
return acc
ok = proc(schema, json_data)
return ok, errors
nose==1.1.2
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author: Tim Henderson
#Email: [email protected]
#Copyright (C) 2012 All Rights Reserved
#For licensing see the LICENSE file in the top level directory.
from json_validator import validate_json
import json_validator as vlib
def test_one_item_valid():
schema = {
"name" : vlib.value_checker("value")
}
ok, errors = validate_json(schema, {"name":"value"})
assert ok
assert len(errors) == 0
def test_one_item_invalid():
schema = {
"name" :
lambda b: (
(True, list())
if (b == 'value')
else (False, ["'%s' is not equal to 'value'" % b]))
}
ok, errors = validate_json(schema, {"name":"vsdalue"})
assert not ok
assert len(errors) == 1
assert errors[0] == "'vsdalue' is not equal to 'value'"
def test_one_item_no_validator():
schema = {
"name" : "value"
}
ok, errors = validate_json(schema, {"name":"vsdalue"})
assert not ok
assert len(errors) == 1
assert errors[0] == 'Expected schema item to be a callable got value'
def test_one_item_validator_returns_one_item():
schema = {
"name" :
lambda b: (True if (b == 'value') else False)
}
ok, errors = validate_json(schema, {"name":"vsdalue"})
assert not ok
assert len(errors) == 1
assert errors[0] == 'Expected item validator to return a tuple got False'
def test_one_item_validator_returns_three_items():
schema = {
"name" :
lambda b: ((True, None, None) if (b == 'value') else (False, "asdf",
"adfs"))
}
ok, errors = validate_json(schema, {"name":"vsdalue"})
assert not ok
assert len(errors) == 1
assert errors[0] == "Expected item validator to return 2 items got (False, 'asdf', 'adfs')"
def test_list_one_item_valid():
schema = [
{
"name" : vlib.value_checker("value")
}
]
ok, errors = validate_json(schema, [{"name":"value"}])
assert ok
assert len(errors) == 0
def test_list_three_items_valid():
schema = [
{
"name" : vlib.value_checker("value")
}
]
ok, errors = validate_json(schema, [{"name":"value"}, {"name":"value"},
{"name":"value"}])
assert ok
assert len(errors) == 0
def test_list_three_items_invalid():
schema = [
{
"name" : vlib.value_checker("value")
}
]
ok, errors = validate_json(schema, [{"name":"vaque"}, {"name":"valqe"},
{"name":"vqlue"}])
assert not ok
assert len(errors) == 3
assert errors == ["'vaque' is not equal to 'value'",
"'valqe' is not equal to 'value'",
"'vqlue' is not equal to 'value'"]
def test_list_three_bare_items_valid():
schema = [
vlib.value_checker("value")
]
ok, errors = validate_json(schema, ["value", "value", "value"])
assert ok
assert len(errors) == 0
def test_length_checker():
schema = [
vlib.length_checker(5)
]
ok, errors = validate_json(schema, ["value", "value", "value"])
assert ok
assert len(errors) == 0
def test_type_checker():
schema = [
vlib.type_checker(basestring)
]
ok, errors = validate_json(schema, ["value", "value", "value"])
assert ok
assert len(errors) == 0
def test_max_length_checker():
schema = [
vlib.max_length_checker(5)
]
ok, errors = validate_json(schema, ["value", "value", "value"])
assert ok
assert len(errors) == 0
def test_max_length_checker_under():
schema = [
vlib.max_length_checker(5)
]
ok, errors = validate_json(schema, ["valu"])
assert ok
assert len(errors) == 0
def test_max_length_checker_over():
schema = [
vlib.max_length_checker(5)
]
ok, errors = validate_json(schema, ["values"])
assert not ok
assert len(errors) == 1
assert errors == ["Sequence, 'values', greater than 5 items long"]
def test_min_length_checker():
schema = [
vlib.min_length_checker(5)
]
ok, errors = validate_json(schema, ["value", "value", "value"])
assert ok
assert len(errors) == 0
def test_min_length_checker_under():
schema = [
vlib.min_length_checker(5)
]
ok, errors = validate_json(schema, ["valu"])
assert not ok
assert len(errors) == 1
assert errors == ["Sequence, 'valu', less than 5 items long"]
def test_min_length_checker_over():
schema = [
vlib.min_length_checker(5)
]
ok, errors = validate_json(schema, ["values"])
assert ok
assert len(errors) == 0
def test_type_or_type_checker():
schema = [
vlib.type_checker(int) | vlib.type_checker(float)
]
ok, errors = validate_json(schema, ["value", "value", "value"])
assert not ok
assert len(errors) == 6
def test_type_and_type_checker():
schema = [
vlib.type_checker(int) & vlib.type_checker(float)
]
ok, errors = validate_json(schema, ["value", "value", "value"])
assert not ok
assert len(errors) == 6
assert errors == [
"Object, ''value'', not of type <type 'int'>",
"Object, ''value'', not of type <type 'float'>",
"Object, ''value'', not of type <type 'int'>",
"Object, ''value'', not of type <type 'float'>",
"Object, ''value'', not of type <type 'int'>",
"Object, ''value'', not of type <type 'float'>"]
def test_type_and_length_checker():
schema = [
vlib.type_checker(basestring) & vlib.length_checker(4)
]
ok, errors = validate_json(schema, ["value"])
assert not ok
assert len(errors) == 1
assert errors == ["Sequence, 'value', is not 4 items long"]
def test_type_or_length_checker():
schema = [
vlib.type_checker(basestring) | vlib.length_checker(4)
]
ok, errors = validate_json(schema, ["value"])
assert ok
assert len(errors) == 0
def test_type_and_length_checker_both_true():
schema = [
vlib.type_checker(basestring) & vlib.length_checker(5)
]
ok, errors = validate_json(schema, ["value"])
assert ok
assert len(errors) == 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment