Skip to content

Commit 33fea1e

Browse files
authored
reject is_instance inputs based on their type, not the mode (#765)
1 parent a3b9788 commit 33fea1e

File tree

2 files changed

+41
-18
lines changed

2 files changed

+41
-18
lines changed

src/validators/is_instance.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use crate::input::Input;
99
use crate::recursion_guard::RecursionGuard;
1010
use crate::tools::SchemaDict;
1111

12-
use super::InputType;
1312
use super::{BuildValidator, CombinedValidator, Definitions, DefinitionsBuilder, Extra, Validator};
1413

1514
#[derive(Debug, Clone)]
@@ -60,27 +59,26 @@ impl Validator for IsInstanceValidator {
6059
&'s self,
6160
py: Python<'data>,
6261
input: &'data impl Input<'data>,
63-
extra: &Extra,
62+
_extra: &Extra,
6463
_definitions: &'data Definitions<CombinedValidator>,
6564
_recursion_guard: &'s mut RecursionGuard,
6665
) -> ValResult<'data, PyObject> {
67-
match extra.mode {
68-
InputType::Json => Err(ValError::InternalErr(PyNotImplementedError::new_err(
69-
"Cannot check isinstance when validating from json,\
66+
if !input.is_python() {
67+
return Err(ValError::InternalErr(PyNotImplementedError::new_err(
68+
"Cannot check isinstance when validating from json, \
7069
use a JsonOrPython validator instead.",
71-
))),
72-
InputType::Python => {
73-
let ob = input.to_object(py);
74-
match ob.as_ref(py).is_instance(self.class.as_ref(py))? {
75-
true => Ok(ob),
76-
false => Err(ValError::new(
77-
ErrorType::IsInstanceOf {
78-
class: self.class_repr.clone(),
79-
},
80-
input,
81-
)),
82-
}
83-
}
70+
)));
71+
}
72+
73+
let ob = input.to_object(py);
74+
match ob.as_ref(py).is_instance(self.class.as_ref(py))? {
75+
true => Ok(ob),
76+
false => Err(ValError::new(
77+
ErrorType::IsInstanceOf {
78+
class: self.class_repr.clone(),
79+
},
80+
input,
81+
)),
8482
}
8583
}
8684

tests/validators/test_is_instance.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,28 @@ def test_class_repr():
164164
assert v.validate_python(1) == 1
165165
with pytest.raises(ValidationError, match=r'Input should be an instance of Foobar \[type=is_instance_of,'):
166166
v.validate_python('1')
167+
168+
169+
def test_is_instance_json_type_before_validator():
170+
# See https://github.com/pydantic/pydantic/issues/6573 - when using a
171+
# "before" validator to coerce JSON to valid Python input it should be
172+
# possible to use isinstance validation. This gives a way for things
173+
# such as type to have a valid input from JSON.
174+
175+
schema = core_schema.is_instance_schema(type)
176+
v = SchemaValidator(schema)
177+
178+
with pytest.raises(
179+
NotImplementedError,
180+
match='Cannot check isinstance when validating from json, use a JsonOrPython validator instead.',
181+
):
182+
v.validate_json('null')
183+
184+
# now wrap in a before validator
185+
def set_type_to_int(input: None) -> type:
186+
return int
187+
188+
schema = core_schema.no_info_before_validator_function(set_type_to_int, schema)
189+
v = SchemaValidator(schema)
190+
191+
assert v.validate_json('null') == int

0 commit comments

Comments
 (0)