Skip to content

Instantly share code, notes, and snippets.

@zetafish
Created September 27, 2017 07:32
Show Gist options
  • Save zetafish/f7a1b93217f7db51352a39d42142ddde to your computer and use it in GitHub Desktop.
Save zetafish/f7a1b93217f7db51352a39d42142ddde to your computer and use it in GitHub Desktop.
validateur.py
from abc import ABCMeta, abstractmethod
from collections import defaultdict
import json
import functools
class Validator(object):
__metaclass__ = ABCMeta
@abstractmethod
def __call__(self, *args, **kwargs):
raise NotImplementedError
class Check(Validator):
def __init__(self, code, f):
self.f = f
self.code = code
def __call__(self, value):
if not self.f(value):
return self.code
def InstanceOf(cls):
return Check('wrong-type', lambda v: isinstance(v, cls))
def MaxSize(n):
return Check('max-size', lambda v: len(v) <= n)
def FreeAdsetName(session, campaign_id):
def available(v):
return False
return Check('duplicate', available)
def FreeTemplateSetName(session, advertiser_id):
def available(v):
return False
return Check('duplicate', available)
class List(Validator):
def __init__(self, validations):
self.validations = validations
def __call__(self, coll):
if not isinstance(coll, list):
return 'wrong-type'
errors = defaultdict(list)
for index, item in enumerate(coll):
e = validate(self.validations, item)
if e:
errors[index].append(e)
return errors
class Dict(Validator):
def __init__(self, validations):
self.validations = validations
def __call__(self, coll):
if not isinstance(coll, dict):
return 'wrong-type'
return validate(self.validations, coll)
def Required(field, dictionary):
return (field in dictionary)
def validate(validation, dictionary):
errors = defaultdict(list)
for key, validations in validation.items():
if Required in validations:
if not Required(key, dictionary):
errors[key] = ['missing']
continue
if key not in dictionary:
continue
validations = [x for x in validations if x != Required]
for v in validations:
e = v(dictionary[key])
if e:
errors[key].append(e)
return errors
# def templateset_create():
# rules = {
# 'name': [Required,
# MaxSize(70),
# FreeTemplateSetName(session, advertiser_id)]
# }
import pytest
from validateur import Required, validate, InstanceOf, List, Dict,\
MaxSize
def test_missing_required_field():
schema = {'name': [Required]}
v = validate(schema, {})
assert v == {'name': ['missing']}
def test_required_as_list():
schema = {'name': [Required]}
v = validate(schema, {})
assert v == {'name': ['missing']}
def test_ignore_unknown_fields():
schema = {'name': [Required]}
v = validate(schema, {'name': 'X', 'age': 1})
assert v == {}
def test_missing_optional_field():
schema = {'name': [InstanceOf(basestring)]}
v = validate(schema, {})
assert v == {}
def test_instance_of():
schema = {'name': [InstanceOf(basestring)]}
v = validate(schema, {'name': 3.1})
assert v == {'name': ['wrong-type']}
def test_multiple_errors():
schema = {'name': [InstanceOf(int),
InstanceOf(float)]}
v = validate(schema, {'name': 'x'})
assert v == {'name': ['wrong-type', 'wrong-type']}
def test_list():
schema = {'places': [Required,
List({'name': [Required,
InstanceOf(basestring)]})]}
v = validate(schema, {})
assert v == {'places': ['missing']}
v = validate(schema, {'places': [{},
{'name': 'x'},
{'name': 5}]})
assert v == {'places': [{0: [{'name': ['missing']}],
2: [{'name': ['wrong-type']}]}]}
def test_dict():
schema = {'places': [Required,
Dict({'name': [Required]})]}
v = validate(schema, {'places': {}})
assert v == {'places': [{'name': ['missing']}]}
@pytest.parameterize('doc,v',[
[{'name': 'abc'}, {}],
[{'name': 'abcd'}, {'max-size'}]
])
def test_max_size(doc, v):
schema = {'name': [Required, MaxSize(3)]}
assert validate(schema, doc) == v
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment