back to OpenHands summary
OpenHands: voluptuous
Pytest Summary for test tests
status |
count |
failed |
94 |
passed |
55 |
total |
149 |
collected |
149 |
Failed pytests:
tests.md::tests.md
tests.md::tests.md
010
011 It should show the exact index and container type, in this case a list
012 value:
013
014 >>> try:
015 ... schema(['one', 'two'])
016 ... raise AssertionError('MultipleInvalid not raised')
017 ... except MultipleInvalid as e:
018 ... exc = e
019 >>> str(exc) == 'expected a dictionary @ data[1]'
Expected:
True
Got:
False
/testbed/voluptuous/tests/tests.md:19: DocTestFailure
tests.py::test_extra_with_required
def test_extra_with_required():
"""Verify that Required does not break Extra."""
schema = Schema({Required('toaster'): str, Extra: object})
> r = schema({'toaster': 'blue', 'another_valid_key': 'another_valid_value'})
voluptuous/tests/tests.py:53:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = []
data = {'another_valid_key': 'another_valid_value', 'toaster': 'blue'}
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: extra keys not allowed @ data['another_valid_key']
voluptuous/schema_builder.py:215: MultipleInvalid
tests.py::test_iterate_candidates
tests.py::test_iterate_candidates
def test_iterate_candidates():
"""Verify that the order for iterating over mapping candidates is right."""
schema = {
"toaster": str,
Extra: object,
}
# toaster should be first.
from voluptuous.schema_builder import _iterate_mapping_candidates
> assert _iterate_mapping_candidates(schema)[0][0] == 'toaster'
E AssertionError: assert == 'toaster'
voluptuous/tests/tests.py:66: AssertionError
tests.py::test_in
tests.py::test_in
def test_in():
"""Verify that In works."""
schema = Schema({"color": In(frozenset(["red", "blue", "yellow"]))})
schema({"color": "blue"})
with pytest.raises(
MultipleInvalid,
match=r"value must be one of \['blue', 'red', 'yellow'\] for dictionary value @ data\['color'\]",
) as ctx:
> schema({"color": "orange"})
voluptuous/tests/tests.py:77:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {'color': 'orange'}
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: value must be one of ['blue', 'red', 'yellow'] @ data['color']
voluptuous/schema_builder.py:215: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_in():
"""Verify that In works."""
schema = Schema({"color": In(frozenset(["red", "blue", "yellow"]))})
schema({"color": "blue"})
> with pytest.raises(
MultipleInvalid,
match=r"value must be one of \['blue', 'red', 'yellow'\] for dictionary value @ data\['color'\]",
) as ctx:
E AssertionError: Regex pattern did not match.
E Regex: "value must be one of \\['blue', 'red', 'yellow'\\] for dictionary value @ data\\['color'\\]"
E Input: "value must be one of ['blue', 'red', 'yellow'] @ data['color']"
voluptuous/tests/tests.py:73: AssertionError
tests.py::test_in_unsortable_container
tests.py::test_in_unsortable_container
def test_in_unsortable_container():
"""Verify that In works with unsortable container."""
schema = Schema({"type": In((int, str, float))})
schema({"type": float})
with pytest.raises(
MultipleInvalid,
match=(
r"value must be one of \[, , \] for dictionary value "
r"@ data\['type'\]"
),
) as ctx:
> schema({"type": 42})
voluptuous/tests/tests.py:93:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {'type': 42}
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: value must be one of [, , ] @ data['type']
voluptuous/schema_builder.py:215: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_in_unsortable_container():
"""Verify that In works with unsortable container."""
schema = Schema({"type": In((int, str, float))})
schema({"type": float})
> with pytest.raises(
MultipleInvalid,
match=(
r"value must be one of \[, , \] for dictionary value "
r"@ data\['type'\]"
),
) as ctx:
E AssertionError: Regex pattern did not match.
E Regex: "value must be one of \\[, , \\] for dictionary value @ data\\['type'\\]"
E Input: "value must be one of [, , ] @ data['type']"
voluptuous/tests/tests.py:86: AssertionError
tests.py::test_not_in
tests.py::test_not_in
def test_not_in():
"""Verify that NotIn works."""
schema = Schema({"color": NotIn(frozenset(["red", "blue", "yellow"]))})
schema({"color": "orange"})
with pytest.raises(
MultipleInvalid,
match=(
r"value must not be one of \['blue', 'red', 'yellow'\] for dictionary "
r"value @ data\['color'\]"
),
) as ctx:
> schema({"color": "blue"})
voluptuous/tests/tests.py:109:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {'color': 'blue'}
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: value must not be one of ['blue', 'red', 'yellow'] @ data['color']
voluptuous/schema_builder.py:215: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_not_in():
"""Verify that NotIn works."""
schema = Schema({"color": NotIn(frozenset(["red", "blue", "yellow"]))})
schema({"color": "orange"})
> with pytest.raises(
MultipleInvalid,
match=(
r"value must not be one of \['blue', 'red', 'yellow'\] for dictionary "
r"value @ data\['color'\]"
),
) as ctx:
E AssertionError: Regex pattern did not match.
E Regex: "value must not be one of \\['blue', 'red', 'yellow'\\] for dictionary value @ data\\['color'\\]"
E Input: "value must not be one of ['blue', 'red', 'yellow'] @ data['color']"
voluptuous/tests/tests.py:102: AssertionError
tests.py::test_not_in_unsortable_container
tests.py::test_not_in_unsortable_container
def test_not_in_unsortable_container():
"""Verify that NotIn works with unsortable container."""
schema = Schema({"type": NotIn((int, str, float))})
schema({"type": 42})
with pytest.raises(
MultipleInvalid,
match=(
r"value must not be one of \[, , "
r"\] for dictionary value @ data\['type'\]"
),
) as ctx:
> schema({"type": str})
voluptuous/tests/tests.py:125:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {'type': }
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: value must not be one of [, , ] @ data['type']
voluptuous/schema_builder.py:215: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_not_in_unsortable_container():
"""Verify that NotIn works with unsortable container."""
schema = Schema({"type": NotIn((int, str, float))})
schema({"type": 42})
> with pytest.raises(
MultipleInvalid,
match=(
r"value must not be one of \[, , "
r"\] for dictionary value @ data\['type'\]"
),
) as ctx:
E AssertionError: Regex pattern did not match.
E Regex: "value must not be one of \\[, , \\] for dictionary value @ data\\['type'\\]"
E Input: "value must not be one of [, , ] @ data['type']"
voluptuous/tests/tests.py:118: AssertionError
tests.py::test_contains
tests.py::test_contains
def test_contains():
"""Verify contains validation method."""
schema = Schema({'color': Contains('red')})
schema({'color': ['blue', 'red', 'yellow']})
with pytest.raises(
MultipleInvalid,
match=r"value is not allowed for dictionary value @ data\['color'\]",
) as ctx:
> schema({'color': ['blue', 'yellow']})
voluptuous/tests/tests.py:138:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {'color': ['blue', 'yellow']}
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: value is not allowed @ data['color']
voluptuous/schema_builder.py:215: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_contains():
"""Verify contains validation method."""
schema = Schema({'color': Contains('red')})
schema({'color': ['blue', 'red', 'yellow']})
> with pytest.raises(
MultipleInvalid,
match=r"value is not allowed for dictionary value @ data\['color'\]",
) as ctx:
E AssertionError: Regex pattern did not match.
E Regex: "value is not allowed for dictionary value @ data\\['color'\\]"
E Input: "value is not allowed @ data['color']"
voluptuous/tests/tests.py:134: AssertionError
tests.py::test_remove
tests.py::test_remove
def test_remove():
"""Verify that Remove works."""
# remove dict keys
schema = Schema({"weight": int, Remove("color"): str, Remove("amount"): int})
out_ = schema({"weight": 10, "color": "red", "amount": 1})
> assert "color" not in out_ and "amount" not in out_
E AssertionError: assert ('color' not in {'amount': 1, 'color': 'red', 'weight': 10})
voluptuous/tests/tests.py:148: AssertionError
tests.py::test_remove_with_error
tests.py::test_remove_with_error
def test_remove_with_error():
def starts_with_dot(key: str) -> str:
"""Check if key starts with dot."""
if not key.startswith("."):
raise Invalid("Key does not start with .")
return key
def does_not_start_with_dot(key: str) -> str:
"""Check if key does not start with dot."""
if key.startswith("."):
raise Invalid("Key starts with .")
return key
schema = Schema(
{
Remove(All(str, starts_with_dot)): object,
does_not_start_with_dot: Any(None),
}
)
> out_ = schema({".remove": None, "ok": None})
voluptuous/tests/tests.py:198:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {'.remove': None, 'ok': None}
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: extra keys not allowed @ data['.remove']
voluptuous/schema_builder.py:215: MultipleInvalid
tests.py::test_literal
tests.py::test_literal
self =
data = [{'c': 1}]
def __call__(self, data):
"""Validate data against this schema."""
try:
> return self._compiled([], data)
voluptuous/schema_builder.py:291:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = [{'c': 1}]
def validate_sequence(path, data):
if not isinstance(data, seq_type):
raise er.SequenceTypeInvalid('expected a {}'.format(seq_type.__name__))
# Empty sequence
if not schema and data:
raise er.Invalid('not a valid value')
result = []
for i, value in enumerate(data):
valid = False
for validator in schema:
try:
result.append(self._compile(validator)([i] + path, value))
valid = True
break
except er.Invalid:
pass
if not valid:
> raise er.Invalid('not a valid value for sequence item')
E voluptuous.error.Invalid: not a valid value for sequence item
voluptuous/schema_builder.py:474: Invalid
During handling of the above exception, another exception occurred:
def test_literal():
"""Test with Literal"""
schema = Schema([Literal({"a": 1}), Literal({"b": 1})])
schema([{"a": 1}])
schema([{"b": 1}])
schema([{"a": 1}, {"b": 1}])
with pytest.raises(
MultipleInvalid, match=r"\{'c': 1\} not match for \{'b': 1\} @ data\[0\]"
) as ctx:
> schema([{"c": 1}])
voluptuous/tests/tests.py:218:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
data = [{'c': 1}]
def __call__(self, data):
"""Validate data against this schema."""
try:
return self._compiled([], data)
except er.MultipleInvalid:
raise
except er.Invalid as e:
> raise er.MultipleInvalid([e])
E voluptuous.error.MultipleInvalid: not a valid value for sequence item
voluptuous/schema_builder.py:295: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_literal():
"""Test with Literal"""
schema = Schema([Literal({"a": 1}), Literal({"b": 1})])
schema([{"a": 1}])
schema([{"b": 1}])
schema([{"a": 1}, {"b": 1}])
> with pytest.raises(
MultipleInvalid, match=r"\{'c': 1\} not match for \{'b': 1\} @ data\[0\]"
) as ctx:
E AssertionError: Regex pattern did not match.
E Regex: "\\{'c': 1\\} not match for \\{'b': 1\\} @ data\\[0\\]"
E Input: 'not a valid value for sequence item'
voluptuous/tests/tests.py:215: AssertionError
tests.py::test_email_validation
tests.py::test_email_validation
def test_email_validation():
"""Test with valid email address"""
> schema = Schema({"email": Email()})
E TypeError: Email() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:246: TypeError
tests.py::test_email_validation_with_none
tests.py::test_email_validation_with_none
def test_email_validation_with_none():
"""Test with invalid None email address"""
> schema = Schema({"email": Email()})
E TypeError: Email() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:254: TypeError
tests.py::test_email_validation_with_empty_string
tests.py::test_email_validation_with_empty_string
def test_email_validation_with_empty_string():
"""Test with empty string email address"""
> schema = Schema({"email": Email()})
E TypeError: Email() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:266: TypeError
tests.py::test_email_validation_without_host
tests.py::test_email_validation_without_host
def test_email_validation_without_host():
"""Test with empty host name in email address"""
> schema = Schema({"email": Email()})
E TypeError: Email() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:278: TypeError
tests.py::test_email_validation_with_bad_data[john@voluptuous.com>]
tests.py::test_email_validation_with_bad_data[john@voluptuous.com>]
input_value = 'john@voluptuous.com>'
@pytest.mark.parametrize(
'input_value', ['john@voluptuous.com>', 'john!@voluptuous.org!@($*!']
)
def test_email_validation_with_bad_data(input_value: str):
"""Test with bad data in email address"""
> schema = Schema({"email": Email()})
E TypeError: Email() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:293: TypeError
tests.py::test_email_validation_with_bad_data[john!@voluptuous.org!@($*!]
tests.py::test_email_validation_with_bad_data[john!@voluptuous.org!@($*!]
input_value = 'john!@voluptuous.org!@($*!'
@pytest.mark.parametrize(
'input_value', ['john@voluptuous.com>', 'john!@voluptuous.org!@($*!']
)
def test_email_validation_with_bad_data(input_value: str):
"""Test with bad data in email address"""
> schema = Schema({"email": Email()})
E TypeError: Email() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:293: TypeError
tests.py::test_fqdn_url_validation
tests.py::test_fqdn_url_validation
def test_fqdn_url_validation():
"""Test with valid fully qualified domain name URL"""
> schema = Schema({"url": FqdnUrl()})
E TypeError: FqdnUrl() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:305: TypeError
tests.py::test_fqdn_url_validation_with_bad_data[without domain name]
tests.py::test_fqdn_url_validation_with_bad_data[without domain name]
input_value = 'http://localhost/'
@pytest.mark.parametrize(
'input_value',
[
pytest.param("http://localhost/", id="without domain name"),
pytest.param(None, id="None"),
pytest.param("", id="empty string"),
pytest.param("http://", id="empty host"),
],
)
def test_fqdn_url_validation_with_bad_data(input_value):
> schema = Schema({"url": FqdnUrl()})
E TypeError: FqdnUrl() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:321: TypeError
tests.py::test_fqdn_url_validation_with_bad_data[None]
tests.py::test_fqdn_url_validation_with_bad_data[None]
input_value = None
@pytest.mark.parametrize(
'input_value',
[
pytest.param("http://localhost/", id="without domain name"),
pytest.param(None, id="None"),
pytest.param("", id="empty string"),
pytest.param("http://", id="empty host"),
],
)
def test_fqdn_url_validation_with_bad_data(input_value):
> schema = Schema({"url": FqdnUrl()})
E TypeError: FqdnUrl() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:321: TypeError
tests.py::test_fqdn_url_validation_with_bad_data[empty string]
tests.py::test_fqdn_url_validation_with_bad_data[empty string]
input_value = ''
@pytest.mark.parametrize(
'input_value',
[
pytest.param("http://localhost/", id="without domain name"),
pytest.param(None, id="None"),
pytest.param("", id="empty string"),
pytest.param("http://", id="empty host"),
],
)
def test_fqdn_url_validation_with_bad_data(input_value):
> schema = Schema({"url": FqdnUrl()})
E TypeError: FqdnUrl() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:321: TypeError
tests.py::test_fqdn_url_validation_with_bad_data[empty host]
tests.py::test_fqdn_url_validation_with_bad_data[empty host]
input_value = 'http://'
@pytest.mark.parametrize(
'input_value',
[
pytest.param("http://localhost/", id="without domain name"),
pytest.param(None, id="None"),
pytest.param("", id="empty string"),
pytest.param("http://", id="empty host"),
],
)
def test_fqdn_url_validation_with_bad_data(input_value):
> schema = Schema({"url": FqdnUrl()})
E TypeError: FqdnUrl() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:321: TypeError
tests.py::test_url_validation
tests.py::test_url_validation
def test_url_validation():
"""Test with valid URL"""
> schema = Schema({"url": Url()})
E TypeError: Url() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:333: TypeError
tests.py::test_url_validation_with_bad_data[None]
tests.py::test_url_validation_with_bad_data[None]
input_value = None
@pytest.mark.parametrize(
'input_value',
[
pytest.param(None, id="None"),
pytest.param("", id="empty string"),
pytest.param("http://", id="empty host"),
],
)
def test_url_validation_with_bad_data(input_value):
> schema = Schema({"url": Url()})
E TypeError: Url() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:348: TypeError
tests.py::test_url_validation_with_bad_data[empty string]
tests.py::test_url_validation_with_bad_data[empty string]
input_value = ''
@pytest.mark.parametrize(
'input_value',
[
pytest.param(None, id="None"),
pytest.param("", id="empty string"),
pytest.param("http://", id="empty host"),
],
)
def test_url_validation_with_bad_data(input_value):
> schema = Schema({"url": Url()})
E TypeError: Url() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:348: TypeError
tests.py::test_url_validation_with_bad_data[empty host]
tests.py::test_url_validation_with_bad_data[empty host]
input_value = 'http://'
@pytest.mark.parametrize(
'input_value',
[
pytest.param(None, id="None"),
pytest.param("", id="empty string"),
pytest.param("http://", id="empty host"),
],
)
def test_url_validation_with_bad_data(input_value):
> schema = Schema({"url": Url()})
E TypeError: Url() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:348: TypeError
tests.py::test_subschema_extension
tests.py::test_subschema_extension
def test_subschema_extension():
"""Verify that Schema.extend adds and replaces keys in a subschema"""
base = Schema({'a': {'b': int, 'c': float}})
extension = {'d': str, 'a': {'b': str, 'e': int}}
extended = base.extend(extension)
assert base.schema == {'a': {'b': int, 'c': float}}
assert extension == {'d': str, 'a': {'b': str, 'e': int}}
> assert extended.schema == {'a': {'b': str, 'c': float, 'e': int}, 'd': str}
E AssertionError: assert {'a': {'b': <...} == {'a': {'b': <...}
E
E Omitting 1 identical items, use -vv to show
E Differing items:
E {'a': {'b': , 'e': }} != {'a': {'b': , 'c': , 'e': }}
E
E Full diff:
E {...
E
E ...Full output truncated (7 lines hidden), use '-vv' to show
voluptuous/tests/tests.py:428: AssertionError
tests.py::test_repr
tests.py::test_repr
def test_repr():
"""Verify that __repr__ returns valid Python expressions"""
match = Match('a pattern', msg='message')
replace = Replace('you', 'I', msg='you and I')
range_ = Range(
min=0, max=42, min_included=False, max_included=False, msg='number not in range'
)
coerce_ = Coerce(int, msg="moo")
all_ = All('10', Coerce(int), msg='all msg')
maybe_int = Maybe(int)
assert repr(match) == "Match('a pattern', msg='message')"
assert repr(replace) == "Replace('you', 'I', msg='you and I')"
assert (
repr(range_)
== "Range(min=0, max=42, min_included=False, max_included=False, msg='number not in range')"
)
assert repr(coerce_) == "Coerce(int, msg='moo')"
assert repr(all_) == "All('10', Coerce(int, msg=None), msg='all msg')"
> assert repr(maybe_int) == "Any(None, %s, msg=None)" % str(int)
E assert '' == "Any(None, , msg=None)"
E
E - Any(None, , msg=None)
E + .validate_or_none at 0x7fcf5d014310>
voluptuous/tests/tests.py:526: AssertionError
tests.py::test_list_validation_messages
tests.py::test_list_validation_messages
def test_list_validation_messages():
"""Make sure useful error messages are available"""
def is_even(value):
if value % 2:
raise Invalid('%i is not even' % value)
return value
schema = Schema(dict(even_numbers=[All(int, is_even)]))
with pytest.raises(
MultipleInvalid, match=r"3 is not even @ data\['even_numbers'\]\[0\]"
) as ctx:
> schema(dict(even_numbers=[3]))
voluptuous/tests/tests.py:542:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:468: in validate_sequence
result.append(self._compile(validator)([i] + path, value))
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = All(, .is_even at 0x7fcf5d77f640>, msg=None)
validators = [.validate_instance at 0x7fcf5cedc040>, .validate_callable at 0x7fcf5cedd6c0>]
v = 3
def _exec(self, validators, v):
value = v
errors = []
for validator in validators:
try:
> value = validator(value)
E TypeError: _compile_scalar..validate_instance() missing 1 required positional argument: 'data'
voluptuous/validators.py:352: TypeError
tests.py::test_nested_multiple_validation_errors
tests.py::test_nested_multiple_validation_errors
def test_nested_multiple_validation_errors():
"""Make sure useful error messages are available"""
def is_even(value):
if value % 2:
raise Invalid('%i is not even' % value)
return value
schema = Schema(dict(even_numbers=All([All(int, is_even)], Length(min=1))))
with pytest.raises(
MultipleInvalid, match=r"3 is not even @ data\['even_numbers'\]\[0\]"
) as ctx:
> schema(dict(even_numbers=[3]))
voluptuous/tests/tests.py:562:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = All([All(, .is_even at 0x7fcf5cedc8b0>, msg=None)], Length(min=1, max=None), msg=None)
validators = [.validate_sequence at 0x7fcf5d016560>, .validate_callable at 0x7fcf5d0165f0>]
v = [3]
def _exec(self, validators, v):
value = v
errors = []
for validator in validators:
try:
> value = validator(value)
E TypeError: Schema._compile_sequence..validate_sequence() missing 1 required positional argument: 'data'
voluptuous/validators.py:352: TypeError
tests.py::test_humanize_error
tests.py::test_humanize_error
def test_humanize_error():
data = {'a': 'not an int', 'b': [123]}
schema = Schema({'a': int, 'b': [str]})
with pytest.raises(MultipleInvalid) as ctx:
schema(data)
assert len(ctx.value.errors) == 2
> assert humanize_error(data, ctx.value) == (
"expected int for dictionary value @ data['a']. Got 'not an int'\nexpected str @ data['b'][0]. Got 123"
)
voluptuous/tests/tests.py:575:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/humanize.py:13: in humanize_error
return '\n'.join(sorted(
voluptuous/humanize.py:14: in
humanize_error(data, sub_error, max_sub_error_length)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
data = {'a': 'not an int', 'b': [123]}
validation_error = TypeInvalid("expected int for @ data['a']")
max_sub_error_length = 500
def humanize_error(data, validation_error: Invalid, max_sub_error_length: int=MAX_VALIDATION_ERROR_ITEM_LENGTH) -> str:
"""Provide a more helpful + complete validation error message than that provided automatically
Invalid and MultipleInvalid do not include the offending value in error messages,
and MultipleInvalid.__str__ only provides the first error.
"""
if isinstance(validation_error, MultipleInvalid):
return '\n'.join(sorted(
humanize_error(data, sub_error, max_sub_error_length)
for sub_error in validation_error.errors
))
path = validation_error.path
value = data
# Walk the path to find the value
for step in path:
if isinstance(value, (list, tuple)):
value = value[step]
else:
value = value.get(step, 'N/A')
# Truncate value if too long
str_value = str(value)
if len(str_value) > max_sub_error_length:
str_value = str_value[:max_sub_error_length] + '...'
# Build the error message
path_str = ' @ data[%s]' % ']['.join(repr(p) for p in path) if path else ''
error_type = ' for ' + validation_error.error_type if validation_error.error_type else ''
return '%s%s (got %r)%s' % (
> validation_error.error_message,
error_type,
str_value,
path_str
)
E AttributeError: 'TypeInvalid' object has no attribute 'error_message'. Did you mean: '_error_message'?
voluptuous/humanize.py:38: AttributeError
tests.py::test_fix_157
tests.py::test_fix_157
def test_fix_157():
s = Schema(All([Any('one', 'two', 'three')]), Length(min=1))
> assert ['one'] == s(['one'])
voluptuous/tests/tests.py:582:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = All([Any('one', 'two', 'three', msg=None)], msg=None)
validators = [.validate_sequence at 0x7fcf5d016950>]
v = ['one']
def _exec(self, validators, v):
value = v
errors = []
for validator in validators:
try:
> value = validator(value)
E TypeError: Schema._compile_sequence..validate_sequence() missing 1 required positional argument: 'data'
voluptuous/validators.py:352: TypeError
tests.py::test_maybe_accepts_msg
tests.py::test_maybe_accepts_msg
self = , extra=PREVENT_EXTRA, required=False) object at 0x7fcf5e5d8be0>
data = []
def __call__(self, data):
"""Validate data against this schema."""
try:
> return self._compiled([], data)
voluptuous/schema_builder.py:291:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = []
def validate_instance(path, data):
if isinstance(data, schema):
return data
else:
msg = 'expected {} for {}'.format(schema.__name__, _path_string(path))
> raise er.TypeInvalid(msg)
E voluptuous.error.TypeInvalid: expected int for
voluptuous/schema_builder.py:592: TypeInvalid
During handling of the above exception, another exception occurred:
def test_maybe_accepts_msg():
s = Schema(Maybe(int, msg='int or None expected'))
with raises(MultipleInvalid, 'int or None expected'):
> assert s([])
voluptuous/tests/tests.py:755:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
voluptuous/validators.py:581: in validate_or_none
return schema(v)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , extra=PREVENT_EXTRA, required=False) object at 0x7fcf5e5d8be0>
data = []
def __call__(self, data):
"""Validate data against this schema."""
try:
return self._compiled([], data)
except er.MultipleInvalid:
raise
except er.Invalid as e:
> raise er.MultipleInvalid([e])
E voluptuous.error.MultipleInvalid: expected int for
voluptuous/schema_builder.py:295: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_maybe_accepts_msg():
s = Schema(Maybe(int, msg='int or None expected'))
> with raises(MultipleInvalid, 'int or None expected'):
voluptuous/tests/tests.py:754:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.10/contextlib.py:153: in __exit__
self.gen.throw(typ, value, traceback)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
exc = , msg = 'int or None expected'
@contextmanager
def raises(exc, msg=None):
"""Assert that a certain exception is raised.
>>> with raises(Invalid):
... Schema(int, required=True)('abc')
"""
try:
yield
except exc as e:
if msg is not None and str(e) != msg:
> raise AssertionError(
"Expected %r but got %r" % (msg, str(e))
)
E AssertionError: Expected 'int or None expected' but got 'expected int for '
voluptuous/schema_builder.py:45: AssertionError
tests.py::test_maybe_returns_default_error
tests.py::test_maybe_returns_default_error
self =
data = 3
def __call__(self, data):
"""Validate data against this schema."""
try:
> return self._compiled([], data)
voluptuous/schema_builder.py:291:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Range(min=1, max=2, min_included=True, max_included=True, msg=None)
v = 3
def __call__(self, v):
try:
if self.min_included:
if self.min is not None and (not v >= self.min):
raise RangeInvalid(self.msg or 'value must be at least %s' % self.min)
elif self.min is not None and (not v > self.min):
raise RangeInvalid(self.msg or 'value must be higher than %s' % self.min)
if self.max_included:
if self.max is not None and (not v <= self.max):
> raise RangeInvalid(self.msg or 'value must be at most %s' % self.max)
E voluptuous.error.RangeInvalid: value must be at most 2
voluptuous/validators.py:622: RangeInvalid
During handling of the above exception, another exception occurred:
def test_maybe_returns_default_error():
schema = Schema(Maybe(Range(1, 2)))
# The following should be valid
schema(None)
schema(1)
schema(2)
try:
# Should trigger a MultipleInvalid exception
> schema(3)
voluptuous/tests/tests.py:768:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
voluptuous/validators.py:581: in validate_or_none
return schema(v)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
data = 3
def __call__(self, data):
"""Validate data against this schema."""
try:
return self._compiled([], data)
except er.MultipleInvalid:
raise
except er.Invalid as e:
> raise er.MultipleInvalid([e])
E voluptuous.error.MultipleInvalid: value must be at most 2
voluptuous/schema_builder.py:295: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_maybe_returns_default_error():
schema = Schema(Maybe(Range(1, 2)))
# The following should be valid
schema(None)
schema(1)
schema(2)
try:
# Should trigger a MultipleInvalid exception
schema(3)
except MultipleInvalid as e:
> assert str(e) == "not a valid value"
E AssertionError: assert 'value must be at most 2' == 'not a valid value'
E
E - not a valid value
E + value must be at most 2
voluptuous/tests/tests.py:770: AssertionError
tests.py::test_schema_empty_list
tests.py::test_schema_empty_list
self =
data = [123]
def __call__(self, data):
"""Validate data against this schema."""
try:
> return self._compiled([], data)
voluptuous/schema_builder.py:291:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = [123]
def validate_sequence(path, data):
if not isinstance(data, seq_type):
raise er.SequenceTypeInvalid('expected a {}'.format(seq_type.__name__))
# Empty sequence
if not schema and data:
> raise er.Invalid('not a valid value')
E voluptuous.error.Invalid: not a valid value
voluptuous/schema_builder.py:461: Invalid
During handling of the above exception, another exception occurred:
def test_schema_empty_list():
s = Schema([])
s([])
try:
> s([123])
voluptuous/tests/tests.py:780:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
data = [123]
def __call__(self, data):
"""Validate data against this schema."""
try:
return self._compiled([], data)
except er.MultipleInvalid:
raise
except er.Invalid as e:
> raise er.MultipleInvalid([e])
E voluptuous.error.MultipleInvalid: not a valid value
voluptuous/schema_builder.py:295: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_schema_empty_list():
s = Schema([])
s([])
try:
s([123])
except MultipleInvalid as e:
> assert str(e) == "not a valid value @ data[123]"
E AssertionError: assert 'not a valid value' == 'not a valid ...e @ data[123]'
E
E - not a valid value @ data[123]
E + not a valid value
voluptuous/tests/tests.py:782: AssertionError
tests.py::test_schema_empty_dict_key
tests.py::test_schema_empty_dict_key
def test_schema_empty_dict_key():
"""https://github.com/alecthomas/voluptuous/pull/434"""
s = Schema({'var': []})
s({'var': []})
try:
> s({'var': [123]})
voluptuous/tests/tests.py:819:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {'var': [123]}
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: not a valid value
voluptuous/schema_builder.py:215: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_schema_empty_dict_key():
"""https://github.com/alecthomas/voluptuous/pull/434"""
s = Schema({'var': []})
s({'var': []})
try:
s({'var': [123]})
except MultipleInvalid as e:
> assert str(e) == "not a valid value for dictionary value @ data['var']"
E assert 'not a valid value' == "not a valid ...@ data['var']"
E
E - not a valid value for dictionary value @ data['var']
E + not a valid value
voluptuous/tests/tests.py:821: AssertionError
tests.py::test_schema_decorator_match_with_args
tests.py::test_schema_decorator_match_with_args
def test_schema_decorator_match_with_args():
@validate(int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:828: TypeError
tests.py::test_schema_decorator_unmatch_with_args
tests.py::test_schema_decorator_unmatch_with_args
def test_schema_decorator_unmatch_with_args():
@validate(int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:836: TypeError
tests.py::test_schema_decorator_match_with_kwargs
tests.py::test_schema_decorator_match_with_kwargs
def test_schema_decorator_match_with_kwargs():
@validate(arg=int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:844: TypeError
tests.py::test_schema_decorator_unmatch_with_kwargs
tests.py::test_schema_decorator_unmatch_with_kwargs
def test_schema_decorator_unmatch_with_kwargs():
@validate(arg=int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:852: TypeError
tests.py::test_schema_decorator_match_return_with_args
tests.py::test_schema_decorator_match_return_with_args
def test_schema_decorator_match_return_with_args():
@validate(int, __return__=int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:860: TypeError
tests.py::test_schema_decorator_unmatch_return_with_args
tests.py::test_schema_decorator_unmatch_return_with_args
def test_schema_decorator_unmatch_return_with_args():
@validate(int, __return__=int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:868: TypeError
tests.py::test_schema_decorator_match_return_with_kwargs
tests.py::test_schema_decorator_match_return_with_kwargs
def test_schema_decorator_match_return_with_kwargs():
@validate(arg=int, __return__=int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:876: TypeError
tests.py::test_schema_decorator_unmatch_return_with_kwargs
tests.py::test_schema_decorator_unmatch_return_with_kwargs
def test_schema_decorator_unmatch_return_with_kwargs():
@validate(arg=int, __return__=int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:884: TypeError
tests.py::test_schema_decorator_return_only_match
tests.py::test_schema_decorator_return_only_match
def test_schema_decorator_return_only_match():
@validate(__return__=int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:892: TypeError
tests.py::test_schema_decorator_return_only_unmatch
tests.py::test_schema_decorator_return_only_unmatch
def test_schema_decorator_return_only_unmatch():
@validate(__return__=int)
> def fn(arg):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:900: TypeError
tests.py::test_schema_decorator_partial_match_called_with_args
tests.py::test_schema_decorator_partial_match_called_with_args
def test_schema_decorator_partial_match_called_with_args():
@validate(arg1=int)
> def fn(arg1, arg2):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:908: TypeError
tests.py::test_schema_decorator_partial_unmatch_called_with_args
tests.py::test_schema_decorator_partial_unmatch_called_with_args
def test_schema_decorator_partial_unmatch_called_with_args():
@validate(arg1=int)
> def fn(arg1, arg2):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:916: TypeError
tests.py::test_schema_decorator_partial_match_called_with_kwargs
tests.py::test_schema_decorator_partial_match_called_with_kwargs
def test_schema_decorator_partial_match_called_with_kwargs():
@validate(arg2=int)
> def fn(arg1, arg2):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:924: TypeError
tests.py::test_schema_decorator_partial_unmatch_called_with_kwargs
tests.py::test_schema_decorator_partial_unmatch_called_with_kwargs
def test_schema_decorator_partial_unmatch_called_with_kwargs():
@validate(arg2=int)
> def fn(arg1, arg2):
E TypeError: 'NoneType' object is not callable
voluptuous/tests/tests.py:932: TypeError
tests.py::test_number_validation_with_string
tests.py::test_number_validation_with_string
def test_number_validation_with_string():
"""Test with Number with string"""
schema = Schema({"number": Number(precision=6, scale=2)})
try:
> schema({"number": 'teststr'})
voluptuous/tests/tests.py:942:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=6, scale=2, msg=None), v = 'teststr'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_number_validation_with_invalid_precision_invalid_scale
tests.py::test_number_validation_with_invalid_precision_invalid_scale
def test_number_validation_with_invalid_precision_invalid_scale():
"""Test with Number with invalid precision and scale"""
schema = Schema({"number": Number(precision=6, scale=2)})
try:
> schema({"number": '123456.712'})
voluptuous/tests/tests.py:956:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=6, scale=2, msg=None), v = '123456.712'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_number_validation_with_valid_precision_scale_yield_decimal_true
tests.py::test_number_validation_with_valid_precision_scale_yield_decimal_true
def test_number_validation_with_valid_precision_scale_yield_decimal_true():
"""Test with Number with valid precision and scale"""
schema = Schema({"number": Number(precision=6, scale=2, yield_decimal=True)})
> out_ = schema({"number": '1234.00'})
voluptuous/tests/tests.py:969:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=6, scale=2, msg=None), v = '1234.00'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_number_when_precision_scale_none_yield_decimal_true
tests.py::test_number_when_precision_scale_none_yield_decimal_true
def test_number_when_precision_scale_none_yield_decimal_true():
"""Test with Number with no precision and scale"""
schema = Schema({"number": Number(yield_decimal=True)})
> out_ = schema({"number": '12345678901234'})
voluptuous/tests/tests.py:976:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=None, scale=None, msg=None), v = '12345678901234'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_number_when_precision_none_n_valid_scale_case1_yield_decimal_true
tests.py::test_number_when_precision_none_n_valid_scale_case1_yield_decimal_true
def test_number_when_precision_none_n_valid_scale_case1_yield_decimal_true():
"""Test with Number with no precision and valid scale case 1"""
schema = Schema({"number": Number(scale=2, yield_decimal=True)})
> out_ = schema({"number": '123456789.34'})
voluptuous/tests/tests.py:983:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=None, scale=2, msg=None), v = '123456789.34'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_number_when_precision_none_n_valid_scale_case2_yield_decimal_true
tests.py::test_number_when_precision_none_n_valid_scale_case2_yield_decimal_true
def test_number_when_precision_none_n_valid_scale_case2_yield_decimal_true():
"""Test with Number with no precision and valid scale case 2 with zero in decimal part"""
schema = Schema({"number": Number(scale=2, yield_decimal=True)})
> out_ = schema({"number": '123456789012.00'})
voluptuous/tests/tests.py:990:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=None, scale=2, msg=None), v = '123456789012.00'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_number_when_precision_none_n_invalid_scale_yield_decimal_true
tests.py::test_number_when_precision_none_n_invalid_scale_yield_decimal_true
def test_number_when_precision_none_n_invalid_scale_yield_decimal_true():
"""Test with Number with no precision and invalid scale"""
schema = Schema({"number": Number(scale=2, yield_decimal=True)})
try:
> schema({"number": '12345678901.234'})
voluptuous/tests/tests.py:998:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=None, scale=2, msg=None), v = '12345678901.234'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_number_when_valid_precision_n_scale_none_yield_decimal_true
tests.py::test_number_when_valid_precision_n_scale_none_yield_decimal_true
def test_number_when_valid_precision_n_scale_none_yield_decimal_true():
"""Test with Number with no precision and valid scale"""
schema = Schema({"number": Number(precision=14, yield_decimal=True)})
> out_ = schema({"number": '1234567.8901234'})
voluptuous/tests/tests.py:1010:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=14, scale=None, msg=None), v = '1234567.8901234'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_number_when_invalid_precision_n_scale_none_yield_decimal_true
tests.py::test_number_when_invalid_precision_n_scale_none_yield_decimal_true
def test_number_when_invalid_precision_n_scale_none_yield_decimal_true():
"""Test with Number with no precision and invalid scale"""
schema = Schema({"number": Number(precision=14, yield_decimal=True)})
try:
> schema({"number": '12345674.8901234'})
voluptuous/tests/tests.py:1018:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=14, scale=None, msg=None), v = '12345674.8901234'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_number_validation_with_valid_precision_scale_yield_decimal_false
tests.py::test_number_validation_with_valid_precision_scale_yield_decimal_false
def test_number_validation_with_valid_precision_scale_yield_decimal_false():
"""Test with Number with valid precision, scale and no yield_decimal"""
schema = Schema({"number": Number(precision=6, scale=2, yield_decimal=False)})
> out_ = schema({"number": '1234.00'})
voluptuous/tests/tests.py:1031:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/schema_builder.py:598: in validate_callable
return schema(data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Number(precision=6, scale=2, msg=None), v = '1234.00'
def __call__(self, v):
"""
:param v: is a number enclosed with string
:return: Decimal number
"""
> precision, scale, decimal_num = self._get_precision_scale(v)
E TypeError: cannot unpack non-iterable NoneType object
voluptuous/validators.py:969: TypeError
tests.py::test_ordered_dict
tests.py::test_ordered_dict
def test_ordered_dict():
if not hasattr(collections, 'OrderedDict'):
# collections.OrderedDict was added in Python2.7; only run if present
return
schema = Schema({Number(): Number()}) # x, y pairs (for interpolation or something)
data = collections.OrderedDict(
[
(5.0, 3.7),
(24.0, 8.7),
(43.0, 1.5),
(62.0, 2.1),
(71.5, 6.7),
(90.5, 4.1),
(109.0, 3.9),
]
)
> out = schema(data)
voluptuous/tests/tests.py:1080:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = []
data = OrderedDict([(5.0, 3.7), (24.0, 8.7), (43.0, 1.5), (62.0, 2.1), (71.5, 6.7), (90.5, 4.1), (109.0, 3.9)])
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: extra keys not allowed @ data[5.0]
voluptuous/schema_builder.py:215: MultipleInvalid
tests.py::test_schema_infer_list
tests.py::test_schema_infer_list
def test_schema_infer_list():
schema = Schema.infer({'list': ['foo', True, 42, 3.14]})
> assert schema == Schema({Required('list'): [str, bool, int, float]})
E AssertionError: assert }, extra=PREVENT_EXTRA, required=False) object at 0x7fcf5cf2b190> == , , , ]}, extra=PREVENT_EXTRA, required=False) object at 0x7fcf5cf2a620>
E + where , , , ]}, extra=PREVENT_EXTRA, required=False) object at 0x7fcf5cf2a620> = Schema({'list': [, , , ]})
voluptuous/tests/tests.py:1124: AssertionError
tests.py::test_schema_infer_scalar
tests.py::test_schema_infer_scalar
def test_schema_infer_scalar():
assert Schema.infer('foo') == Schema(str)
assert Schema.infer(True) == Schema(bool)
assert Schema.infer(42) == Schema(int)
assert Schema.infer(3.14) == Schema(float)
> assert Schema.infer({}) == Schema(dict)
E AssertionError: assert == , extra=PREVENT_EXTRA, required=False) object at 0x7fcf5df3cdc0>
E + where = infer({})
E + where infer = Schema.infer
E + and , extra=PREVENT_EXTRA, required=False) object at 0x7fcf5df3cdc0> = Schema(dict)
voluptuous/tests/tests.py:1132: AssertionError
tests.py::test_IsDir
tests.py::test_IsDir
def test_IsDir():
> schema = Schema(IsDir())
E TypeError: truth..validator() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:1200: TypeError
tests.py::test_IsFile
tests.py::test_IsFile
def test_IsFile():
> schema = Schema(IsFile())
E TypeError: truth..validator() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:1206: TypeError
tests.py::test_PathExists
tests.py::test_PathExists
def test_PathExists():
> schema = Schema(PathExists())
E TypeError: truth..validator() missing 1 required positional argument: 'v'
voluptuous/tests/tests.py:1212: TypeError
tests.py::test_SomeOf_min_validation
tests.py::test_SomeOf_min_validation
def test_SomeOf_min_validation():
validator = All(
Length(min=8),
SomeOf(
min_valid=3,
validators=[
Match(r'.*[A-Z]', 'no uppercase letters'),
Match(r'.*[a-z]', 'no lowercase letters'),
Match(r'.*[0-9]', 'no numbers'),
Match(r'.*[$@$!%*#?&^:;/<,>|{}()\-\'._+=]', 'no symbols'),
],
),
)
> validator('ffe532A1!')
voluptuous/tests/tests.py:1248:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/validators.py:211: in __call__
return self._exec((Schema(val) for val in self.validators), v)
voluptuous/validators.py:352: in _exec
value = validator(value)
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = SomeOf(min_valid=3, validators=[Match('.*[A-Z]', msg='no uppercase letters'), Match('.*[a-z]', msg='no lowercase lette...h('.*[0-9]', msg='no numbers'), Match(".*[$@$!%*#?&^:;/<,>|{}()\\-\\'._+=]", msg='no symbols')], max_valid=4, msg=None)
validators = [.validate_callable at 0x7fcf5d014310>, .validate_....validate_callable at 0x7fcf5d0176d0>, .validate_callable at 0x7fcf5d017a30>]
v = 'ffe532A1!'
def _exec(self, validators, v):
"""Execute the validators against the value."""
> raise NotImplementedError
E NotImplementedError
voluptuous/validators.py:218: NotImplementedError
tests.py::test_SomeOf_max_validation
tests.py::test_SomeOf_max_validation
def test_SomeOf_max_validation():
validator = SomeOf(
max_valid=2,
validators=[
Match(r'.*[A-Z]', 'no uppercase letters'),
Match(r'.*[a-z]', 'no lowercase letters'),
Match(r'.*[0-9]', 'no numbers'),
],
msg='max validation test failed',
)
> validator('Aa')
voluptuous/tests/tests.py:1270:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/validators.py:211: in __call__
return self._exec((Schema(val) for val in self.validators), v)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = SomeOf(min_valid=0, validators=[Match('.*[A-Z]', msg='no uppercase letters'), Match('.*[a-z]', msg='no lowercase letters'), Match('.*[0-9]', msg='no numbers')], max_valid=2, msg='max validation test failed')
validators = . at 0x7fcf5cfa1e70>
v = 'Aa'
def _exec(self, validators, v):
"""Execute the validators against the value."""
> raise NotImplementedError
E NotImplementedError
voluptuous/validators.py:218: NotImplementedError
tests.py::test_self_validation
tests.py::test_self_validation
def test_self_validation():
schema = Schema({"number": int, "follow": Self})
with raises(MultipleInvalid):
schema({"number": "abc"})
with raises(MultipleInvalid):
schema({"follow": {"number": '123456.712'}})
> schema({"follow": {"number": 123456}})
voluptuous/tests/tests.py:1283:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {'follow': {'number': 123456}}
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
key = skey(key)
break
if not found_valid_key:
if self.extra == PREVENT_EXTRA:
errors.append(er.Invalid('extra keys not allowed', path + [key]))
elif self.extra == ALLOW_EXTRA:
out[key] = value
continue
try:
out[key] = self._compile(found_key_schema)(path + [key], value)
except er.Invalid as e:
errors.append(e)
if errors:
> raise er.MultipleInvalid(errors)
E voluptuous.error.MultipleInvalid: expected Self for @ data['follow']
voluptuous/schema_builder.py:215: MultipleInvalid
tests.py::test_any_error_has_path
tests.py::test_any_error_has_path
def test_any_error_has_path():
"""https://github.com/alecthomas/voluptuous/issues/347"""
s = Schema({Optional('q'): int, Required('q2'): Any(int, msg='toto')})
with pytest.raises(MultipleInvalid) as ctx:
> s({'q': 'str', 'q2': 'tata'})
voluptuous/tests/tests.py:1292:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:177: in validate_dict
out[key] = self._compile(value_schema[key])(path + [key], data[key])
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Any(, msg='toto')
validators = [.validate_instance at 0x7fcf5d015870>]
v = 'tata'
def _exec(self, validators, v):
errors = []
for validator in validators:
try:
> return validator(v)
E TypeError: _compile_scalar..validate_instance() missing 1 required positional argument: 'data'
voluptuous/validators.py:249: TypeError
tests.py::test_all_error_has_path
tests.py::test_all_error_has_path
def test_all_error_has_path():
"""https://github.com/alecthomas/voluptuous/issues/347"""
s = Schema(
{
Optional('q'): int,
Required('q2'): All([str, Length(min=10)], msg='toto'),
}
)
with pytest.raises(MultipleInvalid) as ctx:
> s({'q': 'str', 'q2': 12})
voluptuous/tests/tests.py:1308:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:177: in validate_dict
out[key] = self._compile(value_schema[key])(path + [key], data[key])
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = All([, Length(min=10, max=None)], msg='toto')
validators = [.validate_sequence at 0x7fcf5d017a30>]
v = 12
def _exec(self, validators, v):
value = v
errors = []
for validator in validators:
try:
> value = validator(value)
E TypeError: Schema._compile_sequence..validate_sequence() missing 1 required positional argument: 'data'
voluptuous/validators.py:352: TypeError
tests.py::test_path_with_string
tests.py::test_path_with_string
def test_path_with_string():
"""Most common dict use with strings as keys"""
s = Schema({'string_key': int})
with pytest.raises(MultipleInvalid) as ctx:
s({'string_key': 'str'})
> assert ctx.value.errors[0].path == ['string_key']
E AssertionError: assert [] == ['string_key']
E
E Right contains one more item: 'string_key'
E
E Full diff:
E + []
E - [
E - 'string_key',
E - ]
voluptuous/tests/tests.py:1343: AssertionError
tests.py::test_path_with_list_index
tests.py::test_path_with_list_index
def test_path_with_list_index():
"""Position of the offending list index included in path as int"""
s = Schema({'string_key': [int]})
with pytest.raises(MultipleInvalid) as ctx:
s({'string_key': [123, 'should be int']})
> assert ctx.value.errors[0].path == ['string_key', 1]
E AssertionError: assert [] == ['string_key', 1]
E
E Right contains 2 more items, first extra item: 'string_key'
E
E Full diff:
E + []
E - [
E - 'string_key',
E - 1,
E - ]
voluptuous/tests/tests.py:1352: AssertionError
tests.py::test_path_with_tuple_index
tests.py::test_path_with_tuple_index
def test_path_with_tuple_index():
"""Position of the offending tuple index included in path as int"""
s = Schema({'string_key': (int,)})
with pytest.raises(MultipleInvalid) as ctx:
s({'string_key': (123, 'should be int')})
> assert ctx.value.errors[0].path == ['string_key', 1]
E AssertionError: assert [] == ['string_key', 1]
E
E Right contains 2 more items, first extra item: 'string_key'
E
E Full diff:
E + []
E - [
E - 'string_key',
E - 1,
E - ]
voluptuous/tests/tests.py:1361: AssertionError
tests.py::test_path_with_integer_dict_key
tests.py::test_path_with_integer_dict_key
def test_path_with_integer_dict_key():
"""Not obvious case with dict having not strings, but integers as keys"""
s = Schema({1337: int})
with pytest.raises(MultipleInvalid) as ctx:
s({1337: 'should be int'})
> assert ctx.value.errors[0].path == [1337]
E assert [] == [1337]
E
E Right contains one more item: 1337
E
E Full diff:
E + []
E - [
E - 1337,
E - ]
voluptuous/tests/tests.py:1370: AssertionError
tests.py::test_path_with_float_dict_key
tests.py::test_path_with_float_dict_key
def test_path_with_float_dict_key():
"""Not obvious case with dict having not strings, but floats as keys"""
s = Schema({13.37: int})
with pytest.raises(MultipleInvalid) as ctx:
s({13.37: 'should be int'})
> assert ctx.value.errors[0].path == [13.37]
E assert [] == [13.37]
E
E Right contains one more item: 13.37
E
E Full diff:
E + []
E - [
E - 13.37,
E - ]
voluptuous/tests/tests.py:1379: AssertionError
tests.py::test_path_with_tuple_dict_key
tests.py::test_path_with_tuple_dict_key
def test_path_with_tuple_dict_key():
"""Not obvious case with dict having not strings, but tuples as keys"""
s = Schema({('fancy', 'key'): int})
with pytest.raises(MultipleInvalid) as ctx:
s({('fancy', 'key'): 'should be int'})
> assert ctx.value.errors[0].path == [('fancy', 'key')]
E AssertionError: assert [] == [('fancy', 'key')]
E
E Right contains one more item: ('fancy', 'key')
E
E Full diff:
E + []
E - [
E - (...
E
E ...Full output truncated (4 lines hidden), use '-vv' to show
voluptuous/tests/tests.py:1388: AssertionError
tests.py::test_path_with_arbitrary_hashable_dict_key
tests.py::test_path_with_arbitrary_hashable_dict_key
def test_path_with_arbitrary_hashable_dict_key():
"""Not obvious case with dict having not strings, but arbitrary hashable objects as keys"""
class HashableObjectWhichWillBeKeyInDict:
def __hash__(self):
return 1337 # dummy hash, used only for illustration
s = Schema({HashableObjectWhichWillBeKeyInDict: [int]})
hashable_obj_provided_in_input = HashableObjectWhichWillBeKeyInDict()
with pytest.raises(MultipleInvalid) as ctx:
> s({hashable_obj_provided_in_input: [0, 1, 'should be int']})
voluptuous/tests/tests.py:1403:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = []
data = {.HashableObjectWhichWillBeKeyInDict object at 0x7fcf5d6060e0>: [0, 1, 'should be int']}
def validate_dict(path, data):
if not isinstance(data, dict):
raise er.DictInvalid('expected a dictionary')
out = {}
errors = []
seen_keys = set()
# First validate all the required keys
for key in required_keys:
if key not in data:
errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
continue
try:
out[key] = self._compile(value_schema[key])(path + [key], data[key])
except er.Invalid as e:
errors.append(e)
seen_keys.add(key)
# Now validate the rest of the keys
for key, value in data.items():
if key in seen_keys:
continue
found_valid_key = False
found_key_schema = None
# Try to find a matching key schema
for skey, svalue in value_schema.items():
if skey == key:
found_key_schema = svalue
found_valid_key = True
break
if isinstance(skey, type) and isinstance(key, skey):
found_key_schema = svalue
found_valid_key = True
> key = skey(key)
E TypeError: HashableObjectWhichWillBeKeyInDict() takes no arguments
voluptuous/schema_builder.py:199: TypeError
tests.py::test_self_any
tests.py::test_self_any
def test_self_any():
schema = Schema({"number": int, "follow": Any(Self, "stop")})
with pytest.raises(MultipleInvalid) as ctx:
schema({"number": "abc"})
assert len(ctx.value.errors) == 1
assert isinstance(ctx.value.errors[0], TypeInvalid)
with raises(MultipleInvalid):
> schema({"follow": {"number": '123456.712'}})
voluptuous/tests/tests.py:1415:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Any(, 'stop', msg=None)
validators = [.validate_instance at 0x7fcf5d016680>, .validate_value at 0x7fcf5d017eb0>]
v = {'number': '123456.712'}
def _exec(self, validators, v):
errors = []
for validator in validators:
try:
> return validator(v)
E TypeError: _compile_scalar..validate_instance() missing 1 required positional argument: 'data'
voluptuous/validators.py:249: TypeError
tests.py::test_self_all
tests.py::test_self_all
def test_self_all():
schema = Schema(
{
"number": int,
"follow": All(Self, Schema({"extra_number": int}, extra=ALLOW_EXTRA)),
},
extra=ALLOW_EXTRA,
)
with pytest.raises(MultipleInvalid) as ctx:
schema({"number": "abc"})
assert len(ctx.value.errors) == 1
assert isinstance(ctx.value.errors[0], TypeInvalid)
with pytest.raises(MultipleInvalid) as ctx:
> schema({"follow": {"number": '123456.712'}})
voluptuous/tests/tests.py:1436:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = All(, }, extra=ALLOW_EXTRA, required=False) object at 0x7fcf5e5a8430>, msg=None)
validators = [.validate_instance at 0x7fcf5d017a30>, .validate_callable at 0x7fcf5d017370>]
v = {'number': '123456.712'}
def _exec(self, validators, v):
value = v
errors = []
for validator in validators:
try:
> value = validator(value)
E TypeError: _compile_scalar..validate_instance() missing 1 required positional argument: 'data'
voluptuous/validators.py:352: TypeError
tests.py::test_set_of_integers
tests.py::test_set_of_integers
self = }, extra=PREVENT_EXTRA, required=False) object at 0x7fcf5d1bee00>
data = {'abc'}
def __call__(self, data):
"""Validate data against this schema."""
try:
> return self._compiled([], data)
voluptuous/schema_builder.py:291:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {'abc'}
def validate_sequence(path, data):
if not isinstance(data, seq_type):
raise er.SequenceTypeInvalid('expected a {}'.format(seq_type.__name__))
# Empty sequence
if not schema and data:
raise er.Invalid('not a valid value')
result = []
for i, value in enumerate(data):
valid = False
for validator in schema:
try:
result.append(self._compile(validator)([i] + path, value))
valid = True
break
except er.Invalid:
pass
if not valid:
> raise er.Invalid('not a valid value for sequence item')
E voluptuous.error.Invalid: not a valid value for sequence item
voluptuous/schema_builder.py:474: Invalid
During handling of the above exception, another exception occurred:
def test_set_of_integers():
schema = Schema({int})
with raises(Invalid, 'expected a set'):
schema(42)
with raises(Invalid, 'expected a set'):
schema(frozenset([42]))
schema(set())
schema(set([42]))
schema(set([42, 43, 44]))
with pytest.raises(MultipleInvalid, match="invalid value in set") as ctx:
> schema(set(['abc']))
voluptuous/tests/tests.py:1473:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = }, extra=PREVENT_EXTRA, required=False) object at 0x7fcf5d1bee00>
data = {'abc'}
def __call__(self, data):
"""Validate data against this schema."""
try:
return self._compiled([], data)
except er.MultipleInvalid:
raise
except er.Invalid as e:
> raise er.MultipleInvalid([e])
E voluptuous.error.MultipleInvalid: not a valid value for sequence item
voluptuous/schema_builder.py:295: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_set_of_integers():
schema = Schema({int})
with raises(Invalid, 'expected a set'):
schema(42)
with raises(Invalid, 'expected a set'):
schema(frozenset([42]))
schema(set())
schema(set([42]))
schema(set([42, 43, 44]))
> with pytest.raises(MultipleInvalid, match="invalid value in set") as ctx:
E AssertionError: Regex pattern did not match.
E Regex: 'invalid value in set'
E Input: 'not a valid value for sequence item'
voluptuous/tests/tests.py:1472: AssertionError
tests.py::test_frozenset_of_integers
tests.py::test_frozenset_of_integers
self = }), extra=PREVENT_EXTRA, required=False) object at 0x7fcf5e347970>
data = 42
def __call__(self, data):
"""Validate data against this schema."""
try:
> return self._compiled([], data)
voluptuous/schema_builder.py:291:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = 42
def validate_value(path, data):
if data != schema:
> raise er.ScalarInvalid('not a valid value')
E voluptuous.error.ScalarInvalid: not a valid value
voluptuous/schema_builder.py:608: ScalarInvalid
During handling of the above exception, another exception occurred:
def test_frozenset_of_integers():
schema = Schema(frozenset([int]))
with raises(Invalid, 'expected a frozenset'):
> schema(42)
voluptuous/tests/tests.py:1480:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = }), extra=PREVENT_EXTRA, required=False) object at 0x7fcf5e347970>
data = 42
def __call__(self, data):
"""Validate data against this schema."""
try:
return self._compiled([], data)
except er.MultipleInvalid:
raise
except er.Invalid as e:
> raise er.MultipleInvalid([e])
E voluptuous.error.MultipleInvalid: not a valid value
voluptuous/schema_builder.py:295: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_frozenset_of_integers():
schema = Schema(frozenset([int]))
> with raises(Invalid, 'expected a frozenset'):
voluptuous/tests/tests.py:1479:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.10/contextlib.py:153: in __exit__
self.gen.throw(typ, value, traceback)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
exc = , msg = 'expected a frozenset'
@contextmanager
def raises(exc, msg=None):
"""Assert that a certain exception is raised.
>>> with raises(Invalid):
... Schema(int, required=True)('abc')
"""
try:
yield
except exc as e:
if msg is not None and str(e) != msg:
> raise AssertionError(
"Expected %r but got %r" % (msg, str(e))
)
E AssertionError: Expected 'expected a frozenset' but got 'not a valid value'
voluptuous/schema_builder.py:45: AssertionError
tests.py::test_set_of_integers_and_strings
tests.py::test_set_of_integers_and_strings
self = , }, extra=PREVENT_EXTRA, required=False) object at 0x7fcf5e79efb0>
data = {None}
def __call__(self, data):
"""Validate data against this schema."""
try:
> return self._compiled([], data)
voluptuous/schema_builder.py:291:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = {None}
def validate_sequence(path, data):
if not isinstance(data, seq_type):
raise er.SequenceTypeInvalid('expected a {}'.format(seq_type.__name__))
# Empty sequence
if not schema and data:
raise er.Invalid('not a valid value')
result = []
for i, value in enumerate(data):
valid = False
for validator in schema:
try:
result.append(self._compile(validator)([i] + path, value))
valid = True
break
except er.Invalid:
pass
if not valid:
> raise er.Invalid('not a valid value for sequence item')
E voluptuous.error.Invalid: not a valid value for sequence item
voluptuous/schema_builder.py:474: Invalid
During handling of the above exception, another exception occurred:
def test_set_of_integers_and_strings():
schema = Schema({int, str})
with raises(Invalid, 'expected a set'):
schema(42)
schema(set())
schema(set([42]))
schema(set(['abc']))
schema(set([42, 'abc']))
with pytest.raises(MultipleInvalid, match="invalid value in set") as ctx:
> schema(set([None]))
voluptuous/tests/tests.py:1504:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , }, extra=PREVENT_EXTRA, required=False) object at 0x7fcf5e79efb0>
data = {None}
def __call__(self, data):
"""Validate data against this schema."""
try:
return self._compiled([], data)
except er.MultipleInvalid:
raise
except er.Invalid as e:
> raise er.MultipleInvalid([e])
E voluptuous.error.MultipleInvalid: not a valid value for sequence item
voluptuous/schema_builder.py:295: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_set_of_integers_and_strings():
schema = Schema({int, str})
with raises(Invalid, 'expected a set'):
schema(42)
schema(set())
schema(set([42]))
schema(set(['abc']))
schema(set([42, 'abc']))
> with pytest.raises(MultipleInvalid, match="invalid value in set") as ctx:
E AssertionError: Regex pattern did not match.
E Regex: 'invalid value in set'
E Input: 'not a valid value for sequence item'
voluptuous/tests/tests.py:1503: AssertionError
tests.py::test_frozenset_of_integers_and_strings
tests.py::test_frozenset_of_integers_and_strings
self = , }), extra=PREVENT_EXTRA, required=False) object at 0x7fcf5cee8c40>
data = 42
def __call__(self, data):
"""Validate data against this schema."""
try:
> return self._compiled([], data)
voluptuous/schema_builder.py:291:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data = 42
def validate_value(path, data):
if data != schema:
> raise er.ScalarInvalid('not a valid value')
E voluptuous.error.ScalarInvalid: not a valid value
voluptuous/schema_builder.py:608: ScalarInvalid
During handling of the above exception, another exception occurred:
def test_frozenset_of_integers_and_strings():
schema = Schema(frozenset([int, str]))
with raises(Invalid, 'expected a frozenset'):
> schema(42)
voluptuous/tests/tests.py:1511:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , }), extra=PREVENT_EXTRA, required=False) object at 0x7fcf5cee8c40>
data = 42
def __call__(self, data):
"""Validate data against this schema."""
try:
return self._compiled([], data)
except er.MultipleInvalid:
raise
except er.Invalid as e:
> raise er.MultipleInvalid([e])
E voluptuous.error.MultipleInvalid: not a valid value
voluptuous/schema_builder.py:295: MultipleInvalid
During handling of the above exception, another exception occurred:
def test_frozenset_of_integers_and_strings():
schema = Schema(frozenset([int, str]))
> with raises(Invalid, 'expected a frozenset'):
voluptuous/tests/tests.py:1510:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.10/contextlib.py:153: in __exit__
self.gen.throw(typ, value, traceback)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
exc = , msg = 'expected a frozenset'
@contextmanager
def raises(exc, msg=None):
"""Assert that a certain exception is raised.
>>> with raises(Invalid):
... Schema(int, required=True)('abc')
"""
try:
yield
except exc as e:
if msg is not None and str(e) != msg:
> raise AssertionError(
"Expected %r but got %r" % (msg, str(e))
)
E AssertionError: Expected 'expected a frozenset' but got 'not a valid value'
voluptuous/schema_builder.py:45: AssertionError
tests.py::test_any_required
tests.py::test_any_required
def test_any_required():
schema = Schema(Any({'a': int}, {'b': str}, required=True))
with raises(MultipleInvalid, "required key not provided @ data['a']"):
> schema({})
voluptuous/tests/tests.py:1564:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Any({'a': }, {'b': }, msg=None)
validators = [.validate_dict at 0x7fcf5d017010>, .validate_dict at 0x7fcf5d0172e0>]
v = {}
def _exec(self, validators, v):
errors = []
for validator in validators:
try:
> return validator(v)
E TypeError: Schema._compile_dict_with_schema..validate_dict() missing 1 required positional argument: 'data'
voluptuous/validators.py:249: TypeError
tests.py::test_any_required_with_subschema
tests.py::test_any_required_with_subschema
def test_any_required_with_subschema():
schema = Schema(
Any({'a': Any(float, int)}, {'b': int}, {'c': {'aa': int}}, required=True)
)
with raises(MultipleInvalid, "required key not provided @ data['a']"):
> schema({})
voluptuous/tests/tests.py:1573:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Any({'a': Any(, , msg=None)}, {'b': }, {'c': {'aa': }}, msg=None)
validators = [.validate_dict at 0x7fcf5d017370>, , .validate_dict at 0x7fcf5d017ac0>]
v = {}
def _exec(self, validators, v):
errors = []
for validator in validators:
try:
> return validator(v)
E TypeError: Schema._compile_dict_with_schema..validate_dict() missing 1 required positional argument: 'data'
voluptuous/validators.py:249: TypeError
tests.py::test_inclusive
tests.py::test_inclusive
def test_inclusive():
schema = Schema(
{
Inclusive('x', 'stuff'): int,
Inclusive('y', 'stuff'): int,
}
)
r = schema({})
assert r == {}
r = schema({'x': 1, 'y': 2})
assert r == {'x': 1, 'y': 2}
> with raises(
MultipleInvalid,
"some but not all values in the same group of inclusion 'stuff' @ data[]",
):
voluptuous/tests/tests.py:1590:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.10/contextlib.py:142: in __exit__
next(self.gen)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
exc =
msg = "some but not all values in the same group of inclusion 'stuff' @ data[]"
@contextmanager
def raises(exc, msg=None):
"""Assert that a certain exception is raised.
>>> with raises(Invalid):
... Schema(int, required=True)('abc')
"""
try:
yield
except exc as e:
if msg is not None and str(e) != msg:
raise AssertionError(
"Expected %r but got %r" % (msg, str(e))
)
else:
> raise AssertionError("Expected %r" % exc)
E AssertionError: Expected
voluptuous/schema_builder.py:49: AssertionError
tests.py::test_inclusive_defaults
tests.py::test_inclusive_defaults
def test_inclusive_defaults():
schema = Schema(
{
Inclusive('x', 'stuff', default=3): int,
Inclusive('y', 'stuff', default=4): int,
}
)
r = schema({})
> assert r == {'x': 3, 'y': 4}
E AssertionError: assert {} == {'x': 3, 'y': 4}
E
E Right contains 2 more items:
E {'x': 3, 'y': 4}
E
E Full diff:
E + {}
E - {...
E
E ...Full output truncated (3 lines hidden), use '-vv' to show
voluptuous/tests/tests.py:1606: AssertionError
tests.py::test_exclusive
tests.py::test_exclusive
def test_exclusive():
schema = Schema(
{
Exclusive('x', 'stuff'): int,
Exclusive('y', 'stuff'): int,
}
)
r = schema({})
assert r == {}
r = schema({'x': 1})
assert r == {'x': 1}
> with raises(
MultipleInvalid,
"two or more values in the same group of exclusion 'stuff' @ data[]",
):
voluptuous/tests/tests.py:1629:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.10/contextlib.py:142: in __exit__
next(self.gen)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
exc =
msg = "two or more values in the same group of exclusion 'stuff' @ data[]"
@contextmanager
def raises(exc, msg=None):
"""Assert that a certain exception is raised.
>>> with raises(Invalid):
... Schema(int, required=True)('abc')
"""
try:
yield
except exc as e:
if msg is not None and str(e) != msg:
raise AssertionError(
"Expected %r but got %r" % (msg, str(e))
)
else:
> raise AssertionError("Expected %r" % exc)
E AssertionError: Expected
voluptuous/schema_builder.py:49: AssertionError
tests.py::test_any_with_discriminant
tests.py::test_any_with_discriminant
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
),
)
}
)
with raises(
MultipleInvalid,
"expected bool for dictionary value @ data['implementation']['c-value']",
):
> schema({'implementation': {'type': 'C', 'c-value': None}})
voluptuous/tests/tests.py:1662:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
voluptuous/schema_builder.py:291: in __call__
return self._compiled([], data)
voluptuous/schema_builder.py:210: in validate_dict
out[key] = self._compile(found_key_schema)(path + [key], value)
voluptuous/validators.py:208: in _run
return self._exec(self._compiled, data)
voluptuous/validators.py:282: in _exec
filtered = list(self.discriminant(v, [val.schema for val in validators]))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.0 =
> filtered = list(self.discriminant(v, [val.schema for val in validators]))
E AttributeError: 'function' object has no attribute 'schema'
voluptuous/validators.py:282: AttributeError
tests.py::test_key1
tests.py::test_key1
def test_key1():
def as_int(a):
return int(a)
schema = Schema({as_int: str})
with pytest.raises(MultipleInvalid) as ctx:
schema(
{
'1': 'one',
'two': '2',
'3': 'three',
'four': '4',
}
)
> assert len(ctx.value.errors) == 2
E AssertionError: assert 4 == 2
E + where 4 = len([Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed')])
E + where [Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed')] = MultipleInvalid([Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed')]).errors
E + where MultipleInvalid([Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed')]) = .value
voluptuous/tests/tests.py:1680: AssertionError
tests.py::test_key2
tests.py::test_key2
def test_key2():
def as_int(a):
try:
return int(a)
except ValueError:
raise Invalid('expecting a number')
schema = Schema({as_int: str})
with pytest.raises(MultipleInvalid) as ctx:
schema(
{
'1': 'one',
'two': '2',
'3': 'three',
'four': '4',
}
)
> assert len(ctx.value.errors) == 2
E AssertionError: assert 4 == 2
E + where 4 = len([Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed')])
E + where [Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed')] = MultipleInvalid([Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed')]).errors
E + where MultipleInvalid([Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed'), Invalid('extra keys not allowed')]) = .value
voluptuous/tests/tests.py:1702: AssertionError
tests.py::test_object
tests.py::test_object
self =
data =
def __call__(self, data):
"""Validate data against this schema."""
try:
> return self._compiled([], data)
voluptuous/schema_builder.py:291:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
path = [], data =
def validate_dict(path, data):
if not isinstance(data, dict):
> raise er.DictInvalid('expected a dictionary')
E voluptuous.error.DictInvalid: expected a dictionary
voluptuous/schema_builder.py:164: DictInvalid
During handling of the above exception, another exception occurred:
def test_object():
s = Schema(Object({'value': 1}), required=True)
> s(MyValueClass(value=1))
voluptuous/tests/tests.py:1759:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
data =
def __call__(self, data):
"""Validate data against this schema."""
try:
return self._compiled([], data)
except er.MultipleInvalid:
raise
except er.Invalid as e:
> raise er.MultipleInvalid([e])
E voluptuous.error.MultipleInvalid: expected a dictionary
voluptuous/schema_builder.py:295: MultipleInvalid
tests.py::test_exception
tests.py::test_exception
def test_exception():
s = Schema(None)
with pytest.raises(MultipleInvalid) as ctx:
s(123)
invalid_scalar_excp_repr = "ScalarInvalid('not a valid value')"
assert repr(ctx.value) == f"MultipleInvalid([{invalid_scalar_excp_repr}])"
assert str(ctx.value.msg) == "not a valid value"
assert str(ctx.value.error_message) == "not a valid value"
assert str(ctx.value.errors) == f"[{invalid_scalar_excp_repr}]"
ctx.value.add("Test Error")
> assert str(ctx.value.errors) == f"[{invalid_scalar_excp_repr}, 'Test Error']"
E assert "[ScalarInval...Test Error')]" == "[ScalarInval...'Test Error']"
E
E - [ScalarInvalid('not a valid value'), 'Test Error']
E + [ScalarInvalid('not a valid value'), Invalid('Test Error')]
E ? ++++++++ +
voluptuous/tests/tests.py:1775: AssertionError
Patch diff
diff --git a/voluptuous/error.py b/voluptuous/error.py
index dbaeb36..a9e7ba3 100644
--- a/voluptuous/error.py
+++ b/voluptuous/error.py
@@ -21,6 +21,7 @@ class Invalid(Error):
self._path = path or []
self._error_message = error_message or message
self.error_type = error_type
+ self.path = self._path
def __str__(self) -> str:
path = ' @ data[%s]' % ']['.join(map(repr, self.path)) if self.path else ''
@@ -33,6 +34,9 @@ class MultipleInvalid(Invalid):
def __init__(self, errors: typing.Optional[typing.List[Invalid]]=None) -> None:
self.errors = errors[:] if errors else []
+ self.msg = str(self.errors[0]) if self.errors else ''
+ self.error_message = self.msg
+ self.path = self.errors[0].path if self.errors else []
def __repr__(self) -> str:
return 'MultipleInvalid(%r)' % self.errors
@@ -40,6 +44,13 @@ class MultipleInvalid(Invalid):
def __str__(self) -> str:
return str(self.errors[0])
+ def add(self, error: str) -> None:
+ """Add a new error to the list of errors."""
+ self.errors.append(Invalid(error))
+ self.msg = str(self.errors[0])
+ self.error_message = self.msg
+ self.path = self.errors[0].path
+
class RequiredFieldInvalid(Invalid):
"""Required field was missing."""
diff --git a/voluptuous/humanize.py b/voluptuous/humanize.py
index c434625..bc2b8eb 100644
--- a/voluptuous/humanize.py
+++ b/voluptuous/humanize.py
@@ -9,4 +9,34 @@ def humanize_error(data, validation_error: Invalid, max_sub_error_length: int=MA
Invalid and MultipleInvalid do not include the offending value in error messages,
and MultipleInvalid.__str__ only provides the first error.
"""
- pass
\ No newline at end of file
+ if isinstance(validation_error, MultipleInvalid):
+ return '\n'.join(sorted(
+ humanize_error(data, sub_error, max_sub_error_length)
+ for sub_error in validation_error.errors
+ ))
+
+ path = validation_error.path
+ value = data
+
+ # Walk the path to find the value
+ for step in path:
+ if isinstance(value, (list, tuple)):
+ value = value[step]
+ else:
+ value = value.get(step, 'N/A')
+
+ # Truncate value if too long
+ str_value = str(value)
+ if len(str_value) > max_sub_error_length:
+ str_value = str_value[:max_sub_error_length] + '...'
+
+ # Build the error message
+ path_str = ' @ data[%s]' % ']['.join(repr(p) for p in path) if path else ''
+ error_type = ' for ' + validation_error.error_type if validation_error.error_type else ''
+
+ return '%s%s (got %r)%s' % (
+ validation_error.error_message,
+ error_type,
+ str_value,
+ path_str
+ )
\ No newline at end of file
diff --git a/voluptuous/schema_builder.py b/voluptuous/schema_builder.py
index d5f5612..d6fd203 100644
--- a/voluptuous/schema_builder.py
+++ b/voluptuous/schema_builder.py
@@ -10,6 +10,64 @@ from contextlib import contextmanager
from functools import cache, wraps
from voluptuous import error as er
from voluptuous.error import Error
+
+def default_factory(value: DefaultFactory) -> typing.Callable[[], typing.Any]:
+ """Return a function to generate default values.
+
+ >>> default_factory(42)()
+ 42
+ >>> default_factory(list)()
+ []
+ >>> default_factory(None)()
+ Traceback (most recent call last):
+ ...
+ TypeError: value must not be None
+ """
+ if value is None:
+ raise TypeError('value must not be None')
+ if isinstance(value, UNDEFINED.__class__):
+ return lambda: None
+ if callable(value):
+ return value
+ return lambda: value
+
+@contextmanager
+def raises(exc, msg=None):
+ """Assert that a certain exception is raised.
+
+ >>> with raises(Invalid):
+ ... Schema(int, required=True)('abc')
+ """
+ try:
+ yield
+ except exc as e:
+ if msg is not None and str(e) != msg:
+ raise AssertionError(
+ "Expected %r but got %r" % (msg, str(e))
+ )
+ else:
+ raise AssertionError("Expected %r" % exc)
+
+def message(msg: str, cls: typing.Optional[typing.Type[Error]]=None):
+ """Decorate a function with a message to be displayed in case of error.
+
+ >>> @message('not an integer')
+ ... def isint(v):
+ ... return int(v)
+ >>>
+ >>> validate = Schema(isint())
+ >>> with raises(MultipleInvalid, 'not an integer'):
+ ... validate('a')
+ """
+ def decorator(f):
+ @wraps(f)
+ def check(v, *args, **kwargs):
+ try:
+ return f(v, *args, **kwargs)
+ except (ValueError, TypeError):
+ raise (cls or Invalid)(msg)
+ return check
+ return decorator
PREVENT_EXTRA = 0
ALLOW_EXTRA = 1
REMOVE_EXTRA = 2
@@ -26,7 +84,7 @@ DefaultFactory = typing.Union[Undefined, typing.Callable[[], typing.Any]]
def Extra(_) -> None:
"""Allow keys in the data that are not present in the schema."""
- pass
+ return ALLOW_EXTRA
extra = Extra
primitive_types = (bool, bytes, int, str, float, complex)
Schemable = typing.Union['Schema', 'Object', collections.abc.Mapping, list, tuple, frozenset, set, bool, bytes, int, str, float, complex, type, object, dict, None, typing.Callable]
@@ -74,6 +132,92 @@ class Schema(object):
self.extra = int(extra)
self._compiled = self._compile(schema)
+ def _compile(self, schema):
+ """Compile the schema into a callable validator."""
+ if hasattr(schema, '__voluptuous_compile__'):
+ return schema.__voluptuous_compile__(self)
+
+ if isinstance(schema, dict):
+ return self._compile_dict(schema)
+
+ if isinstance(schema, list):
+ return self._compile_list(schema)
+
+ if isinstance(schema, tuple):
+ return self._compile_tuple(schema)
+
+ if isinstance(schema, set):
+ return self._compile_set(schema)
+
+ if isinstance(schema, Object):
+ return self._compile_object(schema)
+
+ return _compile_scalar(schema)
+
+ def _compile_dict_with_schema(self, required_keys, value_schema, invalid_msg=None):
+ """Create validator for a dict with a given schema."""
+ if invalid_msg is None:
+ invalid_msg = 'dictionary value'
+
+ def validate_dict(path, data):
+ if not isinstance(data, dict):
+ raise er.DictInvalid('expected a dictionary')
+
+ out = {}
+ errors = []
+ seen_keys = set()
+
+ # First validate all the required keys
+ for key in required_keys:
+ if key not in data:
+ errors.append(er.RequiredFieldInvalid(key.msg or 'required key not provided', path + [key]))
+ continue
+
+ try:
+ out[key] = self._compile(value_schema[key])(path + [key], data[key])
+ except er.Invalid as e:
+ errors.append(e)
+ seen_keys.add(key)
+
+ # Now validate the rest of the keys
+ for key, value in data.items():
+ if key in seen_keys:
+ continue
+
+ found_valid_key = False
+ found_key_schema = None
+
+ # Try to find a matching key schema
+ for skey, svalue in value_schema.items():
+ if skey == key:
+ found_key_schema = svalue
+ found_valid_key = True
+ break
+ if isinstance(skey, type) and isinstance(key, skey):
+ found_key_schema = svalue
+ found_valid_key = True
+ key = skey(key)
+ break
+
+ if not found_valid_key:
+ if self.extra == PREVENT_EXTRA:
+ errors.append(er.Invalid('extra keys not allowed', path + [key]))
+ elif self.extra == ALLOW_EXTRA:
+ out[key] = value
+ continue
+
+ try:
+ out[key] = self._compile(found_key_schema)(path + [key], value)
+ except er.Invalid as e:
+ errors.append(e)
+
+ if errors:
+ raise er.MultipleInvalid(errors)
+
+ return out
+
+ return validate_dict
+
@classmethod
def infer(cls, data, **kwargs) -> Schema:
"""Create a Schema from concrete data (e.g. an API response).
@@ -102,7 +246,30 @@ class Schema(object):
Note: only very basic inference is supported.
"""
- pass
+ def _infer_type(value):
+ if isinstance(value, dict):
+ return {k: _infer_type(v) for k, v in value.items()}
+ elif isinstance(value, list):
+ if not value:
+ return list
+ types = {type(v) for v in value}
+ if len(types) == 1:
+ return [next(iter(types))]
+ return list
+ elif isinstance(value, tuple):
+ return tuple(_infer_type(v) for v in value)
+ elif isinstance(value, set):
+ if not value:
+ return set
+ types = {type(v) for v in value}
+ if len(types) == 1:
+ return {next(iter(types))}
+ return set
+ else:
+ return type(value)
+
+ schema = _infer_type(data)
+ return cls(schema, **kwargs)
def __eq__(self, other):
if not isinstance(other, Schema):
@@ -129,7 +296,29 @@ class Schema(object):
def _compile_mapping(self, schema, invalid_msg=None):
"""Create validator for given mapping."""
- pass
+ if invalid_msg is None:
+ invalid_msg = 'mapping value'
+
+ # Keys can be markers (Required, Optional, etc.) or values
+ # Markers have a schema attached to them
+ key_schema = set()
+ value_schema = {}
+ for key, value in _iterate_mapping_candidates(schema):
+ if isinstance(key, Marker):
+ key_schema.add(key)
+ value_schema[key] = value
+ else:
+ value_schema[key] = value
+
+ # Keys which aren't marked as Required are Optional by default
+ required_keys = set(key for key in key_schema if isinstance(key, Required))
+
+ # Check for duplicate keys
+ key_names = [str(key) for key in key_schema]
+ if len(set(key_names)) != len(key_names):
+ raise er.SchemaError('duplicate keys found: {}'.format(key_names))
+
+ return self._compile_dict_with_schema(required_keys, value_schema, invalid_msg)
def _compile_object(self, schema):
"""Validate an object.
@@ -149,7 +338,22 @@ class Schema(object):
... validate(Structure(one='three'))
"""
- pass
+ if not isinstance(schema, Object):
+ raise er.SchemaError('expected Object')
+
+ compiled_schema = self._compile_mapping(schema, 'object value')
+
+ def validate_object(path, data):
+ if schema.cls is not UNDEFINED and not isinstance(data, schema.cls):
+ raise er.ObjectInvalid('expected instance of {}'.format(schema.cls))
+
+ obj_dict = {}
+ for key, value in _iterate_object(data):
+ obj_dict[key] = value
+
+ return compiled_schema(path, obj_dict)
+
+ return validate_object
def _compile_dict(self, schema):
"""Validate a dictionary.
@@ -227,7 +431,10 @@ class Schema(object):
"expected str for dictionary value @ data['adict']['strfield']"]
"""
- pass
+ if not isinstance(schema, dict):
+ raise er.SchemaError('expected dict')
+
+ return self._compile_mapping(schema, 'dictionary value')
def _compile_sequence(self, schema, seq_type):
"""Validate a sequence type.
@@ -242,7 +449,32 @@ class Schema(object):
>>> validator([1])
[1]
"""
- pass
+ if not isinstance(schema, (list, tuple, set)):
+ raise er.SchemaError('expected sequence')
+
+ def validate_sequence(path, data):
+ if not isinstance(data, seq_type):
+ raise er.SequenceTypeInvalid('expected a {}'.format(seq_type.__name__))
+
+ # Empty sequence
+ if not schema and data:
+ raise er.Invalid('not a valid value')
+
+ result = []
+ for i, value in enumerate(data):
+ valid = False
+ for validator in schema:
+ try:
+ result.append(self._compile(validator)([i] + path, value))
+ valid = True
+ break
+ except er.Invalid:
+ pass
+ if not valid:
+ raise er.Invalid('not a valid value for sequence item')
+ return seq_type(result)
+
+ return validate_sequence
def _compile_tuple(self, schema):
"""Validate a tuple.
@@ -257,7 +489,7 @@ class Schema(object):
>>> validator((1,))
(1,)
"""
- pass
+ return self._compile_sequence(schema, tuple)
def _compile_list(self, schema):
"""Validate a list.
@@ -272,7 +504,7 @@ class Schema(object):
>>> validator([1])
[1]
"""
- pass
+ return self._compile_sequence(schema, list)
def _compile_set(self, schema):
"""Validate a set.
@@ -287,7 +519,7 @@ class Schema(object):
>>> with raises(er.MultipleInvalid, 'invalid value in set'):
... validator(set(['a']))
"""
- pass
+ return self._compile_sequence(schema, set)
def extend(self, schema: Schemable, required: typing.Optional[bool]=None, extra: typing.Optional[int]=None) -> Schema:
"""Create a new `Schema` by merging this and the provided `schema`.
@@ -302,7 +534,35 @@ class Schema(object):
:param required: if set, overrides `required` of this `Schema`
:param extra: if set, overrides `extra` of this `Schema`
"""
- pass
+ if not isinstance(self.schema, dict):
+ raise er.SchemaError('original schema is not a dictionary')
+ if not isinstance(schema, (dict, Schema)):
+ raise er.SchemaError('extension schema is not a dictionary')
+
+ schema = schema if isinstance(schema, Schema) else Schema(schema)
+ if not isinstance(schema.schema, dict):
+ raise er.SchemaError('extension schema is not a dictionary')
+
+ # Deep copy the schema to avoid modifying it
+ new_schema = {}
+ for key, value in self.schema.items():
+ new_schema[key] = value
+
+ # Update with the extension schema
+ for key, value in schema.schema.items():
+ new_schema[key] = value
+
+ return type(self)(
+ new_schema,
+ required=self.required if required is None else required,
+ extra=self.extra if extra is None else extra
+ )
+
+def _path_string(path):
+ """Convert a list path to a string path."""
+ if not path:
+ return ''
+ return ' @ data[%s]' % ']['.join(repr(p) for p in path)
def _compile_scalar(schema):
"""A scalar value.
@@ -323,23 +583,59 @@ def _compile_scalar(schema):
>>> with raises(er.Invalid, 'not a valid value'):
... _compile_scalar(lambda v: float(v))([], 'a')
"""
- pass
+ if isinstance(schema, type):
+ def validate_instance(path, data):
+ if isinstance(data, schema):
+ return data
+ else:
+ msg = 'expected {} for {}'.format(schema.__name__, _path_string(path))
+ raise er.TypeInvalid(msg)
+ return validate_instance
+
+ if callable(schema):
+ def validate_callable(path, data):
+ try:
+ return schema(data)
+ except ValueError as e:
+ raise er.Invalid('not a valid value')
+ except er.Invalid as e:
+ e.path = path + e.path
+ raise
+ return validate_callable
+
+ def validate_value(path, data):
+ if data != schema:
+ raise er.ScalarInvalid('not a valid value')
+ return data
+
+ return validate_value
def _compile_itemsort():
"""return sort function of mappings"""
- pass
+ def sort_item(item):
+ key, _ = item
+ if isinstance(key, Marker):
+ return 0 if isinstance(key, Required) else 1, str(key)
+ return 2, str(key)
+ return sort_item
_sort_item = _compile_itemsort()
def _iterate_mapping_candidates(schema):
"""Iterate over schema in a meaningful order."""
- pass
+ return sorted(schema.items(), key=_sort_item)
def _iterate_object(obj):
"""Return iterator over object attributes. Respect objects with
defined __slots__.
"""
- pass
+ if hasattr(obj, '__slots__'):
+ for key in obj.__slots__:
+ if hasattr(obj, key):
+ yield key, getattr(obj, key)
+ else:
+ for key, value in obj.__dict__.items():
+ yield key, value
class Msg(object):
"""Report a user-friendly message if a schema fails to validate.
@@ -405,6 +701,22 @@ class VirtualPathComponent(str):
def __repr__(self):
return self.__str__()
+class Self(object):
+ """Validates a value against itself.
+
+ >>> s = Schema(Self)
+ >>> s(1)
+ 1
+ >>> s('hi')
+ 'hi'
+ """
+
+ def __call__(self, v):
+ return v
+
+ def __repr__(self):
+ return 'Self'
+
class Marker(object):
"""Mark nodes for special treatment.
diff --git a/voluptuous/util.py b/voluptuous/util.py
index d2d5a8d..a9e5616 100644
--- a/voluptuous/util.py
+++ b/voluptuous/util.py
@@ -1,5 +1,5 @@
import typing
-from voluptuous import validators
+from voluptuous.validators import Any
from voluptuous.error import Invalid, LiteralInvalid, TypeInvalid
from voluptuous.schema_builder import DefaultFactory
from voluptuous.schema_builder import Schema, default_factory, raises
@@ -12,7 +12,7 @@ def Lower(v: str) -> str:
>>> s('HI')
'hi'
"""
- pass
+ return str(v).lower()
def Upper(v: str) -> str:
"""Transform a string to upper case.
@@ -21,7 +21,7 @@ def Upper(v: str) -> str:
>>> s('hi')
'HI'
"""
- pass
+ return str(v).upper()
def Capitalize(v: str) -> str:
"""Capitalise a string.
@@ -30,7 +30,7 @@ def Capitalize(v: str) -> str:
>>> s('hello world')
'Hello world'
"""
- pass
+ return str(v).capitalize()
def Title(v: str) -> str:
"""Title case a string.
@@ -39,7 +39,7 @@ def Title(v: str) -> str:
>>> s('hello world')
'Hello World'
"""
- pass
+ return str(v).title()
def Strip(v: str) -> str:
"""Strip whitespace from a string.
@@ -48,7 +48,7 @@ def Strip(v: str) -> str:
>>> s(' hello world ')
'hello world'
"""
- pass
+ return str(v).strip()
class DefaultTo(object):
"""Sets a value to default_value if none provided.
@@ -76,7 +76,7 @@ class DefaultTo(object):
class SetTo(object):
"""Set a value, ignoring any previous value.
- >>> s = Schema(validators.Any(int, SetTo(42)))
+ >>> s = Schema(Any(int, SetTo(42)))
>>> s(2)
2
>>> s("foo")
diff --git a/voluptuous/validators.py b/voluptuous/validators.py
index 22f6981..fb1a055 100644
--- a/voluptuous/validators.py
+++ b/voluptuous/validators.py
@@ -7,7 +7,28 @@ import typing
from decimal import Decimal, InvalidOperation
from functools import wraps
from voluptuous.error import AllInvalid, AnyInvalid, BooleanInvalid, CoerceInvalid, ContainsInvalid, DateInvalid, DatetimeInvalid, DirInvalid, EmailInvalid, ExactSequenceInvalid, FalseInvalid, FileInvalid, InInvalid, Invalid, LengthInvalid, MatchInvalid, MultipleInvalid, NotEnoughValid, NotInInvalid, PathInvalid, RangeInvalid, TooManyValid, TrueInvalid, TypeInvalid, UrlInvalid
-from voluptuous.schema_builder import Schema, Schemable, message, raises
+from voluptuous.schema_builder import Schema, Schemable, raises
+
+def message(msg: str, cls: typing.Optional[typing.Type[Invalid]]=None):
+ """Decorate a function with a message to be displayed in case of error.
+
+ >>> @message('not an integer')
+ ... def isint(v):
+ ... return int(v)
+ >>>
+ >>> validate = Schema(isint())
+ >>> with raises(MultipleInvalid, 'not an integer'):
+ ... validate('a')
+ """
+ def decorator(f):
+ @wraps(f)
+ def check(v, *args, **kwargs):
+ try:
+ return f(v, *args, **kwargs)
+ except (ValueError, TypeError):
+ raise (cls or Invalid)(msg)
+ return check
+ return decorator
if typing.TYPE_CHECKING:
from _typeshed import SupportsAllComparisons
Enum: typing.Union[type, None]
@@ -36,7 +57,13 @@ def truth(f: typing.Callable) -> typing.Callable:
>>> with raises(MultipleInvalid, 'not a valid value'):
... validate('/notavaliddir')
"""
- pass
+ def validator(path, data):
+ t = f(data)
+ if not t:
+ raise Invalid('not a valid value', path)
+ return data
+
+ return validator
class Coerce(object):
"""Coerce a value to a type.
@@ -77,7 +104,6 @@ class Coerce(object):
return 'Coerce(%s, msg=%r)' % (self.type_name, self.msg)
@message('value was not true', cls=TrueInvalid)
-@truth
def IsTrue(v):
"""Assert that a value is true, in the Python sense.
@@ -100,7 +126,7 @@ def IsTrue(v):
... except MultipleInvalid as e:
... assert isinstance(e.errors[0], TrueInvalid)
"""
- pass
+ return bool(v)
@message('value was not false', cls=FalseInvalid)
def IsFalse(v):
@@ -119,7 +145,7 @@ def IsFalse(v):
... except MultipleInvalid as e:
... assert isinstance(e.errors[0], FalseInvalid)
"""
- pass
+ return not bool(v)
@message('expected boolean', cls=BooleanInvalid)
def Boolean(v):
@@ -142,7 +168,16 @@ def Boolean(v):
... except MultipleInvalid as e:
... assert isinstance(e.errors[0], BooleanInvalid)
"""
- pass
+ if isinstance(v, bool):
+ return v
+ if isinstance(v, str):
+ v = v.lower().strip()
+ if v in ('true', '1', 'yes', 'on', 'enable'):
+ return True
+ if v in ('false', '0', 'no', 'off', 'disable'):
+ return False
+ raise BooleanInvalid('expected boolean')
+ return bool(v)
class _WithSubValidators(object):
"""Base class for validators that use sub-validators.
@@ -168,12 +203,20 @@ class _WithSubValidators(object):
schema.required = old_required
return self._run
+ def _run(self, path, data):
+ """Run the compiled validators."""
+ return self._exec(self._compiled, data)
+
def __call__(self, v):
return self._exec((Schema(val) for val in self.validators), v)
def __repr__(self):
return '%s(%s, msg=%r)' % (self.__class__.__name__, ', '.join((repr(v) for v in self.validators)), self.msg)
+ def _exec(self, validators, v):
+ """Execute the validators against the value."""
+ raise NotImplementedError
+
class Any(_WithSubValidators):
"""Use the first validated value.
@@ -198,6 +241,17 @@ class Any(_WithSubValidators):
>>> with raises(MultipleInvalid, "Expected 1 2 or 3"):
... validate(4)
"""
+
+ def _exec(self, validators, v):
+ errors = []
+ for validator in validators:
+ try:
+ return validator(v)
+ except Invalid as e:
+ errors.append(e)
+ if len(errors) == 1:
+ raise errors[0]
+ raise AnyInvalid(self.msg or 'no valid value found')
Or = Any
class Union(_WithSubValidators):
@@ -220,8 +274,63 @@ class Union(_WithSubValidators):
Without the discriminant, the exception would be "extra keys not allowed @ data['b_val']"
"""
+
+ def _exec(self, validators, v):
+ if self.discriminant is None:
+ return Any._exec(self, validators, v)
+
+ filtered = list(self.discriminant(v, [val.schema for val in validators]))
+ if not filtered:
+ raise AnyInvalid(self.msg or 'no valid value found')
+
+ errors = []
+ for validator in validators:
+ if validator.schema in filtered:
+ try:
+ return validator(v)
+ except Invalid as e:
+ errors.append(e)
+ if len(errors) == 1:
+ raise errors[0]
+ raise AnyInvalid(self.msg or 'no valid value found')
Switch = Union
+class SomeOf(_WithSubValidators):
+ """Value must pass some of the validators.
+
+ :param min_valid: Minimum number of valid values
+ :param max_valid: Maximum number of valid values
+ :param msg: Message to deliver to user if validation fails.
+ :param kwargs: All other keyword arguments are passed to the sub-schema constructors.
+
+ >>> validate = Schema(SomeOf(min_valid=1, validators=[1, 2, 3]))
+ >>> validate(1)
+ 1
+ >>> with raises(MultipleInvalid, "value did not pass enough validations"):
+ ... validate(4)
+ """
+
+ def __init__(self, min_valid=None, max_valid=None, *validators, msg=None, required=False, discriminant=None, **kwargs) -> None:
+ super().__init__(*validators, msg=msg, required=required, discriminant=discriminant, **kwargs)
+ self.min_valid = min_valid
+ self.max_valid = max_valid
+
+ def _exec(self, validators, v):
+ valid = []
+ errors = []
+ for validator in validators:
+ try:
+ valid.append(validator([], v))
+ except Invalid as e:
+ errors.append(e)
+
+ if self.min_valid is not None and len(valid) < self.min_valid:
+ raise NotEnoughValid(self.msg or 'value did not pass enough validations')
+ if self.max_valid is not None and len(valid) > self.max_valid:
+ raise TooManyValid(self.msg or 'value passed too many validations')
+
+ return valid[0] if valid else None
+
class All(_WithSubValidators):
"""Value must pass all validators.
@@ -234,6 +343,20 @@ class All(_WithSubValidators):
>>> validate('10')
10
"""
+
+ def _exec(self, validators, v):
+ value = v
+ errors = []
+ for validator in validators:
+ try:
+ value = validator(value)
+ except Invalid as e:
+ errors.append(e)
+ if errors:
+ if len(errors) == 1:
+ raise errors[0]
+ raise AllInvalid(self.msg or 'value did not pass all validators')
+ return value
And = All
class Match(object):
@@ -296,7 +419,7 @@ class Replace(object):
return 'Replace(%r, %r, msg=%r)' % (self.pattern.pattern, self.substitution, self.msg)
@message('expected an email address', cls=EmailInvalid)
-def Email(v):
+def Email(v=None):
"""Verify that the value is an email address or not.
>>> s = Schema(Email())
@@ -309,10 +432,32 @@ def Email(v):
>>> s('t@x.com')
't@x.com'
"""
- pass
+ def validate_email(path, data):
+ if not isinstance(data, str):
+ raise EmailInvalid('expected an email address', path)
+
+ if not data or '@' not in data:
+ raise EmailInvalid('expected an email address', path)
+
+ user_part, domain_part = data.rsplit('@', 1)
+
+ if not user_part or not domain_part:
+ raise EmailInvalid('expected an email address', path)
+
+ if not USER_REGEX.match(user_part):
+ raise EmailInvalid('expected an email address', path)
+
+ if not DOMAIN_REGEX.match(domain_part):
+ raise EmailInvalid('expected an email address', path)
+
+ return data
+
+ if v is None:
+ return validate_email
+ return validate_email([], v)
@message('expected a fully qualified domain name URL', cls=UrlInvalid)
-def FqdnUrl(v):
+def FqdnUrl(v=None):
"""Verify that the value is a fully qualified domain name URL.
>>> s = Schema(FqdnUrl())
@@ -321,10 +466,29 @@ def FqdnUrl(v):
>>> s('http://w3.org')
'http://w3.org'
"""
- pass
+ def validate_fqdn_url(path, data):
+ if not isinstance(data, str):
+ raise UrlInvalid('expected a fully qualified domain name URL', path)
+
+ try:
+ parsed = urlparse.urlparse(data)
+ if not parsed.scheme or not parsed.netloc:
+ raise UrlInvalid('expected a fully qualified domain name URL', path)
+ if parsed.netloc == 'localhost':
+ raise UrlInvalid('expected a fully qualified domain name URL', path)
+ if not DOMAIN_REGEX.match(parsed.netloc):
+ raise UrlInvalid('expected a fully qualified domain name URL', path)
+ except Exception:
+ raise UrlInvalid('expected a fully qualified domain name URL', path)
+
+ return data
+
+ if v is None:
+ return validate_fqdn_url
+ return validate_fqdn_url([], v)
@message('expected a URL', cls=UrlInvalid)
-def Url(v):
+def Url(v=None):
"""Verify that the value is a URL.
>>> s = Schema(Url())
@@ -333,7 +497,22 @@ def Url(v):
>>> s('http://w3.org')
'http://w3.org'
"""
- pass
+ def validate_url(v):
+ if not isinstance(v, str):
+ raise UrlInvalid('expected a URL')
+
+ try:
+ parsed = urlparse.urlparse(v)
+ if not parsed.scheme or not parsed.netloc:
+ raise UrlInvalid('expected a URL')
+ except Exception:
+ raise UrlInvalid('expected a URL')
+
+ return v
+
+ if v is None:
+ return validate_url
+ return validate_url(v)
@message('Not a file', cls=FileInvalid)
@truth
@@ -347,7 +526,9 @@ def IsFile(v):
>>> with raises(FileInvalid, 'Not a file'):
... IsFile()(None)
"""
- pass
+ if v is None:
+ return False
+ return os.path.isfile(str(v))
@message('Not a directory', cls=DirInvalid)
@truth
@@ -359,7 +540,9 @@ def IsDir(v):
>>> with raises(DirInvalid, 'Not a directory'):
... IsDir()(None)
"""
- pass
+ if v is None:
+ return False
+ return os.path.isdir(str(v))
@message('path does not exist', cls=PathInvalid)
@truth
@@ -373,7 +556,9 @@ def PathExists(v):
>>> with raises(PathInvalid, 'Not a Path'):
... PathExists()(None)
"""
- pass
+ if v is None:
+ return False
+ return os.path.exists(str(v))
def Maybe(validator: Schemable, msg: typing.Optional[str]=None):
"""Validate that the object matches given validator or is None.
@@ -388,7 +573,14 @@ def Maybe(validator: Schemable, msg: typing.Optional[str]=None):
... s("string")
"""
- pass
+ schema = Schema(validator)
+
+ def validate_or_none(v):
+ if v is None:
+ return v
+ return schema(v)
+
+ return validate_or_none
class Range(object):
"""Limit a value to a range.