-
Notifications
You must be signed in to change notification settings - Fork 1
/
validol2.py
197 lines (175 loc) · 5.41 KB
/
validol2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# -*- coding: utf-8 -*-
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# Copyright (C) 2010 Konstantin Merenkov <[email protected]>
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
from itertools import izip, cycle
__version__ = '0.1'
__author__ = "Konstantin Merenkov <[email protected]>"
class ValidationError(Exception):
def __init__(self, message):
super(ValidationError, self).__init__(message)
def validate(scheme, obj):
"""
>>> validate(str, "foo")
'foo'
>>> validate(int, 10)
10
>>> validate(int, "10")
10
>>> validate([int], ["10"])
[10]
>>> from itertools import cycle
>>> validate(cycle([int]), xrange(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> validate({"user": str,
... "blocked": boolean,
... "email": str},
... {"user": "john",
... "blocked": "false",
... "email": "[email protected]"}
... )
{'blocked': False, 'email': '[email protected]', 'user': 'john'}
>>> validate(any_of([10, 20, 30]), 10)
10
>>> try:
... validate(any_of([10, 20, 30]), 40)
... except ValidationError, e:
... print str(e)
Failed any_of validation: 40
>>> validate(in_range(0, 10), 5)
5
>>> try:
... validate(in_range(0, 10), 15)
... except ValidationError, e:
... print str(e)
Failed in_range validation: 15
>>> validate({optional("foo"): "bar"}, {})
{}
"""
if callable(scheme):
return scheme(obj)
elif hasattr(scheme, 'items') and hasattr(obj, 'items'):
return validate_dict(scheme, obj)
elif hasattr(scheme, '__iter__') and hasattr(obj, '__iter__'):
return validate_iterable(scheme, obj)
elif scheme == obj:
return obj
raise ValidationError("Don't know how to validate %s against %s" % (obj, scheme))
# special validators
def boolean(obj):
if type(obj) is bool:
return obj
ol = str(obj).lower()
if ol in ["1", "true"]:
return True
elif ol in ["0", "false"]:
return False
raise ValidationError("Failed bool validation: %s" % (obj,))
def in_range(start, end):
def _in_range(obj):
ok = False
try:
ok = start <= float(obj) <= end
except Exception:
pass
if not ok:
raise ValidationError("Failed in_range validation: %s" % (obj,))
return obj
return _in_range
def lt(value):
def _lt(obj):
ok = False
try:
ok = type(value)(obj) < value
except Exception:
pass
if not ok:
raise ValidationError("Failed gt validation: %s" % (obj,))
return type(value)(obj)
return _lt
def gt(value):
def _gt(obj):
ok = False
try:
ok = type(value)(obj) > value
except Exception:
pass
if not ok:
raise ValidationError("Failed gt validation: %s" % (obj,))
return type(value)(obj)
return _gt
def str_strict(obj):
if isinstance(obj, basestring):
return obj
raise ValidationError("Failed str_strict validation: %s" % (obj,))
def any_of(xs):
def _any_of(obj):
for x in xs:
try:
return validate(x, obj)
except:
pass
raise ValidationError("Failed any_of validation: %s" % (obj,))
return result
return _any_of
def optional(scheme):
def _optional(obj):
return validate(scheme, obj)
return _optional
def regexp(expr):
def _regexp(obj):
if expr.match(obj):
return obj
raise ValidationError("Failed regexp validation: %s" % (obj,))
return _regexp
# actual implementation
def validate_iterable(scheme, obj):
if type(scheme) is set and type(obj) is set:
if scheme == obj:
return obj
raise ValidationError("Failed iterable validation: %s" % (obj,))
else:
results = []
t = type(obj)
for s, o in izip(scheme, obj):
try:
results.append(validate(s, o))
except (TypeError, ValueError):
raise ValidationError("Failed iterable validation: %s" % (obj,))
try:
return t(results)
except Exception:
return results
def validate_dict(scheme, obj):
validated = {}
scheme_dict = dict(scheme)
for okey, ovalue in obj.items():
ok = False
for skey, svalue in scheme_dict.items():
try:
k = validate(skey, okey)
v = validate(svalue, ovalue)
validated[k] = v
ok = True
scheme_dict.pop(skey)
break
except Exception:
pass
if not ok:
raise ValidationError("Failed dict validation: %s" % ((okey, ovalue),))
for s in scheme_dict:
if not (callable(s) and getattr(s, "func_name", None) == '_optional'):
raise ValidationError("Failed dict validation: %s" % (obj,))
return validated
if __name__ == '__main__':
import doctest
doctest.testmod()