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 14, 2019
1 parent dc452ec commit 94505a3
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 34 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

Expand Down Expand Up @@ -1263,3 +1263,27 @@ def test_frozenset_of_integers_and_strings():
assert_equal(str(e), "invalid value in frozenset")
else:
assert False, "Did not raise Invalid"

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"
53 changes: 20 additions & 33 deletions voluptuous/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,20 +191,15 @@ 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):
Expand Down Expand Up @@ -254,11 +249,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 @@ -269,7 +259,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 @@ -280,30 +269,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 @@ -324,8 +311,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 94505a3

Please sign in to comment.