Skip to content

Commit

Permalink
Fix validation of Literal from JSON keys when used as dict key (#…
Browse files Browse the repository at this point in the history
…1075)

Co-authored-by: David Montague <35119617+dmontagu@users.noreply.github.com>
  • Loading branch information
sydney-runkle and dmontagu committed Nov 16, 2023
1 parent 3fea833 commit 203b395
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 4 deletions.
16 changes: 13 additions & 3 deletions src/validators/literal.rs
Expand Up @@ -9,7 +9,7 @@ use pyo3::{intern, PyTraverseError, PyVisit};

use crate::build_tools::{py_schema_err, py_schema_error_type};
use crate::errors::{ErrorType, ValError, ValResult};
use crate::input::Input;
use crate::input::{Input, ValidationMatch};
use crate::py_gc::PyGcTraverse;
use crate::tools::SchemaDict;

Expand Down Expand Up @@ -116,8 +116,18 @@ impl<T: Debug> LiteralLookup<T> {
}
}
if let Some(expected_strings) = &self.expected_str {
// dbg!(expected_strings);
if let Ok(either_str) = input.exact_str() {
let validation_result = if input.is_python() {
input.exact_str()
} else {
// Strings coming from JSON are treated as "strict" but not "exact" for reasons
// of parsing types like UUID; see the implementation of `validate_str` for Json
// inputs for justification. We might change that eventually, but for now we need
// to work around this when loading from JSON
// V3 TODO: revisit making this "exact" for JSON inputs
input.validate_str(true, false).map(ValidationMatch::into_inner)
};

if let Ok(either_str) = validation_result {
let cow = either_str.as_cow()?;
if let Some(id) = expected_strings.get(cow.as_ref()) {
return Ok(Some((input, &self.values[*id])));
Expand Down
33 changes: 32 additions & 1 deletion tests/test.rs
@@ -1,6 +1,6 @@
#[cfg(test)]
mod tests {
use _pydantic_core::SchemaSerializer;
use _pydantic_core::{SchemaSerializer, SchemaValidator};
use pyo3::prelude::*;
use pyo3::types::PyDict;

Expand Down Expand Up @@ -86,4 +86,35 @@ a = A()
assert_eq!(serialized, b"{\"b\":\"b\"}");
});
}

#[test]
fn test_literal_schema() {
Python::with_gil(|py| {
let code = r#"
schema = {
"type": "dict",
"keys_schema": {
"type": "literal",
"expected": ["a", "b"],
},
"values_schema": {
"type": "str",
},
"strict": False,
}
json_input = '{"a": "something"}'
"#;
let locals = PyDict::new(py);
py.run(code, None, Some(locals)).unwrap();
let schema: &PyDict = locals.get_item("schema").unwrap().unwrap().extract().unwrap();
let json_input: &PyAny = locals.get_item("json_input").unwrap().unwrap().extract().unwrap();
let binding = SchemaValidator::py_new(py, schema, None)
.unwrap()
.validate_json(py, json_input, None, None, None)
.unwrap();
let validation_result: &PyAny = binding.extract(py).unwrap();
let repr = format!("{}", validation_result.repr().unwrap());
assert_eq!(repr, "{'a': 'something'}");
});
}
}

0 comments on commit 203b395

Please sign in to comment.