@@ -23,10 +23,44 @@ def uniq(seq):
23
23
return '\n ' .join (a )
24
24
25
25
26
+ def handle_default (init ):
27
+
28
+ """Add default handling to the __init__ method
29
+ Meant to be used as a decorator"""
30
+
31
+ def init2 (self , * args , ** kw ):
32
+ # get default from the ``default`` keyword argument
33
+ if 'default' in kw :
34
+ self .default = kw ['default' ]
35
+ del (kw ['default' ])
36
+ # if auto_default is set, get default from first argument
37
+ elif hasattr (self , 'auto_default' ) and self .auto_default :
38
+ self .default = args [0 ]
39
+ if hasattr (self .default , 'default' ):
40
+ self .default = self .default .default
41
+ elif issubclass (type (self .default ), type ):
42
+ self .default = self .default ()
43
+ elif hasattr (self .default , 'validate' ):
44
+ # e.g. {Optional(Use(int)): ...}
45
+ delattr (self , 'default' )
46
+ # normal init
47
+ init (self , * args , ** kw )
48
+ # validate default
49
+ if hasattr (self , 'default' ):
50
+ try :
51
+ self .default = self .validate (self .default )
52
+ except SchemaError :
53
+ raise ValueError ('%s does not validate its default: %s' % (
54
+ self , self .default ))
55
+ return init2
56
+
57
+
26
58
class And (object ):
27
59
60
+ @handle_default
28
61
def __init__ (self , * args , ** kw ):
29
62
self ._args = args
63
+ assert len (args )
30
64
assert list (kw ) in (['error' ], [])
31
65
self ._error = kw .get ('error' )
32
66
@@ -55,6 +89,7 @@ def validate(self, data):
55
89
56
90
class Use (object ):
57
91
92
+ @handle_default
58
93
def __init__ (self , callable_ , error = None ):
59
94
assert callable (callable_ )
60
95
self ._callable = callable_
@@ -91,6 +126,7 @@ def priority(s):
91
126
92
127
class Schema (object ):
93
128
129
+ @handle_default
94
130
def __init__ (self , schema , error = None ):
95
131
self ._schema = schema
96
132
self ._error = error
@@ -136,15 +172,22 @@ def validate(self, data):
136
172
if x is not None :
137
173
raise SchemaError (['invalid value for key %r' % key ] +
138
174
x .autos , [e ] + x .errors )
139
- coverage = set (k for k in coverage if type (k ) is not Optional )
140
175
required = set (k for k in s if type (k ) is not Optional )
141
- if coverage != required :
176
+ # missed keys
177
+ if not required .issubset (coverage ):
142
178
raise SchemaError ('missed keys %r' % (required - coverage ), e )
179
+ # wrong keys
143
180
if len (new ) != len (data ):
144
181
wrong_keys = set (data .keys ()) - set (new .keys ())
145
182
s_wrong_keys = ', ' .join ('%r' % k for k in sorted (wrong_keys ))
146
183
raise SchemaError ('wrong keys %s in %r' % (s_wrong_keys , data ),
147
184
e )
185
+ # default for optional keys
186
+ for k in set (s ) - required - coverage :
187
+ try :
188
+ new [k .default ] = s [k ].default
189
+ except AttributeError :
190
+ pass
148
191
return new
149
192
if hasattr (s , 'validate' ):
150
193
try :
@@ -179,3 +222,5 @@ def validate(self, data):
179
222
class Optional (Schema ):
180
223
181
224
"""Marker for an optional part of Schema."""
225
+
226
+ auto_default = True
0 commit comments