Skip to content

Commit

Permalink
Avoid using ? with get_item to handle unhashable inputs properly (#…
Browse files Browse the repository at this point in the history
…1089)

Co-authored-by: Samuel Colvin <s@muelcolvin.com>
  • Loading branch information
sydney-runkle and samuelcolvin authored Nov 22, 2023
1 parent 3840e00 commit 5b63e7a
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/validators/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ impl<T: Debug> LiteralLookup<T> {
}
// must be an enum or bytes
if let Some(expected_py) = &self.expected_py {
if let Some(v) = expected_py.as_ref(py).get_item(input)? {
// We don't use ? to unpack the result of `get_item` in the next line because unhashable
// inputs will produce a TypeError, which in this case we just want to treat equivalently
// to a failed lookup
if let Ok(Some(v)) = expected_py.as_ref(py).get_item(input) {
let id: usize = v.extract().unwrap();
return Ok(Some((input, &self.values[id])));
}
Expand Down
32 changes: 32 additions & 0 deletions tests/validators/test_union.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,3 +771,35 @@ class BinaryEnum(IntEnum):
assert validator.validate_python(1) is not BinaryEnum.ONE
assert validator.validate_python(BinaryEnum.ZERO) is BinaryEnum.ZERO
assert validator.validate_python(BinaryEnum.ONE) is BinaryEnum.ONE


def test_model_and_literal_union() -> None:
# see https://github.com/pydantic/pydantic/issues/8183
class ModelA:
pass

validator = SchemaValidator(
{
'type': 'union',
'choices': [
{
'type': 'model',
'cls': ModelA,
'schema': {
'type': 'model-fields',
'fields': {
'a': {'type': 'model-field', 'schema': {'type': 'int'}},
},
},
},
{'type': 'literal', 'expected': [True]},
],
}
)

# validation against Literal[True] fails bc of the unhashable dict
# A ValidationError is raised, not a ValueError, which allows the validation against the union to continue
m = validator.validate_python({'a': 42})
assert isinstance(m, ModelA)
assert m.a == 42
assert validator.validate_python(True) is True

0 comments on commit 5b63e7a

Please sign in to comment.