|
1 | 1 | // Validator for Enums, so named because "enum" is a reserved keyword in Rust.
|
2 | 2 | use std::marker::PhantomData;
|
3 | 3 |
|
| 4 | +use pyo3::exceptions::PyTypeError; |
4 | 5 | use pyo3::intern;
|
5 | 6 | use pyo3::prelude::*;
|
6 | 7 | use pyo3::types::{PyDict, PyFloat, PyInt, PyList, PyString, PyType};
|
7 | 8 |
|
8 | 9 | use crate::build_tools::{is_strict, py_schema_err};
|
9 | 10 | use crate::errors::{ErrorType, ValError, ValResult};
|
10 | 11 | use crate::input::Input;
|
11 |
| -use crate::tools::SchemaDict; |
| 12 | +use crate::tools::{safe_repr, SchemaDict}; |
12 | 13 |
|
13 | 14 | use super::is_instance::class_repr;
|
14 | 15 | use super::literal::{expected_repr_name, LiteralLookup};
|
@@ -118,7 +119,34 @@ impl<T: EnumValidateValue> Validator for EnumValidator<T> {
|
118 | 119 | } else if let Some(v) = T::validate_value(py, input, &self.lookup, strict)? {
|
119 | 120 | state.floor_exactness(Exactness::Lax);
|
120 | 121 | return Ok(v);
|
| 122 | + } else if let Some(ref missing) = self.missing { |
| 123 | + state.floor_exactness(Exactness::Lax); |
| 124 | + let enum_value = missing.bind(py).call1((input.to_object(py),)).map_err(|_| { |
| 125 | + ValError::new( |
| 126 | + ErrorType::Enum { |
| 127 | + expected: self.expected_repr.clone(), |
| 128 | + context: None, |
| 129 | + }, |
| 130 | + input, |
| 131 | + ) |
| 132 | + })?; |
| 133 | + // check enum_value is an instance of the class like |
| 134 | + // https://github.com/python/cpython/blob/v3.12.2/Lib/enum.py#L1148 |
| 135 | + if enum_value.is_instance(class)? { |
| 136 | + return Ok(enum_value.into()); |
| 137 | + } else if !enum_value.is(&py.None()) { |
| 138 | + let type_error = PyTypeError::new_err(format!( |
| 139 | + "error in {}._missing_: returned {} instead of None or a valid member", |
| 140 | + class |
| 141 | + .name() |
| 142 | + .and_then(|name| name.extract::<String>()) |
| 143 | + .unwrap_or_else(|_| "<Unknown>".into()), |
| 144 | + safe_repr(&enum_value) |
| 145 | + )); |
| 146 | + return Err(type_error.into()); |
| 147 | + } |
121 | 148 | } else if let Ok(res) = class.as_unbound().call1(py, (input.as_python(),)) {
|
| 149 | + // as a last result, just try to initialize the enum with the input |
122 | 150 | state.floor_exactness(Exactness::Lax);
|
123 | 151 | return Ok(res);
|
124 | 152 | }
|
|
0 commit comments