Skip to content

Commit

Permalink
allow a discrminant field in sub-validators
Browse files Browse the repository at this point in the history
  • Loading branch information
ydidwania committed Nov 30, 2018
1 parent e72fd3b commit dc452ec
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions voluptuous/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,29 @@ class _WithSubValidators(object):

def __init__(self, *validators, **kwargs):
self.validators = validators
print('..validators = ', self.validators)
self.msg = kwargs.pop('msg', None)
print('..msg = ', self.msg)
self.discriminant = kwargs.pop('discriminant', None)
print('..discriminant = ', self.discriminant)

def __voluptuous_compile__(self, schema):
print('..schema = ', schema)
self.schema = schema
self._compiled = [
schema._compile(v)
for v in self.validators
]
print('..self._compiled = ', self._compiled)
return self._run

def _run(self, path, value):
if self.discriminant is not None:
self._compiled = [
self.schema._compile(v)
for v in self.discriminant(value, self.validators)
]

return self._exec(self._compiled, value, path)

def __call__(self, v):
Expand Down Expand Up @@ -241,6 +254,11 @@ class Any(_WithSubValidators):

def _exec(self, funcs, v, path=None):
error = None
print ('..self = ', self)
print ('..v = ', v)
print ('..funcs = ', funcs)
print('..path = ', path)

for func in funcs:
try:
if path is None:
Expand All @@ -251,6 +269,7 @@ def _exec(self, funcs, v, path=None):
if error is None or len(e.path) > len(error.path):
error = e
else:
print ('..error = ', error)
if error:
raise error if self.msg is None else AnyInvalid(
self.msg, path=path)
Expand All @@ -261,6 +280,53 @@ def _exec(self, funcs, v, path=None):
# Convenience alias
Or = Any

class Switch(_WithSubValidators):
# """Use the first validated value among those selected by discrminant.

# :param msg: Message to deliver to user if validation fails.
# :param kwargs: All other keyword arguments are passed to the sub-Schema constructors.
# :returns: Return value of the first validator that passes.

# >>> validate = Schema(Any('true', 'false',
# ... All(Any(int, bool), Coerce(bool))))
# >>> validate('true')
# 'true'
# >>> validate(1)
# True
# >>> with raises(MultipleInvalid, "not a valid value"):
# ... validate('moo')

# msg argument is used

# >>> validate = Schema(Any(1, 2, 3, msg="Expected 1 2 or 3"))
# >>> validate(1)
# 1
# >>> with raises(MultipleInvalid, "Expected 1 2 or 3"):
# ... validate(4)
# """

def _exec(self, funcs, v, path=None):
error = None
for func in funcs:
try:
if path is None:
return func(v)
else:
return func(path, v)
except Invalid as e:
if error is None or len(e.path) > len(error.path):
error = e
else:
if error:
raise error if self.msg is None else AnyInvalid(
self.msg, path=path)
raise AnyInvalid(self.msg or 'no valid value found',
path=path)


# # Convenience alias
# Union = Switch


class All(_WithSubValidators):
"""Value must pass all validators.
Expand Down

0 comments on commit dc452ec

Please sign in to comment.