@@ -27,6 +27,7 @@ def passthrough(v):
2727
2828class Validator (object ):
2929 is_required = True
30+ is_conditional = False
3031
3132 def __init__ (self , inner = None ):
3233 if inner is None :
@@ -51,6 +52,35 @@ def __call__(self, value):
5152class Required (Validator ):
5253 pass
5354
55+ class RequiredOnlyIfNot (Required ):
56+ """ This validator will require the key ONLY IF other keys are NOT present in
57+ the payload.
58+
59+ This validator was added because threadless.com payloads use "ShippingMethod" whereas
60+ Artist Shops payloads use "ShippingAccount" and "ShippingMethodId"
61+
62+ An example would be that SomeKey is only required if SomeOtherKey is not present in the payload:
63+ "SomeKey" = RequiredOnlyIfNot(['SomeOtherKey'])
64+
65+ """
66+ is_required = True
67+ is_conditional = True
68+ other_keys = []
69+
70+ def __init__ (self , other_keys = [], inner = None ):
71+ if not isinstance (other_keys , (tuple , list )):
72+ other_keys = [other_keys ]
73+ self .other_keys = other_keys
74+
75+ super (RequiredOnlyIfNot , self ).__init__ (inner )
76+
77+ def __call__ (self , value , d ):
78+ # if all of other_keys are present in the payload,
79+ # then require don't require this field
80+ if all ([key in d .keys () for key in self .other_keys ]):
81+ self .is_required = False
82+
83+ return super (RequiredOnlyIfNot , self ).__call__ (value )
5484
5585class Optional (Validator ):
5686 is_required = False
@@ -81,7 +111,17 @@ def _validate(d, **validation_spec):
81111 validator = validation_spec .pop (k , None )
82112 if validator is None :
83113 raise ValidationError ('parameter "%s" not allowed' % k )
84- d [k ] = validator (v )
114+ if validator .is_conditional : # conditional validators need the whole dictionary to look at other keys
115+ d [k ] = validator (v , d )
116+ else :
117+ d [k ] = validator (v )
118+
119+ # it's possible that there's some conditional validators still in the validation_spec
120+ # because their corresponding key isn't in the payload, so look over them and if all
121+ # of their other_keys are present in the payload, then this conditional validator isn't required
122+ for k , v in validation_spec .items ():
123+ if v .is_conditional and all ([key in d .keys () for key in v .other_keys ]):
124+ v .is_required = False
85125
86126 validation_spec = dict ((k , v ) for k , v in validation_spec .items () if v .is_required )
87127 if validation_spec :
@@ -442,14 +482,17 @@ def new(self, **kwargs):
442482 Overnight = 'ON' ,
443483 )
444484 _validate (kwargs ,
445- OrderId = Required (), # XXX number
446- ShippingMethod = Required (Enum ('FirstClass' , 'PriorityMail' , 'TrackedDelivery' , 'SecondDay' , 'Overnight' )),
447- PackSlip = Optional (Image ),
448- Comments = Optional (Array (Comment )),
449- OrderInfo = Required (OrderInfo ),
450- Cases = Required (Array (Case )),
485+ OrderId = Required (), # XXX number
486+ ShippingMethod = RequiredOnlyIfNot (['ShippingAccount' , 'ShippingMethodId' ], Enum ('FirstClass' , 'PriorityMail' , 'TrackedDelivery' , 'SecondDay' , 'Overnight' )),
487+ ShippingMethodId = RequiredOnlyIfNot (['ShippingMethod' ]),
488+ ShippingAccount = RequiredOnlyIfNot (['ShippingMethod' ]),
489+ PackSlip = Optional (Image ),
490+ Comments = Optional (Array (Comment )),
491+ OrderInfo = Required (OrderInfo ),
492+ Cases = Required (Array (Case )),
451493 )
452- kwargs ['ShippingMethod' ] = shipping_method_map [ kwargs ['ShippingMethod' ] ]
494+ if "ShippingMethod" in kwargs :
495+ kwargs ['ShippingMethod' ] = shipping_method_map [ kwargs ['ShippingMethod' ] ]
453496 # XXX OrderDate (date or datetime?)
454497
455498 request = self ._generate_request (
0 commit comments