Skip to content

Commit 5b63e7a

Browse files
Avoid using ? with get_item to handle unhashable inputs properly (#1089)
Co-authored-by: Samuel Colvin <s@muelcolvin.com>
1 parent 3840e00 commit 5b63e7a

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

src/validators/literal.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ impl<T: Debug> LiteralLookup<T> {
136136
}
137137
// must be an enum or bytes
138138
if let Some(expected_py) = &self.expected_py {
139-
if let Some(v) = expected_py.as_ref(py).get_item(input)? {
139+
// We don't use ? to unpack the result of `get_item` in the next line because unhashable
140+
// inputs will produce a TypeError, which in this case we just want to treat equivalently
141+
// to a failed lookup
142+
if let Ok(Some(v)) = expected_py.as_ref(py).get_item(input) {
140143
let id: usize = v.extract().unwrap();
141144
return Ok(Some((input, &self.values[id])));
142145
}

tests/validators/test_union.py

+32
Original file line numberDiff line numberDiff line change
@@ -771,3 +771,35 @@ class BinaryEnum(IntEnum):
771771
assert validator.validate_python(1) is not BinaryEnum.ONE
772772
assert validator.validate_python(BinaryEnum.ZERO) is BinaryEnum.ZERO
773773
assert validator.validate_python(BinaryEnum.ONE) is BinaryEnum.ONE
774+
775+
776+
def test_model_and_literal_union() -> None:
777+
# see https://github.com/pydantic/pydantic/issues/8183
778+
class ModelA:
779+
pass
780+
781+
validator = SchemaValidator(
782+
{
783+
'type': 'union',
784+
'choices': [
785+
{
786+
'type': 'model',
787+
'cls': ModelA,
788+
'schema': {
789+
'type': 'model-fields',
790+
'fields': {
791+
'a': {'type': 'model-field', 'schema': {'type': 'int'}},
792+
},
793+
},
794+
},
795+
{'type': 'literal', 'expected': [True]},
796+
],
797+
}
798+
)
799+
800+
# validation against Literal[True] fails bc of the unhashable dict
801+
# A ValidationError is raised, not a ValueError, which allows the validation against the union to continue
802+
m = validator.validate_python({'a': 42})
803+
assert isinstance(m, ModelA)
804+
assert m.a == 42
805+
assert validator.validate_python(True) is True

0 commit comments

Comments
 (0)