Skip to content

Commit

Permalink
Add test for Union type
Browse files Browse the repository at this point in the history
  • Loading branch information
ydidwania committed Aug 15, 2019
1 parent 9718199 commit 42240bc
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 30 deletions.
26 changes: 25 additions & 1 deletion voluptuous/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Replace, Range, Coerce, All, Any, Length, FqdnUrl, ALLOW_EXTRA, PREVENT_EXTRA,
validate, ExactSequence, Equal, Unordered, Number, Maybe, Datetime, Date,
Contains, Marker, IsDir, IsFile, PathExists, SomeOf, TooManyValid, Self,
raises)
raises, Union)
from voluptuous.humanize import humanize_error
from voluptuous.util import u, Capitalize, Lower, Strip, Title, Upper

Expand Down Expand Up @@ -1406,3 +1406,27 @@ def test_exclusive():
"two or more values in the same group of exclusion 'stuff' @ data[<stuff>]")
else:
assert False, "Did not raise Invalid for multiple values in Exclusive group"

def test_any_with_discriminant():
schema = Schema({
'implementation': Union({
'type': 'A',
'a-value': str,
}, {
'type': 'B',
'b-value': int,
}, {
'type': 'C',
'c-value': bool,
}, discriminant=lambda value, alternatives: filter(lambda v : v['type'] == value['type'], alternatives))
})
try:
schema({
'implementation': {
'type': 'C',
'c-value': None,}
})
except MultipleInvalid as e:
assert_equal(str(e),'expected bool for dictionary value @ data[\'implementation\'][\'c-value\']')
else:
assert False, "Did not raise correct Invalid"
50 changes: 21 additions & 29 deletions voluptuous/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,13 @@ class _WithSubValidators(object):

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

def __voluptuous_compile__(self, schema):
self._compiled = []
self.schema = schema
for v in self.validators:
schema.required = self.required
self._compiled.append(schema._compile(v))
Expand Down Expand Up @@ -250,11 +250,6 @@ 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 @@ -265,7 +260,6 @@ 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 @@ -276,30 +270,28 @@ def _exec(self, funcs, v, path=None):
# Convenience alias
Or = Any

class Switch(_WithSubValidators):
# """Use the first validated value among those selected by discrminant.
class Union(_WithSubValidators):
"""Use the first validated value among those selected by discrminant.
:param msg: Message to deliver to user if validation fails.
:param discriminant: Function to filter the values
:param kwargs: All other keyword arguments are passed to the sub-Schema constructors.
:returns: Return value of the first validator that passes.
# :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.
discriminant(value, validators) is invoked in execution.
# >>> 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')
>>> validate = Schema(Union({'type':'a', 'a_val':'1'},{'type':'b', 'b_val':'2'},
... discriminant=lambda val, alt: filter(
... lambda v : v['type'] == val['type'] , alt)))
>>> validate({'type':'a', 'val':'1'})
True
>>> with raises(MultipleInvalid, "not a valid value for dictionary value @ data['b_val']"):
... validate({'type':'b', 'a_val':'5'})
# msg argument is used
```discriminant({'type':'b', 'a_val':'5'}, [{'type':'a', 'a_val':'1'},{'type':'b', 'b_val':'2'}])``` is invoked
# >>> 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)
# """
Without the discriminant, the exception would be "extra keys not allowed @ data['b_val']"
"""

def _exec(self, funcs, v, path=None):
error = None
Expand All @@ -320,8 +312,8 @@ def _exec(self, funcs, v, path=None):
path=path)


# # Convenience alias
# Union = Switch
# Convenience alias
Switch = Union


class All(_WithSubValidators):
Expand Down

0 comments on commit 42240bc

Please sign in to comment.