diff --git a/src/errors/line_error.rs b/src/errors/line_error.rs index ecd4294098..9a9d6ef6f8 100644 --- a/src/errors/line_error.rs +++ b/src/errors/line_error.rs @@ -5,6 +5,7 @@ use pyo3::DowncastIntoError; use jiter::JsonValue; +use crate::input::BorrowInput; use crate::input::Input; use super::location::{LocItem, Location}; @@ -12,13 +13,19 @@ use super::types::ErrorType; pub type ValResult = Result; -pub trait AsErrorValue { - fn as_error_value(&self) -> InputValue; +pub trait ToErrorValue { + fn to_error_value(&self) -> InputValue; } -impl<'a, T: Input<'a>> AsErrorValue for T { - fn as_error_value(&self) -> InputValue { - Input::as_error_value(self) +impl<'a, T: BorrowInput<'a>> ToErrorValue for T { + fn to_error_value(&self) -> InputValue { + Input::as_error_value(self.borrow_input()) + } +} + +impl ToErrorValue for &'_ dyn ToErrorValue { + fn to_error_value(&self) -> InputValue { + (**self).to_error_value() } } @@ -55,11 +62,11 @@ impl From> for ValError { } impl ValError { - pub fn new(error_type: ErrorType, input: &impl AsErrorValue) -> ValError { + pub fn new(error_type: ErrorType, input: impl ToErrorValue) -> ValError { Self::LineErrors(vec![ValLineError::new(error_type, input)]) } - pub fn new_with_loc(error_type: ErrorType, input: &impl AsErrorValue, loc: impl Into) -> ValError { + pub fn new_with_loc(error_type: ErrorType, input: impl ToErrorValue, loc: impl Into) -> ValError { Self::LineErrors(vec![ValLineError::new_with_loc(error_type, input, loc)]) } @@ -94,26 +101,26 @@ pub struct ValLineError { } impl ValLineError { - pub fn new(error_type: ErrorType, input: &impl AsErrorValue) -> ValLineError { + pub fn new(error_type: ErrorType, input: impl ToErrorValue) -> ValLineError { Self { error_type, - input_value: input.as_error_value(), + input_value: input.to_error_value(), location: Location::default(), } } - pub fn new_with_loc(error_type: ErrorType, input: &impl AsErrorValue, loc: impl Into) -> ValLineError { + pub fn new_with_loc(error_type: ErrorType, input: impl ToErrorValue, loc: impl Into) -> ValLineError { Self { error_type, - input_value: input.as_error_value(), + input_value: input.to_error_value(), location: Location::new_some(loc.into()), } } - pub fn new_with_full_loc(error_type: ErrorType, input: &impl AsErrorValue, location: Location) -> ValLineError { + pub fn new_with_full_loc(error_type: ErrorType, input: impl ToErrorValue, location: Location) -> ValLineError { Self { error_type, - input_value: input.as_error_value(), + input_value: input.to_error_value(), location, } } diff --git a/src/errors/mod.rs b/src/errors/mod.rs index bee5f7225e..ffdda90e34 100644 --- a/src/errors/mod.rs +++ b/src/errors/mod.rs @@ -6,7 +6,7 @@ mod types; mod validation_exception; mod value_exception; -pub use self::line_error::{AsErrorValue, InputValue, ValError, ValLineError, ValResult}; +pub use self::line_error::{InputValue, ToErrorValue, ValError, ValLineError, ValResult}; pub use self::location::LocItem; pub use self::types::{list_all_errors, ErrorType, ErrorTypeDefaults, Number}; pub use self::validation_exception::ValidationError; diff --git a/src/errors/value_exception.rs b/src/errors/value_exception.rs index b8b484d89b..20ad6174a3 100644 --- a/src/errors/value_exception.rs +++ b/src/errors/value_exception.rs @@ -5,7 +5,7 @@ use pyo3::types::{PyDict, PyString}; use crate::input::InputType; use crate::tools::extract_i64; -use super::line_error::AsErrorValue; +use super::line_error::ToErrorValue; use super::{ErrorType, ValError}; #[pyclass(extends=PyException, module="pydantic_core._pydantic_core")] @@ -106,7 +106,7 @@ impl PydanticCustomError { } impl PydanticCustomError { - pub fn into_val_error(self, input: &impl AsErrorValue) -> ValError { + pub fn into_val_error(self, input: impl ToErrorValue) -> ValError { let error_type = ErrorType::CustomError { error_type: self.error_type, message_template: self.message_template, @@ -181,7 +181,7 @@ impl PydanticKnownError { } impl PydanticKnownError { - pub fn into_val_error(self, input: &impl AsErrorValue) -> ValError { + pub fn into_val_error(self, input: impl ToErrorValue) -> ValError { ValError::new(self.error_type, input) } } diff --git a/src/input/datetime.rs b/src/input/datetime.rs index a567bd3d2f..f8ae6929ef 100644 --- a/src/input/datetime.rs +++ b/src/input/datetime.rs @@ -14,6 +14,7 @@ use std::hash::Hasher; use strum::EnumMessage; use super::Input; +use crate::errors::ToErrorValue; use crate::errors::{ErrorType, ValError, ValResult}; use crate::tools::py_err; @@ -285,7 +286,7 @@ impl<'a> EitherDateTime<'a> { } } -pub fn bytes_as_date<'a>(input: &'a impl Input<'a>, bytes: &[u8]) -> ValResult> { +pub fn bytes_as_date<'py>(input: &(impl Input<'py> + ?Sized), bytes: &[u8]) -> ValResult> { match Date::parse_bytes(bytes) { Ok(date) => Ok(date.into()), Err(err) => Err(ValError::new( @@ -298,11 +299,11 @@ pub fn bytes_as_date<'a>(input: &'a impl Input<'a>, bytes: &[u8]) -> ValResult( - input: &'a impl Input<'a>, +pub fn bytes_as_time<'py>( + input: &(impl Input<'py> + ?Sized), bytes: &[u8], microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, -) -> ValResult> { +) -> ValResult> { match Time::parse_bytes_with_config( bytes, &TimeConfig { @@ -321,11 +322,11 @@ pub fn bytes_as_time<'a>( } } -pub fn bytes_as_datetime<'a, 'b>( - input: &'a impl Input<'a>, - bytes: &'b [u8], +pub fn bytes_as_datetime<'py>( + input: &(impl Input<'py> + ?Sized), + bytes: &[u8], microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, -) -> ValResult> { +) -> ValResult> { match DateTime::parse_bytes_with_config( bytes, &TimeConfig { @@ -344,11 +345,11 @@ pub fn bytes_as_datetime<'a, 'b>( } } -pub fn int_as_datetime<'a>( - input: &'a impl Input<'a>, +pub fn int_as_datetime<'py>( + input: &(impl Input<'py> + ?Sized), timestamp: i64, timestamp_microseconds: u32, -) -> ValResult { +) -> ValResult> { match DateTime::from_timestamp_with_config( timestamp, timestamp_microseconds, @@ -382,7 +383,7 @@ macro_rules! nan_check { }; } -pub fn float_as_datetime<'a>(input: &'a impl Input<'a>, timestamp: f64) -> ValResult { +pub fn float_as_datetime<'py>(input: &(impl Input<'py> + ?Sized), timestamp: f64) -> ValResult> { nan_check!(input, timestamp, DatetimeParsing); let microseconds = timestamp.fract().abs() * 1_000_000.0; // checking for extra digits in microseconds is unreliable with large floats, @@ -408,11 +409,11 @@ pub fn date_as_datetime<'py>(date: &Bound<'py, PyDate>) -> PyResult( - input: &'a impl Input<'a>, +pub fn int_as_time<'py>( + input: &(impl Input<'py> + ?Sized), timestamp: i64, timestamp_microseconds: u32, -) -> ValResult { +) -> ValResult> { let time_timestamp: u32 = match timestamp { t if t < 0_i64 => { return Err(ValError::new( @@ -447,14 +448,14 @@ pub fn int_as_time<'a>( } } -pub fn float_as_time<'a>(input: &'a impl Input<'a>, timestamp: f64) -> ValResult { +pub fn float_as_time<'py>(input: &(impl Input<'py> + ?Sized), timestamp: f64) -> ValResult> { nan_check!(input, timestamp, TimeParsing); let microseconds = timestamp.fract().abs() * 1_000_000.0; // round for same reason as above int_as_time(input, timestamp.floor() as i64, microseconds.round() as u32) } -fn map_timedelta_err<'a>(input: &'a impl Input<'a>, err: ParseError) -> ValError { +fn map_timedelta_err(input: impl ToErrorValue, err: ParseError) -> ValError { ValError::new( ErrorType::TimeDeltaParsing { error: Cow::Borrowed(err.get_documentation().unwrap_or_default()), @@ -464,11 +465,11 @@ fn map_timedelta_err<'a>(input: &'a impl Input<'a>, err: ParseError) -> ValError ) } -pub fn bytes_as_timedelta<'a, 'b>( - input: &'a impl Input<'a>, - bytes: &'b [u8], +pub fn bytes_as_timedelta<'py>( + input: &(impl Input<'py> + ?Sized), + bytes: &[u8], microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, -) -> ValResult> { +) -> ValResult> { match Duration::parse_bytes_with_config( bytes, &TimeConfig { @@ -481,7 +482,7 @@ pub fn bytes_as_timedelta<'a, 'b>( } } -pub fn int_as_duration<'a>(input: &'a impl Input<'a>, total_seconds: i64) -> ValResult { +pub fn int_as_duration(input: impl ToErrorValue, total_seconds: i64) -> ValResult { let positive = total_seconds >= 0; let total_seconds = total_seconds.unsigned_abs(); // we can safely unwrap here since we've guaranteed seconds and microseconds can't cause overflow @@ -490,7 +491,7 @@ pub fn int_as_duration<'a>(input: &'a impl Input<'a>, total_seconds: i64) -> Val Duration::new(positive, days, seconds, 0).map_err(|err| map_timedelta_err(input, err)) } -pub fn float_as_duration<'a>(input: &'a impl Input<'a>, total_seconds: f64) -> ValResult { +pub fn float_as_duration(input: impl ToErrorValue, total_seconds: f64) -> ValResult { nan_check!(input, total_seconds, TimeDeltaParsing); let positive = total_seconds >= 0_f64; let total_seconds = total_seconds.abs(); diff --git a/src/input/input_abstract.rs b/src/input/input_abstract.rs index 4198e72026..553f0b33c0 100644 --- a/src/input/input_abstract.rs +++ b/src/input/input_abstract.rs @@ -4,7 +4,7 @@ use pyo3::exceptions::PyValueError; use pyo3::types::{PyDict, PyType}; use pyo3::{intern, prelude::*}; -use crate::errors::{ErrorTypeDefaults, InputValue, LocItem, ValError, ValResult}; +use crate::errors::{ErrorTypeDefaults, InputValue, ValError, ValResult}; use crate::tools::py_err; use crate::{PyMultiHostUrl, PyUrl}; @@ -46,7 +46,7 @@ impl TryFrom<&str> for InputType { /// the convention is to either implement: /// * `strict_*` & `lax_*` if they have different behavior /// * or, `validate_*` and `strict_*` to just call `validate_*` if the behavior for strict and lax is the same -pub trait Input<'py>: fmt::Debug + ToPyObject + Into + Sized { +pub trait Input<'py>: fmt::Debug + ToPyObject { fn as_error_value(&self) -> InputValue; fn identity(&self) -> Option { @@ -83,9 +83,9 @@ pub trait Input<'py>: fmt::Debug + ToPyObject + Into + Sized { false } - fn validate_args(&self) -> ValResult>; + fn validate_args(&self) -> ValResult>; - fn validate_dataclass_args<'a>(&'a self, dataclass_name: &str) -> ValResult>; + fn validate_dataclass_args<'a>(&'a self, dataclass_name: &str) -> ValResult>; fn validate_str(&self, strict: bool, coerce_numbers_to_str: bool) -> ValResult>>; @@ -201,25 +201,25 @@ pub trait Input<'py>: fmt::Debug + ToPyObject + Into + Sized { fn validate_iter(&self) -> ValResult; - fn validate_date(&self, strict: bool) -> ValResult>; + fn validate_date(&self, strict: bool) -> ValResult>>; fn validate_time( &self, strict: bool, microseconds_overflow_behavior: speedate::MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult>; + ) -> ValResult>>; fn validate_datetime( &self, strict: bool, microseconds_overflow_behavior: speedate::MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult>; + ) -> ValResult>>; fn validate_timedelta( &self, strict: bool, microseconds_overflow_behavior: speedate::MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult>; + ) -> ValResult>>; } /// The problem to solve here is that iterating collections often returns owned @@ -228,6 +228,13 @@ pub trait Input<'py>: fmt::Debug + ToPyObject + Into + Sized { /// or borrowed; all we care about is that we can borrow it again with `borrow_input` /// for some lifetime 'a. pub trait BorrowInput<'py> { - type Input: Input<'py>; + type Input: Input<'py> + ?Sized; fn borrow_input(&self) -> &Self::Input; } + +impl<'py, T: Input<'py> + ?Sized> BorrowInput<'py> for &'_ T { + type Input = T; + fn borrow_input(&self) -> &Self::Input { + self + } +} diff --git a/src/input/input_json.rs b/src/input/input_json.rs index 86cfe69e46..53a261d811 100644 --- a/src/input/input_json.rs +++ b/src/input/input_json.rs @@ -60,7 +60,7 @@ impl<'py> Input<'py> for JsonValue { } } - fn validate_args(&self) -> ValResult> { + fn validate_args(&self) -> ValResult> { match self { JsonValue::Object(object) => Ok(JsonArgs::new(None, Some(object)).into()), JsonValue::Array(array) => Ok(JsonArgs::new(Some(array), None).into()), @@ -68,7 +68,7 @@ impl<'py> Input<'py> for JsonValue { } } - fn validate_dataclass_args<'a>(&'a self, class_name: &str) -> ValResult> { + fn validate_dataclass_args<'a>(&'a self, class_name: &str) -> ValResult> { match self { JsonValue::Object(object) => Ok(JsonArgs::new(None, Some(object)).into()), _ => { @@ -241,7 +241,7 @@ impl<'py> Input<'py> for JsonValue { } } - fn validate_date(&self, _strict: bool) -> ValResult> { + fn validate_date(&self, _strict: bool) -> ValResult>> { match self { JsonValue::Str(v) => bytes_as_date(self, v.as_bytes()).map(ValidationMatch::strict), _ => Err(ValError::new(ErrorTypeDefaults::DateType, self)), @@ -251,7 +251,7 @@ impl<'py> Input<'py> for JsonValue { &self, strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { match self { JsonValue::Str(v) => { bytes_as_time(self, v.as_bytes(), microseconds_overflow_behavior).map(ValidationMatch::strict) @@ -277,7 +277,7 @@ impl<'py> Input<'py> for JsonValue { &self, strict: bool, microseconds_overflow_behavior: speedate::MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { match self { JsonValue::Str(v) => { bytes_as_datetime(self, v.as_bytes(), microseconds_overflow_behavior).map(ValidationMatch::strict) @@ -292,7 +292,7 @@ impl<'py> Input<'py> for JsonValue { &self, strict: bool, microseconds_overflow_behavior: speedate::MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { match self { JsonValue::Str(v) => { bytes_as_timedelta(self, v.as_bytes(), microseconds_overflow_behavior).map(ValidationMatch::strict) @@ -308,19 +308,12 @@ impl<'py> Input<'py> for JsonValue { } } -impl BorrowInput<'_> for &'_ JsonValue { - type Input = JsonValue; - fn borrow_input(&self) -> &Self::Input { - self - } -} - /// Required for JSON Object keys so the string can behave like an Input -impl<'py> Input<'py> for String { +impl<'py> Input<'py> for str { fn as_error_value(&self) -> InputValue { // Justification for the clone: this is on the error pathway and we are generally ok // with errors having a performance penalty - InputValue::Json(JsonValue::Str(self.clone())) + InputValue::Json(JsonValue::Str(self.to_owned())) } fn as_kwargs(&self, _py: Python<'py>) -> Option> { @@ -328,12 +321,12 @@ impl<'py> Input<'py> for String { } #[cfg_attr(has_coverage_attribute, coverage(off))] - fn validate_args(&self) -> ValResult> { + fn validate_args(&self) -> ValResult> { Err(ValError::new(ErrorTypeDefaults::ArgumentsType, self)) } #[cfg_attr(has_coverage_attribute, coverage(off))] - fn validate_dataclass_args<'a>(&'a self, class_name: &str) -> ValResult> { + fn validate_dataclass_args<'a>(&'a self, class_name: &str) -> ValResult> { let class_name = class_name.to_string(); Err(ValError::new( ErrorType::DataclassType { @@ -354,7 +347,7 @@ impl<'py> Input<'py> for String { // converting input // TODO: in V3 we may want to make JSON str always win if in union, for consistency, // see https://github.com/pydantic/pydantic-core/pull/867#discussion_r1386582501 - Ok(ValidationMatch::strict(self.as_str().into())) + Ok(ValidationMatch::strict(self.into())) } fn validate_bytes<'a>(&'a self, _strict: bool) -> ValResult>> { @@ -410,7 +403,7 @@ impl<'py> Input<'py> for String { Ok(string_to_vec(self).into()) } - fn validate_date(&self, _strict: bool) -> ValResult> { + fn validate_date(&self, _strict: bool) -> ValResult>> { bytes_as_date(self, self.as_bytes()).map(ValidationMatch::lax) } @@ -418,7 +411,7 @@ impl<'py> Input<'py> for String { &self, _strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { bytes_as_time(self, self.as_bytes(), microseconds_overflow_behavior).map(ValidationMatch::lax) } @@ -426,7 +419,7 @@ impl<'py> Input<'py> for String { &self, _strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { bytes_as_datetime(self, self.as_bytes(), microseconds_overflow_behavior).map(ValidationMatch::lax) } @@ -434,20 +427,20 @@ impl<'py> Input<'py> for String { &self, _strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { bytes_as_timedelta(self, self.as_bytes(), microseconds_overflow_behavior).map(ValidationMatch::lax) } } impl BorrowInput<'_> for &'_ String { - type Input = String; + type Input = str; fn borrow_input(&self) -> &Self::Input { self } } impl BorrowInput<'_> for String { - type Input = String; + type Input = str; fn borrow_input(&self) -> &Self::Input { self } diff --git a/src/input/input_python.rs b/src/input/input_python.rs index c74942caef..edc9aec04c 100644 --- a/src/input/input_python.rs +++ b/src/input/input_python.rs @@ -160,7 +160,7 @@ impl<'py> Input<'py> for Bound<'py, PyAny> { self.is_callable() } - fn validate_args(&self) -> ValResult> { + fn validate_args(&self) -> ValResult> { if let Ok(dict) = self.downcast::() { Ok(PyArgs::new(None, Some(dict.clone())).into()) } else if let Ok(args_kwargs) = self.extract::() { @@ -176,7 +176,7 @@ impl<'py> Input<'py> for Bound<'py, PyAny> { } } - fn validate_dataclass_args<'a>(&'a self, class_name: &str) -> ValResult> { + fn validate_dataclass_args<'a>(&'a self, class_name: &str) -> ValResult> { if let Ok(dict) = self.downcast::() { Ok(PyArgs::new(None, Some(dict.clone())).into()) } else if let Ok(args_kwargs) = self.extract::() { @@ -584,7 +584,7 @@ impl<'py> Input<'py> for Bound<'py, PyAny> { } } - fn validate_date(&self, strict: bool) -> ValResult> { + fn validate_date(&self, strict: bool) -> ValResult>> { if let Ok(date) = self.downcast_exact::() { Ok(ValidationMatch::exact(date.clone().into())) } else if self.is_instance_of::() { @@ -615,7 +615,7 @@ impl<'py> Input<'py> for Bound<'py, PyAny> { &self, strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { if let Ok(time) = self.downcast_exact::() { return Ok(ValidationMatch::exact(time.clone().into())); } else if let Ok(time) = self.downcast::() { @@ -649,7 +649,7 @@ impl<'py> Input<'py> for Bound<'py, PyAny> { &self, strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { if let Ok(dt) = self.downcast_exact::() { return Ok(ValidationMatch::exact(dt.clone().into())); } else if let Ok(dt) = self.downcast::() { @@ -685,7 +685,7 @@ impl<'py> Input<'py> for Bound<'py, PyAny> { &self, strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { if let Ok(either_dt) = EitherTimedelta::try_from(self) { let exactness = if matches!(either_dt, EitherTimedelta::PyExact(_)) { Exactness::Exact diff --git a/src/input/input_string.rs b/src/input/input_string.rs index 61a41cd345..486dff5ffb 100644 --- a/src/input/input_string.rs +++ b/src/input/input_string.rs @@ -73,12 +73,12 @@ impl<'py> Input<'py> for StringMapping<'py> { None } - fn validate_args(&self) -> ValResult> { + fn validate_args(&self) -> ValResult> { // do we want to support this? Err(ValError::new(ErrorTypeDefaults::ArgumentsType, self)) } - fn validate_dataclass_args<'a>(&'a self, _dataclass_name: &str) -> ValResult> { + fn validate_dataclass_args<'a>(&'a self, _dataclass_name: &str) -> ValResult> { match self { StringMapping::String(_) => Err(ValError::new(ErrorTypeDefaults::ArgumentsType, self)), StringMapping::Mapping(m) => Ok(GenericArguments::StringMapping(m.clone())), @@ -162,7 +162,7 @@ impl<'py> Input<'py> for StringMapping<'py> { Err(ValError::new(ErrorTypeDefaults::IterableType, self)) } - fn validate_date(&self, _strict: bool) -> ValResult> { + fn validate_date(&self, _strict: bool) -> ValResult>> { match self { Self::String(s) => bytes_as_date(self, py_string_str(s)?.as_bytes()).map(ValidationMatch::strict), Self::Mapping(_) => Err(ValError::new(ErrorTypeDefaults::DateType, self)), @@ -173,7 +173,7 @@ impl<'py> Input<'py> for StringMapping<'py> { &self, _strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { match self { Self::String(s) => bytes_as_time(self, py_string_str(s)?.as_bytes(), microseconds_overflow_behavior) .map(ValidationMatch::strict), @@ -185,7 +185,7 @@ impl<'py> Input<'py> for StringMapping<'py> { &self, _strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { match self { Self::String(s) => bytes_as_datetime(self, py_string_str(s)?.as_bytes(), microseconds_overflow_behavior) .map(ValidationMatch::strict), @@ -197,7 +197,7 @@ impl<'py> Input<'py> for StringMapping<'py> { &self, _strict: bool, microseconds_overflow_behavior: MicrosecondsPrecisionOverflowBehavior, - ) -> ValResult> { + ) -> ValResult>> { match self { Self::String(s) => bytes_as_timedelta(self, py_string_str(s)?.as_bytes(), microseconds_overflow_behavior) .map(ValidationMatch::strict), diff --git a/src/input/return_enums.rs b/src/input/return_enums.rs index b365500e0e..a6db98710f 100644 --- a/src/input/return_enums.rs +++ b/src/input/return_enums.rs @@ -20,7 +20,9 @@ use pyo3::{ffi, intern}; use pyo3::types::PyFunction; use serde::{ser::Error, Serialize, Serializer}; -use crate::errors::{py_err_string, ErrorType, ErrorTypeDefaults, InputValue, ValError, ValLineError, ValResult}; +use crate::errors::{ + py_err_string, ErrorType, ErrorTypeDefaults, InputValue, ToErrorValue, ValError, ValLineError, ValResult, +}; use crate::tools::{extract_i64, py_err}; use crate::validators::{CombinedValidator, Exactness, ValidationState, Validator}; @@ -83,7 +85,7 @@ pub enum GenericIterable<'a, 'py> { Iterator(Bound<'py, PyIterator>), JsonArray(&'a [JsonValue]), JsonObject(&'a JsonObject), - JsonString(&'a String), + JsonString(&'a str), } impl<'py> GenericIterable<'_, 'py> { @@ -121,8 +123,7 @@ impl<'py> GenericIterable<'_, 'py> { } } -#[derive(Debug)] -struct MaxLengthCheck<'a, INPUT> { +struct MaxLengthCheck<'a, INPUT: ?Sized> { current_length: usize, max_length: Option, field_type: &'a str, @@ -130,7 +131,7 @@ struct MaxLengthCheck<'a, INPUT> { actual_length: Option, } -impl<'a, INPUT> MaxLengthCheck<'a, INPUT> { +impl<'a, INPUT: ?Sized> MaxLengthCheck<'a, INPUT> { fn new(max_length: Option, field_type: &'a str, input: &'a INPUT, actual_length: Option) -> Self { Self { current_length: 0, @@ -142,19 +143,19 @@ impl<'a, INPUT> MaxLengthCheck<'a, INPUT> { } } -impl<'a, INPUT: Input<'a>> MaxLengthCheck<'_, INPUT> { +impl<'py, INPUT: Input<'py> + ?Sized> MaxLengthCheck<'_, INPUT> { fn incr(&mut self) -> ValResult<()> { if let Some(max_length) = self.max_length { self.current_length += 1; if self.current_length > max_length { - return Err(ValError::new( + return Err(ValError::new_custom_input( ErrorType::TooLong { field_type: self.field_type.to_string(), max_length, actual_length: self.actual_length, context: None, }, - self.input, + self.input.to_error_value(), )); } } @@ -176,13 +177,13 @@ macro_rules! any_next_error { } #[allow(clippy::too_many_arguments)] -fn validate_iter_to_vec<'a, 's>( - py: Python<'a>, - iter: impl Iterator>>, +fn validate_iter_to_vec<'py>( + py: Python<'py>, + iter: impl Iterator>>, capacity: usize, - mut max_length_check: MaxLengthCheck<'_, impl Input<'a>>, - validator: &'s CombinedValidator, - state: &mut ValidationState, + mut max_length_check: MaxLengthCheck<'_, impl Input<'py> + ?Sized>, + validator: &CombinedValidator, + state: &mut ValidationState<'_, 'py>, ) -> ValResult> { let mut output: Vec = Vec::with_capacity(capacity); let mut errors: Vec = Vec::new(); @@ -240,15 +241,15 @@ impl BuildSet for Bound<'_, PyFrozenSet> { } #[allow(clippy::too_many_arguments)] -fn validate_iter_to_set<'a, 's>( - py: Python<'a>, +fn validate_iter_to_set<'py>( + py: Python<'py>, set: &impl BuildSet, - iter: impl Iterator>>, - input: &impl Input<'a>, + iter: impl Iterator>>, + input: &(impl Input<'py> + ?Sized), field_type: &'static str, max_length: Option, - validator: &'s CombinedValidator, - state: &mut ValidationState, + validator: &CombinedValidator, + state: &mut ValidationState<'_, 'py>, ) -> ValResult<()> { let mut errors: Vec = Vec::new(); for (index, item_result) in iter.enumerate() { @@ -290,9 +291,9 @@ fn validate_iter_to_set<'a, 's>( fn no_validator_iter_to_vec<'py>( py: Python<'py>, - input: &impl Input<'py>, + input: &(impl Input<'py> + ?Sized), iter: impl Iterator>>, - mut max_length_check: MaxLengthCheck<'_, impl Input<'py>>, + mut max_length_check: MaxLengthCheck<'_, impl Input<'py> + ?Sized>, ) -> ValResult> { iter.enumerate() .map(|(index, result)| { @@ -333,11 +334,11 @@ impl<'py> GenericIterable<'_, 'py> { pub fn validate_to_vec( &self, py: Python<'py>, - input: &impl Input<'py>, + input: &(impl Input<'py> + ?Sized), max_length: Option, field_type: &'static str, validator: &CombinedValidator, - state: &mut ValidationState, + state: &mut ValidationState<'_, 'py>, ) -> ValResult> { let actual_length = self.generic_len(); let capacity = actual_length.unwrap_or(DEFAULT_CAPACITY); @@ -366,11 +367,11 @@ impl<'py> GenericIterable<'_, 'py> { &self, py: Python<'py>, set: &impl BuildSet, - input: &impl Input<'py>, + input: &(impl Input<'py> + ?Sized), max_length: Option, field_type: &'static str, validator: &CombinedValidator, - state: &mut ValidationState, + state: &mut ValidationState<'_, 'py>, ) -> ValResult<()> { macro_rules! validate_set { ($iter:expr) => { @@ -393,7 +394,7 @@ impl<'py> GenericIterable<'_, 'py> { pub fn to_vec( &self, py: Python<'py>, - input: &impl Input<'py>, + input: &(impl Input<'py> + ?Sized), field_type: &'static str, max_length: Option, ) -> ValResult> { @@ -479,7 +480,7 @@ pub struct MappingGenericIterator<'py> { iter: Bound<'py, PyIterator>, } -fn mapping_err<'py>(err: PyErr, py: Python<'py>, input: &'py impl Input<'py>) -> ValError { +fn mapping_err<'py>(err: PyErr, py: Python<'py>, input: &'py (impl Input<'py> + ?Sized)) -> ValError { ValError::new( ErrorType::MappingType { error: py_err_string(py, err).into(), @@ -742,20 +743,20 @@ impl<'a> JsonArgs<'a> { } #[cfg_attr(debug_assertions, derive(Debug))] -pub enum GenericArguments<'a> { - Py(PyArgs<'a>), +pub enum GenericArguments<'a, 'py> { + Py(PyArgs<'py>), Json(JsonArgs<'a>), - StringMapping(Bound<'a, PyDict>), + StringMapping(Bound<'py, PyDict>), } -impl<'a> From> for GenericArguments<'a> { - fn from(s: PyArgs<'a>) -> GenericArguments<'a> { +impl<'py> From> for GenericArguments<'_, 'py> { + fn from(s: PyArgs<'py>) -> Self { Self::Py(s) } } -impl<'a> From> for GenericArguments<'a> { - fn from(s: JsonArgs<'a>) -> GenericArguments<'a> { +impl<'a> From> for GenericArguments<'a, '_> { + fn from(s: JsonArgs<'a>) -> Self { Self::Json(s) } } diff --git a/src/input/shared.rs b/src/input/shared.rs index 2f8edf6ade..5f0040e3e7 100644 --- a/src/input/shared.rs +++ b/src/input/shared.rs @@ -20,7 +20,7 @@ pub fn get_enum_meta_object(py: Python) -> &Bound<'_, PyAny> { .bind(py) } -pub fn str_as_bool<'py>(input: &impl Input<'py>, str: &str) -> ValResult { +pub fn str_as_bool<'py>(input: &(impl Input<'py> + ?Sized), str: &str) -> ValResult { if str == "0" || str.eq_ignore_ascii_case("f") || str.eq_ignore_ascii_case("n") @@ -42,7 +42,7 @@ pub fn str_as_bool<'py>(input: &impl Input<'py>, str: &str) -> ValResult { } } -pub fn int_as_bool<'py>(input: &impl Input<'py>, int: i64) -> ValResult { +pub fn int_as_bool<'py>(input: &(impl Input<'py> + ?Sized), int: i64) -> ValResult { if int == 0 { Ok(false) } else if int == 1 { @@ -72,7 +72,7 @@ fn strip_underscores(s: &str) -> Option { /// max length of the input is 4300, see /// https://docs.python.org/3/whatsnew/3.11.html#other-cpython-implementation-changes and /// https://github.com/python/cpython/issues/95778 for more info in that length bound -pub fn str_as_int<'s>(input: &'s impl Input<'s>, str: &str) -> ValResult> { +pub fn str_as_int<'py>(input: &(impl Input<'py> + ?Sized), str: &str) -> ValResult> { let str = str.trim(); let len = str.len(); if len > 4300 { @@ -97,7 +97,7 @@ pub fn str_as_int<'s>(input: &'s impl Input<'s>, str: &str) -> ValResult(input: &'s impl Input<'s>, str: &str) -> ValResult> { +pub fn str_as_float<'py>(input: &(impl Input<'py> + ?Sized), str: &str) -> ValResult> { match str.trim().parse() { Ok(float) => Ok(EitherFloat::F64(float)), Err(_) => match strip_underscores(str).and_then(|stripped| stripped.parse().ok()) { @@ -109,7 +109,7 @@ pub fn str_as_float<'s>(input: &'s impl Input<'s>, str: &str) -> ValResult(_input: &'s impl Input<'s>, str: &str, len: usize) -> Option> { +fn _parse_str<'py>(_input: &(impl Input<'py> + ?Sized), str: &str, len: usize) -> Option> { if len < 19 { if let Ok(i) = str.parse::() { return Some(EitherInt::I64(i)); @@ -131,7 +131,7 @@ fn strip_decimal_zeros(s: &str) -> Option<&str> { None } -pub fn float_as_int<'a>(input: &'a impl Input<'a>, float: f64) -> ValResult> { +pub fn float_as_int<'py>(input: &(impl Input<'py> + ?Sized), float: f64) -> ValResult> { if float.is_infinite() || float.is_nan() { Err(ValError::new(ErrorTypeDefaults::FiniteNumber, input)) } else if float % 1.0 != 0.0 { @@ -143,7 +143,10 @@ pub fn float_as_int<'a>(input: &'a impl Input<'a>, float: f64) -> ValResult(input: &'a impl Input<'a>, decimal: &Bound<'a, PyAny>) -> ValResult> { +pub fn decimal_as_int<'py>( + input: &(impl Input<'py> + ?Sized), + decimal: &Bound<'py, PyAny>, +) -> ValResult> { let py = decimal.py(); if !decimal.call_method0(intern!(py, "is_finite"))?.extract::()? { return Err(ValError::new(ErrorTypeDefaults::FiniteNumber, input)); diff --git a/src/lookup_key.rs b/src/lookup_key.rs index d8f8aac618..a7772a184e 100644 --- a/src/lookup_key.rs +++ b/src/lookup_key.rs @@ -8,8 +8,8 @@ use pyo3::types::{PyDict, PyList, PyMapping, PyString}; use jiter::{JsonObject, JsonValue}; use crate::build_tools::py_schema_err; -use crate::errors::{py_err_string, ErrorType, ValError, ValLineError, ValResult}; -use crate::input::{Input, StringMapping}; +use crate::errors::{py_err_string, ErrorType, ToErrorValue, ValError, ValLineError, ValResult}; +use crate::input::StringMapping; use crate::tools::{extract_i64, py_err}; /// Used for getting items from python dicts, python objects, or JSON objects, in different ways @@ -307,10 +307,10 @@ impl LookupKey { } } - pub fn error<'d>( + pub fn error( &self, error_type: ErrorType, - input: &impl Input<'d>, + input: impl ToErrorValue, loc_by_alias: bool, field_name: &str, ) -> ValLineError { diff --git a/src/validators/any.rs b/src/validators/any.rs index a274ff6422..d254cb31b7 100644 --- a/src/validators/any.rs +++ b/src/validators/any.rs @@ -30,8 +30,8 @@ impl Validator for AnyValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { // in a union, Any should be preferred to doing lax coercions state.floor_exactness(Exactness::Strict); diff --git a/src/validators/arguments.rs b/src/validators/arguments.rs index 33a9e504ab..e2e2d13deb 100644 --- a/src/validators/arguments.rs +++ b/src/validators/arguments.rs @@ -169,8 +169,8 @@ impl Validator for ArgumentsValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let args = input.validate_args()?; diff --git a/src/validators/bool.rs b/src/validators/bool.rs index 81f7d51df8..d09fbd5f03 100644 --- a/src/validators/bool.rs +++ b/src/validators/bool.rs @@ -33,8 +33,8 @@ impl Validator for BoolValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { // TODO in theory this could be quicker if we used PyBool rather than going to a bool // and back again, might be worth profiling? diff --git a/src/validators/bytes.rs b/src/validators/bytes.rs index ded9da1127..eb9d9441d1 100644 --- a/src/validators/bytes.rs +++ b/src/validators/bytes.rs @@ -43,8 +43,8 @@ impl Validator for BytesValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { input .validate_bytes(state.strict_or(self.strict)) @@ -69,8 +69,8 @@ impl Validator for BytesConstrainedValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let either_bytes = input.validate_bytes(state.strict_or(self.strict))?.unpack(state); let len = either_bytes.len()?; diff --git a/src/validators/call.rs b/src/validators/call.rs index 09f0fa771a..6783a5eda6 100644 --- a/src/validators/call.rs +++ b/src/validators/call.rs @@ -78,8 +78,8 @@ impl Validator for CallValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let args = self.arguments_validator.validate(py, input, state)?.into_bound(py); diff --git a/src/validators/callable.rs b/src/validators/callable.rs index 15c3c3c6b9..235dc6dd09 100644 --- a/src/validators/callable.rs +++ b/src/validators/callable.rs @@ -28,8 +28,8 @@ impl Validator for CallableValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { state.floor_exactness(Exactness::Lax); match input.callable() { diff --git a/src/validators/chain.rs b/src/validators/chain.rs index 0b20b142ed..f7137d398c 100644 --- a/src/validators/chain.rs +++ b/src/validators/chain.rs @@ -73,8 +73,8 @@ impl Validator for ChainValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let mut steps_iter = self.steps.iter(); let first_step = steps_iter.next().unwrap(); diff --git a/src/validators/custom_error.rs b/src/validators/custom_error.rs index 44dffbdb5b..6759f77958 100644 --- a/src/validators/custom_error.rs +++ b/src/validators/custom_error.rs @@ -3,7 +3,7 @@ use pyo3::prelude::*; use pyo3::types::PyDict; use crate::build_tools::py_schema_err; -use crate::errors::AsErrorValue; +use crate::errors::ToErrorValue; use crate::errors::{ErrorType, PydanticCustomError, PydanticKnownError, ValError, ValResult}; use crate::input::Input; use crate::tools::SchemaDict; @@ -49,7 +49,7 @@ impl CustomError { } } - pub fn as_val_error(&self, input: &impl AsErrorValue) -> ValError { + pub fn as_val_error(&self, input: impl ToErrorValue) -> ValError { match self { CustomError::KnownError(ref known_error) => known_error.clone().into_val_error(input), CustomError::Custom(ref custom_error) => custom_error.clone().into_val_error(input), @@ -91,8 +91,8 @@ impl Validator for CustomErrorValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { self.validator .validate(py, input, state) diff --git a/src/validators/dataclass.rs b/src/validators/dataclass.rs index 68067ef784..e2b479fbdc 100644 --- a/src/validators/dataclass.rs +++ b/src/validators/dataclass.rs @@ -144,8 +144,8 @@ impl Validator for DataclassArgsValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let args = input.validate_dataclass_args(&self.dataclass_name)?; @@ -382,13 +382,13 @@ impl Validator for DataclassArgsValidator { } } - fn validate_assignment<'data>( + fn validate_assignment<'py>( &self, - py: Python<'data>, - obj: &Bound<'data, PyAny>, + py: Python<'py>, + obj: &Bound<'py, PyAny>, field_name: &str, - field_value: &Bound<'data, PyAny>, - state: &mut ValidationState, + field_value: &Bound<'py, PyAny>, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let dict = obj.downcast::()?; @@ -532,8 +532,8 @@ impl Validator for DataclassValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { if let Some(self_instance) = state.extra().self_instance { // in the case that self_instance is Some, we're calling validation from within `BaseModel.__init__` @@ -569,13 +569,13 @@ impl Validator for DataclassValidator { } } - fn validate_assignment<'data>( + fn validate_assignment<'py>( &self, - py: Python<'data>, - obj: &Bound<'data, PyAny>, + py: Python<'py>, + obj: &Bound<'py, PyAny>, field_name: &str, - field_value: &Bound<'data, PyAny>, - state: &mut ValidationState, + field_value: &Bound<'py, PyAny>, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { if self.frozen { return Err(ValError::new(ErrorTypeDefaults::FrozenInstance, field_value)); @@ -610,12 +610,12 @@ impl Validator for DataclassValidator { impl DataclassValidator { /// here we just call the inner validator, then set attributes on `self_instance` - fn validate_init<'s, 'data>( - &'s self, - py: Python<'data>, + fn validate_init<'py>( + &self, + py: Python<'py>, self_instance: &Bound<'_, PyAny>, - input: &impl Input<'data>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { // we need to set `self_instance` to None for nested validators as we don't want to operate on the self_instance // instance anymore @@ -637,12 +637,12 @@ impl DataclassValidator { Ok(dict) } - fn set_dict_call<'s, 'data>( - &'s self, - py: Python<'data>, + fn set_dict_call<'py>( + &self, + py: Python<'py>, dc: &Bound<'_, PyAny>, val_output: PyObject, - input: &impl Input<'data>, + input: &(impl Input<'py> + ?Sized), ) -> ValResult<()> { let (dc_dict, post_init_kwargs): (Bound<'_, PyAny>, Bound<'_, PyAny>) = val_output.extract(py)?; if self.slots { diff --git a/src/validators/date.rs b/src/validators/date.rs index c34d9eeafe..75aefa9351 100644 --- a/src/validators/date.rs +++ b/src/validators/date.rs @@ -42,8 +42,8 @@ impl Validator for DateValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let strict = state.strict_or(self.strict); let date = match input.validate_date(strict) { @@ -109,7 +109,7 @@ impl Validator for DateValidator { /// "exact date", e.g. has a zero time component. /// /// Ok(None) means that this is not relevant to dates (the input was not a datetime nor a string) -fn date_from_datetime<'data>(input: &impl Input<'data>) -> Result>, ValError> { +fn date_from_datetime<'py>(input: &(impl Input<'py> + ?Sized)) -> Result>, ValError> { let either_dt = match input.validate_datetime(false, speedate::MicrosecondsPrecisionOverflowBehavior::Truncate) { Ok(val_match) => val_match.into_inner(), // if the error was a parsing error, update the error type from DatetimeParsing to DateFromDatetimeParsing diff --git a/src/validators/datetime.rs b/src/validators/datetime.rs index d31f53becc..4874e78a33 100644 --- a/src/validators/datetime.rs +++ b/src/validators/datetime.rs @@ -8,6 +8,7 @@ use strum::EnumMessage; use crate::build_tools::{is_strict, py_schema_error_type}; use crate::build_tools::{py_schema_err, schema_or_config_same}; +use crate::errors::ToErrorValue; use crate::errors::{py_err_string, ErrorType, ErrorTypeDefaults, ValError, ValResult}; use crate::input::{EitherDateTime, Input}; @@ -62,8 +63,8 @@ impl Validator for DateTimeValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let strict = state.strict_or(self.strict); let datetime = match input.validate_datetime(strict, self.microseconds_precision) { @@ -141,7 +142,7 @@ impl Validator for DateTimeValidator { /// In lax mode, if the input is not a datetime, we try parsing the input as a date and add the "00:00:00" time. /// Ok(None) means that this is not relevant to datetimes (the input was not a date nor a string) -fn datetime_from_date<'data>(input: &impl Input<'data>) -> Result>, ValError> { +fn datetime_from_date<'py>(input: &(impl Input<'py> + ?Sized)) -> Result>, ValError> { let either_date = match input.validate_date(false) { Ok(val_match) => val_match.into_inner(), // if the error was a parsing error, update the error type from DateParsing to DatetimeFromDateParsing @@ -307,7 +308,7 @@ impl TZConstraint { } } - pub(super) fn tz_check<'d>(&self, tz_offset: Option, input: &impl Input<'d>) -> ValResult<()> { + pub(super) fn tz_check(&self, tz_offset: Option, input: impl ToErrorValue) -> ValResult<()> { match (self, tz_offset) { (TZConstraint::Aware(_), None) => return Err(ValError::new(ErrorTypeDefaults::TimezoneAware, input)), (TZConstraint::Aware(Some(tz_expected)), Some(tz_actual)) => { diff --git a/src/validators/decimal.rs b/src/validators/decimal.rs index 1836476563..38409c9d46 100644 --- a/src/validators/decimal.rs +++ b/src/validators/decimal.rs @@ -5,10 +5,10 @@ use pyo3::types::{IntoPyDict, PyDict, PyTuple, PyType}; use pyo3::{prelude::*, PyTypeInfo}; use crate::build_tools::{is_strict, schema_or_config_same}; -use crate::errors::ValError; +use crate::errors::ErrorType; use crate::errors::ValResult; -use crate::errors::{ErrorType, InputValue}; use crate::errors::{ErrorTypeDefaults, Number}; +use crate::errors::{ToErrorValue, ValError}; use crate::input::Input; use crate::tools::SchemaDict; @@ -120,8 +120,8 @@ impl Validator for DecimalValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let decimal = input.validate_decimal(state.strict_or(self.strict), py)?; @@ -264,7 +264,7 @@ impl Validator for DecimalValidator { } } -pub(crate) fn create_decimal<'a>(arg: &Bound<'a, PyAny>, input: &impl Input<'a>) -> ValResult> { +pub(crate) fn create_decimal<'py>(arg: &Bound<'py, PyAny>, input: impl ToErrorValue) -> ValResult> { let py = arg.py(); get_decimal_type(py).call1((arg,)).map_err(|e| { let decimal_exception = match py @@ -274,16 +274,16 @@ pub(crate) fn create_decimal<'a>(arg: &Bound<'a, PyAny>, input: &impl Input<'a>) Ok(decimal_exception) => decimal_exception, Err(e) => return ValError::InternalErr(e), }; - handle_decimal_new_error(input.as_error_value(), e, decimal_exception) + handle_decimal_new_error(input, e, decimal_exception) }) } -fn handle_decimal_new_error(input: InputValue, error: PyErr, decimal_exception: Bound<'_, PyAny>) -> ValError { +fn handle_decimal_new_error(input: impl ToErrorValue, error: PyErr, decimal_exception: Bound<'_, PyAny>) -> ValError { let py = decimal_exception.py(); if error.matches(py, decimal_exception) { - ValError::new_custom_input(ErrorTypeDefaults::DecimalParsing, input) + ValError::new(ErrorTypeDefaults::DecimalParsing, input) } else if error.matches(py, PyTypeError::type_object_bound(py)) { - ValError::new_custom_input(ErrorTypeDefaults::DecimalType, input) + ValError::new(ErrorTypeDefaults::DecimalType, input) } else { ValError::InternalErr(error) } diff --git a/src/validators/definitions.rs b/src/validators/definitions.rs index a6599c8477..9cbb322713 100644 --- a/src/validators/definitions.rs +++ b/src/validators/definitions.rs @@ -72,8 +72,8 @@ impl Validator for DefinitionRefValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { self.definition.read(|validator| { let validator = validator.unwrap(); @@ -88,13 +88,13 @@ impl Validator for DefinitionRefValidator { }) } - fn validate_assignment<'data>( + fn validate_assignment<'py>( &self, - py: Python<'data>, - obj: &Bound<'data, PyAny>, + py: Python<'py>, + obj: &Bound<'py, PyAny>, field_name: &str, - field_value: &Bound<'data, PyAny>, - state: &mut ValidationState, + field_value: &Bound<'py, PyAny>, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { self.definition.read(|validator| { let validator = validator.unwrap(); diff --git a/src/validators/dict.rs b/src/validators/dict.rs index 425ea606e3..48a7c82b2a 100644 --- a/src/validators/dict.rs +++ b/src/validators/dict.rs @@ -70,8 +70,8 @@ impl Validator for DictValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let strict = state.strict_or(self.strict); let dict = input.validate_dict(strict)?; @@ -99,14 +99,14 @@ impl Validator for DictValidator { } impl DictValidator { - fn validate_generic_mapping<'data>( + fn validate_generic_mapping<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), mapping_iter: impl Iterator< - Item = ValResult<(impl BorrowInput<'data> + Clone + Into, impl BorrowInput<'data>)>, + Item = ValResult<(impl BorrowInput<'py> + Clone + Into, impl BorrowInput<'py>)>, >, - state: &mut ValidationState, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let output = PyDict::new_bound(py); let mut errors: Vec = Vec::new(); diff --git a/src/validators/float.rs b/src/validators/float.rs index 3d8a9a9a87..3a79de9fea 100644 --- a/src/validators/float.rs +++ b/src/validators/float.rs @@ -67,8 +67,8 @@ impl Validator for FloatValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let either_float = input.validate_float(state.strict_or(self.strict))?.unpack(state); if !self.allow_inf_nan && !either_float.as_f64().is_finite() { @@ -99,8 +99,8 @@ impl Validator for ConstrainedFloatValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let either_float = input.validate_float(state.strict_or(self.strict))?.unpack(state); let float: f64 = either_float.as_f64(); diff --git a/src/validators/frozenset.rs b/src/validators/frozenset.rs index b5f7056278..b6b3956308 100644 --- a/src/validators/frozenset.rs +++ b/src/validators/frozenset.rs @@ -31,8 +31,8 @@ impl Validator for FrozenSetValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let collection = input.validate_frozenset(state.strict_or(self.strict))?; let exactness = match &collection { diff --git a/src/validators/function.rs b/src/validators/function.rs index 6f54e5a16f..855337a01a 100644 --- a/src/validators/function.rs +++ b/src/validators/function.rs @@ -6,7 +6,8 @@ use pyo3::types::{PyAny, PyDict, PyString}; use pyo3::{intern, PyTraverseError, PyVisit}; use crate::errors::{ - ErrorType, PydanticCustomError, PydanticKnownError, PydanticOmit, ValError, ValResult, ValidationError, + ErrorType, PydanticCustomError, PydanticKnownError, PydanticOmit, ToErrorValue, ValError, ValResult, + ValidationError, }; use crate::input::Input; use crate::py_gc::PyGcTraverse; @@ -93,12 +94,12 @@ pub struct FunctionBeforeValidator { impl_build!(FunctionBeforeValidator, "function-before"); impl FunctionBeforeValidator { - fn _validate<'s, 'data>( + fn _validate<'s, 'py>( &'s self, - call: impl FnOnce(Bound<'data, PyAny>, &mut ValidationState<'_>) -> ValResult, - py: Python<'data>, - input: &impl Input<'data>, - state: &'s mut ValidationState<'_>, + call: impl FnOnce(Bound<'py, PyAny>, &mut ValidationState<'_, 'py>) -> ValResult, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + state: &'s mut ValidationState<'_, 'py>, ) -> ValResult { let r = if self.info_arg { let info = ValidationInfo::new(py, state.extra(), &self.config, self.field_name.clone()); @@ -118,24 +119,24 @@ impl_py_gc_traverse!(FunctionBeforeValidator { }); impl Validator for FunctionBeforeValidator { - fn validate<'data>( + fn validate<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, - state: &mut ValidationState<'_>, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { - let validate = |v, s: &mut ValidationState<'_>| self.validator.validate(py, &v, s); + let validate = |v, s: &mut ValidationState<'_, 'py>| self.validator.validate(py, &v, s); self._validate(validate, py, input, state) } - fn validate_assignment<'data>( + fn validate_assignment<'py>( &self, - py: Python<'data>, - obj: &Bound<'data, PyAny>, + py: Python<'py>, + obj: &Bound<'py, PyAny>, field_name: &str, - field_value: &Bound<'data, PyAny>, - state: &mut ValidationState, + field_value: &Bound<'py, PyAny>, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { - let validate = move |v, s: &mut ValidationState<'_>| { + let validate = move |v, s: &mut ValidationState<'_, 'py>| { self.validator.validate_assignment(py, &v, field_name, field_value, s) }; self._validate(validate, py, obj, state) @@ -159,12 +160,12 @@ pub struct FunctionAfterValidator { impl_build!(FunctionAfterValidator, "function-after"); impl FunctionAfterValidator { - fn _validate<'s, 'data, I: Input<'data>>( - &'s self, - call: impl FnOnce(&I, &mut ValidationState<'_>) -> ValResult, - py: Python<'data>, + fn _validate<'py, I: Input<'py> + ?Sized>( + &self, + call: impl FnOnce(&I, &mut ValidationState<'_, 'py>) -> ValResult, + py: Python<'py>, input: &I, - state: &mut ValidationState<'_>, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let v = call(input, state)?; let r = if self.info_arg { @@ -184,24 +185,24 @@ impl_py_gc_traverse!(FunctionAfterValidator { }); impl Validator for FunctionAfterValidator { - fn validate<'data>( + fn validate<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, - state: &mut ValidationState<'_>, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { - let validate = |v: &_, s: &mut ValidationState<'_>| self.validator.validate(py, v, s); + let validate = |v: &_, s: &mut ValidationState<'_, 'py>| self.validator.validate(py, v, s); self._validate(validate, py, input, state) } - fn validate_assignment<'data>( + fn validate_assignment<'py>( &self, - py: Python<'data>, - obj: &Bound<'data, PyAny>, + py: Python<'py>, + obj: &Bound<'py, PyAny>, field_name: &str, - field_value: &Bound<'data, PyAny>, - state: &mut ValidationState, + field_value: &Bound<'py, PyAny>, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { - let validate = move |v: &Bound<'data, PyAny>, s: &mut ValidationState<'_>| { + let validate = move |v: &Bound<'py, PyAny>, s: &mut ValidationState<'_, 'py>| { self.validator.validate_assignment(py, v, field_name, field_value, s) }; self._validate(validate, py, obj, state) @@ -251,8 +252,8 @@ impl Validator for FunctionPlainValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let r = if self.info_arg { let info = ValidationInfo::new(py, state.extra(), &self.config, self.field_name.clone()); @@ -311,12 +312,12 @@ impl BuildValidator for FunctionWrapValidator { } impl FunctionWrapValidator { - fn _validate<'s, 'data>( - &'s self, + fn _validate<'py>( + &self, handler: &Bound<'_, PyAny>, - py: Python<'data>, - input: &impl Input<'data>, - state: &mut ValidationState, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let r = if self.info_arg { let info = ValidationInfo::new(py, state.extra(), &self.config, self.field_name.clone()); @@ -338,8 +339,8 @@ impl Validator for FunctionWrapValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let handler = ValidatorCallable { validator: InternalValidator::new( @@ -357,13 +358,13 @@ impl Validator for FunctionWrapValidator { result } - fn validate_assignment<'data>( + fn validate_assignment<'py>( &self, - py: Python<'data>, - obj: &Bound<'data, PyAny>, + py: Python<'py>, + obj: &Bound<'py, PyAny>, field_name: &str, - field_value: &Bound<'data, PyAny>, - state: &mut ValidationState, + field_value: &Bound<'py, PyAny>, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let handler = AssignmentValidatorCallable { validator: InternalValidator::new( @@ -471,7 +472,7 @@ macro_rules! py_err_string { /// Only `ValueError` (including `PydanticCustomError` and `ValidationError`) and `AssertionError` are considered /// as validation errors, `TypeError` is now considered as a runtime error to catch errors in function signatures -pub fn convert_err<'a>(py: Python<'a>, err: PyErr, input: &impl Input<'a>) -> ValError { +pub fn convert_err(py: Python<'_>, err: PyErr, input: impl ToErrorValue) -> ValError { if err.is_instance_of::(py) { let error_value = err.value_bound(py); if let Ok(pydantic_value_error) = error_value.extract::() { diff --git a/src/validators/generator.rs b/src/validators/generator.rs index d4326cf474..f73532268e 100644 --- a/src/validators/generator.rs +++ b/src/validators/generator.rs @@ -62,8 +62,8 @@ impl Validator for GeneratorValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let iterator = input.validate_iter()?; let validator = self.item_validator.as_ref().map(|v| { @@ -253,12 +253,12 @@ impl InternalValidator { } } - pub fn validate_assignment<'data>( + pub fn validate_assignment<'py>( &mut self, - py: Python<'data>, - model: &Bound<'data, PyAny>, + py: Python<'py>, + model: &Bound<'py, PyAny>, field_name: &str, - field_value: &Bound<'data, PyAny>, + field_value: &Bound<'py, PyAny>, outer_location: Option, ) -> PyResult { let extra = Extra { @@ -289,10 +289,10 @@ impl InternalValidator { result } - pub fn validate<'data>( + pub fn validate<'py>( &mut self, - py: Python<'data>, - input: &impl Input<'data>, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), outer_location: Option, ) -> PyResult { let extra = Extra { diff --git a/src/validators/int.rs b/src/validators/int.rs index 580c677d60..e5b2333228 100644 --- a/src/validators/int.rs +++ b/src/validators/int.rs @@ -46,8 +46,8 @@ impl Validator for IntValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { input .validate_int(state.strict_or(self.strict)) @@ -75,8 +75,8 @@ impl Validator for ConstrainedIntValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let either_int = input.validate_int(state.strict_or(self.strict))?.unpack(state); let int_value = either_int.as_int()?; diff --git a/src/validators/is_instance.rs b/src/validators/is_instance.rs index 0261beae52..7eb7961d55 100644 --- a/src/validators/is_instance.rs +++ b/src/validators/is_instance.rs @@ -55,11 +55,11 @@ impl BuildValidator for IsInstanceValidator { impl_py_gc_traverse!(IsInstanceValidator { class }); impl Validator for IsInstanceValidator { - fn validate<'data>( + fn validate<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, - _state: &mut ValidationState, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + _state: &mut ValidationState<'_, 'py>, ) -> ValResult { if !input.is_python() { return Err(ValError::InternalErr(PyNotImplementedError::new_err( diff --git a/src/validators/is_subclass.rs b/src/validators/is_subclass.rs index 54b343aae4..da45997943 100644 --- a/src/validators/is_subclass.rs +++ b/src/validators/is_subclass.rs @@ -43,11 +43,11 @@ impl BuildValidator for IsSubclassValidator { impl_py_gc_traverse!(IsSubclassValidator { class }); impl Validator for IsSubclassValidator { - fn validate<'data>( + fn validate<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, - _state: &mut ValidationState, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + _state: &mut ValidationState<'_, 'py>, ) -> ValResult { match input.input_is_subclass(self.class.bind(py))? { true => Ok(input.to_object(py)), diff --git a/src/validators/json.rs b/src/validators/json.rs index bcae2b3ec6..62a23f0e6a 100644 --- a/src/validators/json.rs +++ b/src/validators/json.rs @@ -49,8 +49,8 @@ impl Validator for JsonValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let v_match = validate_json_bytes(input)?; let json_either_bytes = v_match.unpack(state); @@ -76,7 +76,9 @@ impl Validator for JsonValidator { } } -pub fn validate_json_bytes<'a, 'py>(input: &'a impl Input<'py>) -> ValResult>> { +pub fn validate_json_bytes<'a, 'py>( + input: &'a (impl Input<'py> + ?Sized), +) -> ValResult>> { match input.validate_bytes(false) { Ok(v_match) => Ok(v_match), Err(ValError::LineErrors(e)) => Err(ValError::LineErrors( @@ -95,7 +97,7 @@ fn map_bytes_error(line_error: ValLineError) -> ValLineError { } } -pub fn map_json_err<'py>(input: &impl Input<'py>, error: jiter::JsonError, json_bytes: &[u8]) -> ValError { +pub fn map_json_err<'py>(input: &(impl Input<'py> + ?Sized), error: jiter::JsonError, json_bytes: &[u8]) -> ValError { ValError::new( ErrorType::JsonInvalid { error: error.description(json_bytes), diff --git a/src/validators/json_or_python.rs b/src/validators/json_or_python.rs index 373f1e0f69..c76a294182 100644 --- a/src/validators/json_or_python.rs +++ b/src/validators/json_or_python.rs @@ -52,8 +52,8 @@ impl Validator for JsonOrPython { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { match state.extra().input_type { InputType::Python => self.python.validate(py, input, state), diff --git a/src/validators/lax_or_strict.rs b/src/validators/lax_or_strict.rs index 38c7d68930..bc354651a2 100644 --- a/src/validators/lax_or_strict.rs +++ b/src/validators/lax_or_strict.rs @@ -59,8 +59,8 @@ impl Validator for LaxOrStrictValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { if state.strict_or(self.strict) { self.strict_validator.validate(py, input, state) diff --git a/src/validators/list.rs b/src/validators/list.rs index fed237213b..6409d370bc 100644 --- a/src/validators/list.rs +++ b/src/validators/list.rs @@ -119,8 +119,8 @@ impl Validator for ListValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let seq = input.validate_list(state.strict_or(self.strict))?; let exactness = match &seq { diff --git a/src/validators/literal.rs b/src/validators/literal.rs index 43ffdd5d4b..69784efcaa 100644 --- a/src/validators/literal.rs +++ b/src/validators/literal.rs @@ -91,7 +91,11 @@ impl LiteralLookup { }) } - pub fn validate<'a, 'py, I: Input<'py>>(&self, py: Python<'py>, input: &'a I) -> ValResult> { + pub fn validate<'a, 'py, I: Input<'py> + ?Sized>( + &self, + py: Python<'py>, + input: &'a I, + ) -> ValResult> { if let Some(expected_bool) = &self.expected_bool { if let Ok(bool_value) = input.validate_bool(true) { if bool_value.into_inner() { @@ -189,11 +193,11 @@ impl BuildValidator for LiteralValidator { impl_py_gc_traverse!(LiteralValidator { lookup }); impl Validator for LiteralValidator { - fn validate<'data>( + fn validate<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, - _state: &mut ValidationState, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + _state: &mut ValidationState<'_, 'py>, ) -> ValResult { match self.lookup.validate(py, input)? { Some((_, v)) => Ok(v.clone()), diff --git a/src/validators/mod.rs b/src/validators/mod.rs index 4f791ac7eb..8fbfb95eb4 100644 --- a/src/validators/mod.rs +++ b/src/validators/mod.rs @@ -318,19 +318,16 @@ impl SchemaValidator { impl SchemaValidator { #[allow(clippy::too_many_arguments)] - fn _validate<'s, 'data>( - &'data self, - py: Python<'data>, - input: &impl Input<'data>, + fn _validate<'py>( + &self, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), input_type: InputType, strict: Option, from_attributes: Option, - context: Option<&Bound<'data, PyAny>>, - self_instance: Option<&Bound<'_, PyAny>>, - ) -> ValResult - where - 's: 'data, - { + context: Option<&Bound<'py, PyAny>>, + self_instance: Option<&Bound<'py, PyAny>>, + ) -> ValResult { let mut recursion_guard = RecursionState::default(); let mut state = ValidationState::new( Extra::new(strict, from_attributes, context, self_instance, input_type), @@ -564,27 +561,27 @@ pub fn build_validator( /// More (mostly immutable) data to pass between validators, should probably be class `Context`, /// but that would confuse it with context as per pydantic/pydantic#1549 #[derive(Debug)] -pub struct Extra<'a> { +pub struct Extra<'a, 'py> { /// Validation mode pub input_type: InputType, /// This is used as the `data` kwargs to validator functions - pub data: Option>, + pub data: Option>, /// whether we're in strict or lax mode pub strict: Option, /// Validation time setting of `from_attributes` pub from_attributes: Option, /// context used in validator functions - pub context: Option<&'a Bound<'a, PyAny>>, + pub context: Option<&'a Bound<'py, PyAny>>, /// This is an instance of the model or dataclass being validated, when validation is performed from `__init__` - self_instance: Option<&'a Bound<'a, PyAny>>, + self_instance: Option<&'a Bound<'py, PyAny>>, } -impl<'a> Extra<'a> { +impl<'a, 'py> Extra<'a, 'py> { pub fn new( strict: Option, from_attributes: Option, - context: Option<&'a Bound<'a, PyAny>>, - self_instance: Option<&'a Bound<'a, PyAny>>, + context: Option<&'a Bound<'py, PyAny>>, + self_instance: Option<&'a Bound<'py, PyAny>>, input_type: InputType, ) -> Self { Extra { @@ -598,7 +595,7 @@ impl<'a> Extra<'a> { } } -impl<'a> Extra<'a> { +impl Extra<'_, '_> { pub fn as_strict(&self) -> Self { Self { input_type: self.input_type, @@ -711,29 +708,29 @@ pub trait Validator: Send + Sync + Debug { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult; /// Get a default value, currently only used by `WithDefaultValidator` - fn default_value( + fn default_value<'py>( &self, - _py: Python<'_>, + _py: Python<'py>, _outer_loc: Option>, - _state: &mut ValidationState, + _state: &mut ValidationState<'_, 'py>, ) -> ValResult> { Ok(None) } /// Validate assignment to a field of a model #[allow(clippy::too_many_arguments)] - fn validate_assignment<'data>( + fn validate_assignment<'py>( &self, - _py: Python<'data>, - _obj: &Bound<'data, PyAny>, + _py: Python<'py>, + _obj: &Bound<'py, PyAny>, _field_name: &str, - _field_value: &Bound<'data, PyAny>, - _state: &mut ValidationState, + _field_value: &Bound<'py, PyAny>, + _state: &mut ValidationState<'_, 'py>, ) -> ValResult { let py_err = PyTypeError::new_err(format!("validate_assignment is not supported for {}", self.get_name())); Err(py_err.into()) diff --git a/src/validators/model.rs b/src/validators/model.rs index 182f644328..db6f032f11 100644 --- a/src/validators/model.rs +++ b/src/validators/model.rs @@ -111,8 +111,8 @@ impl Validator for ModelValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { if let Some(self_instance) = state.extra().self_instance { // in the case that self_instance is Some, we're calling validation from within `BaseModel.__init__` @@ -154,13 +154,13 @@ impl Validator for ModelValidator { } } - fn validate_assignment<'data>( + fn validate_assignment<'py>( &self, - py: Python<'data>, - model: &Bound<'data, PyAny>, + py: Python<'py>, + model: &Bound<'py, PyAny>, field_name: &str, - field_value: &Bound<'data, PyAny>, - state: &mut ValidationState, + field_value: &Bound<'py, PyAny>, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { if self.frozen { return Err(ValError::new(ErrorTypeDefaults::FrozenInstance, field_value)); @@ -223,12 +223,12 @@ impl Validator for ModelValidator { impl ModelValidator { /// here we just call the inner validator, then set attributes on `self_instance` - fn validate_init<'s, 'data>( - &'s self, - py: Python<'data>, - self_instance: &Bound<'s, PyAny>, - input: &impl Input<'data>, - state: &mut ValidationState, + fn validate_init<'py>( + &self, + py: Python<'py>, + self_instance: &Bound<'py, PyAny>, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { // we need to set `self_instance` to None for nested validators as we don't want to operate on self_instance // anymore @@ -250,12 +250,12 @@ impl ModelValidator { self.call_post_init(py, self_instance.clone(), input, state.extra()) } - fn validate_construct<'s, 'data>( - &'s self, - py: Python<'data>, - input: &impl Input<'data>, + fn validate_construct<'py>( + &self, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), existing_fields_set: Option<&Bound<'_, PyAny>>, - state: &mut ValidationState, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { if self.custom_init { // If we wanted, we could introspect the __init__ signature, and store the @@ -291,11 +291,11 @@ impl ModelValidator { self.call_post_init(py, instance, input, state.extra()) } - fn call_post_init<'s, 'data>( - &'s self, - py: Python<'data>, + fn call_post_init<'py>( + &self, + py: Python<'py>, instance: Bound<'_, PyAny>, - input: &impl Input<'data>, + input: &(impl Input<'py> + ?Sized), extra: &Extra, ) -> ValResult { if let Some(ref post_init) = self.post_init { diff --git a/src/validators/model_fields.rs b/src/validators/model_fields.rs index 2f01d09df8..39042158f2 100644 --- a/src/validators/model_fields.rs +++ b/src/validators/model_fields.rs @@ -122,8 +122,8 @@ impl Validator for ModelFieldsValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let strict = state.strict_or(self.strict); let from_attributes = state.extra().from_attributes.unwrap_or(self.from_attributes); @@ -340,13 +340,13 @@ impl Validator for ModelFieldsValidator { } } - fn validate_assignment<'data>( + fn validate_assignment<'py>( &self, - py: Python<'data>, - obj: &Bound<'data, PyAny>, + py: Python<'py>, + obj: &Bound<'py, PyAny>, field_name: &str, - field_value: &Bound<'data, PyAny>, - state: &mut ValidationState, + field_value: &Bound<'py, PyAny>, + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let dict = obj.downcast::()?; diff --git a/src/validators/none.rs b/src/validators/none.rs index 1ae1a3b146..f3f04d0787 100644 --- a/src/validators/none.rs +++ b/src/validators/none.rs @@ -24,11 +24,11 @@ impl BuildValidator for NoneValidator { impl_py_gc_traverse!(NoneValidator {}); impl Validator for NoneValidator { - fn validate<'data>( + fn validate<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, - _state: &mut ValidationState, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + _state: &mut ValidationState<'_, 'py>, ) -> ValResult { match input.is_none() { true => Ok(py.None()), diff --git a/src/validators/nullable.rs b/src/validators/nullable.rs index 20c1d79269..de02179d50 100644 --- a/src/validators/nullable.rs +++ b/src/validators/nullable.rs @@ -36,8 +36,8 @@ impl Validator for NullableValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { match input.is_none() { true => Ok(py.None()), diff --git a/src/validators/set.rs b/src/validators/set.rs index 92f58e8d20..727d1a01f7 100644 --- a/src/validators/set.rs +++ b/src/validators/set.rs @@ -61,8 +61,8 @@ impl Validator for SetValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let collection = input.validate_set(state.strict_or(self.strict))?; let exactness = match &collection { diff --git a/src/validators/string.rs b/src/validators/string.rs index b72b6efb40..645217edd9 100644 --- a/src/validators/string.rs +++ b/src/validators/string.rs @@ -44,8 +44,8 @@ impl Validator for StrValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { input .validate_str(state.strict_or(self.strict), self.coerce_numbers_to_str) @@ -76,8 +76,8 @@ impl Validator for StrConstrainedValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let either_str = input .validate_str(state.strict_or(self.strict), self.coerce_numbers_to_str)? diff --git a/src/validators/time.rs b/src/validators/time.rs index 524050f892..a9c6ae5612 100644 --- a/src/validators/time.rs +++ b/src/validators/time.rs @@ -43,8 +43,8 @@ impl Validator for TimeValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let time = input .validate_time(state.strict_or(self.strict), self.microseconds_precision)? diff --git a/src/validators/timedelta.rs b/src/validators/timedelta.rs index 17ebc09364..47817662d7 100644 --- a/src/validators/timedelta.rs +++ b/src/validators/timedelta.rs @@ -68,8 +68,8 @@ impl Validator for TimeDeltaValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let timedelta = input .validate_timedelta(state.strict_or(self.strict), self.microseconds_precision)? diff --git a/src/validators/tuple.rs b/src/validators/tuple.rs index a3968f85cf..601e591b3d 100644 --- a/src/validators/tuple.rs +++ b/src/validators/tuple.rs @@ -60,11 +60,11 @@ impl_py_gc_traverse!(TupleValidator { validators }); impl TupleValidator { #[allow(clippy::too_many_arguments)] - fn validate_tuple_items<'data, I: BorrowInput<'data>>( + fn validate_tuple_items<'py, I: BorrowInput<'py>>( &self, - py: Python<'data>, - input: &impl Input<'data>, - state: &mut ValidationState, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, output: &mut Vec, errors: &mut Vec, item_validators: &[CombinedValidator], @@ -97,11 +97,11 @@ impl TupleValidator { } #[allow(clippy::too_many_arguments)] - fn validate_tuple_variable<'data, I: BorrowInput<'data>, InputT: Input<'data>>( + fn validate_tuple_variable<'py, I: BorrowInput<'py>>( &self, - py: Python<'data>, - input: &InputT, - state: &mut ValidationState, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, errors: &mut Vec, collection_iter: &mut NextCountingIterator>, actual_length: Option, @@ -216,9 +216,9 @@ impl TupleValidator { Ok(output) } - fn push_output_item<'data>( + fn push_output_item<'py>( &self, - input: &impl Input<'data>, + input: &(impl Input<'py> + ?Sized), output: &mut Vec, item: PyObject, actual_length: Option, @@ -245,8 +245,8 @@ impl Validator for TupleValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let collection = input.validate_tuple(state.strict_or(self.strict))?; let exactness = match &collection { diff --git a/src/validators/typed_dict.rs b/src/validators/typed_dict.rs index b85d2df60d..998942f7f1 100644 --- a/src/validators/typed_dict.rs +++ b/src/validators/typed_dict.rs @@ -148,8 +148,8 @@ impl Validator for TypedDictValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let strict = state.strict_or(self.strict); let dict = input.validate_dict(strict)?; diff --git a/src/validators/union.rs b/src/validators/union.rs index f3c1174a0f..7001f92801 100644 --- a/src/validators/union.rs +++ b/src/validators/union.rs @@ -8,7 +8,7 @@ use smallvec::SmallVec; use crate::build_tools::py_schema_err; use crate::build_tools::{is_strict, schema_or_config}; -use crate::errors::{ErrorType, ValError, ValLineError, ValResult}; +use crate::errors::{ErrorType, ToErrorValue, ValError, ValLineError, ValResult}; use crate::input::{GenericMapping, Input}; use crate::lookup_key::LookupKey; use crate::py_gc::PyGcTraverse; @@ -101,11 +101,11 @@ impl BuildValidator for UnionValidator { } impl UnionValidator { - fn validate_smart<'data>( + fn validate_smart<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, - state: &mut ValidationState, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let old_exactness = state.exactness; let strict = state.strict_or(self.strict); @@ -167,11 +167,11 @@ impl UnionValidator { Err(errors.into_val_error(input)) } - fn validate_left_to_right<'data>( + fn validate_left_to_right<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, - state: &mut ValidationState, + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let mut errors = MaybeErrors::new(self.custom_error.as_ref()); @@ -205,8 +205,8 @@ impl Validator for UnionValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { match self.mode { UnionMode::Smart => self.validate_smart(py, input, state), @@ -249,7 +249,7 @@ impl<'a> MaybeErrors<'a> { } } - fn into_val_error<'i>(self, input: &impl Input<'i>) -> ValError { + fn into_val_error(self, input: impl ToErrorValue) -> ValError { match self { Self::Custom(custom_error) => custom_error.as_val_error(input), Self::Errors(errors) => ValError::LineErrors( @@ -393,8 +393,8 @@ impl Validator for TaggedUnionValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { match self.discriminator { Discriminator::LookupKey(ref lookup_key) => { @@ -447,11 +447,11 @@ impl Validator for TaggedUnionValidator { } impl TaggedUnionValidator { - fn self_schema_tag<'data>( + fn self_schema_tag<'py>( &self, - py: Python<'data>, - input: &impl Input<'data>, - ) -> ValResult> { + py: Python<'py>, + input: &(impl Input<'py> + ?Sized), + ) -> ValResult> { let dict = input.strict_dict()?; let tag = match &dict { GenericMapping::PyDict(dict) => match dict.get_item(intern!(py, "type"))? { @@ -480,12 +480,12 @@ impl TaggedUnionValidator { } } - fn find_call_validator<'s, 'data>( - &'s self, - py: Python<'data>, - tag: &Bound<'data, PyAny>, - input: &impl Input<'data>, - state: &mut ValidationState, + fn find_call_validator<'py>( + &self, + py: Python<'py>, + tag: &Bound<'py, PyAny>, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { if let Ok(Some((tag, validator))) = self.lookup.validate(py, tag) { return match validator.validate(py, input, state) { @@ -507,7 +507,7 @@ impl TaggedUnionValidator { } } - fn tag_not_found<'s, 'data>(&'s self, input: &impl Input<'data>) -> ValError { + fn tag_not_found<'py>(&self, input: &(impl Input<'py> + ?Sized)) -> ValError { match self.custom_error { Some(ref custom_error) => custom_error.as_val_error(input), None => ValError::new( diff --git a/src/validators/url.rs b/src/validators/url.rs index 29eb2daa63..786b2d6536 100644 --- a/src/validators/url.rs +++ b/src/validators/url.rs @@ -10,6 +10,7 @@ use ahash::AHashSet; use url::{ParseError, SyntaxViolation, Url}; use crate::build_tools::{is_strict, py_schema_err}; +use crate::errors::ToErrorValue; use crate::errors::{ErrorType, ErrorTypeDefaults, ValError, ValResult}; use crate::input::Input; use crate::tools::SchemaDict; @@ -63,8 +64,8 @@ impl Validator for UrlValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let mut lib_url = self.get_url(input, state.strict_or(self.strict))?; @@ -103,7 +104,7 @@ impl Validator for UrlValidator { } impl UrlValidator { - fn get_url<'s, 'data>(&'s self, input: &impl Input<'data>, strict: bool) -> ValResult { + fn get_url<'py>(&self, input: &(impl Input<'py> + ?Sized), strict: bool) -> ValResult { match input.validate_str(strict, false) { Ok(val_match) => { let either_str = val_match.into_inner(); @@ -133,7 +134,7 @@ impl UrlValidator { } } - fn check_length<'s, 'data>(&self, input: &impl Input<'data>, url_str: &str) -> ValResult<()> { + fn check_length<'py>(&self, input: &(impl Input<'py> + ?Sized), url_str: &str) -> ValResult<()> { if let Some(max_length) = self.max_length { if url_str.len() > max_length { return Err(ValError::new( @@ -197,8 +198,8 @@ impl Validator for MultiHostUrlValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let mut multi_url = self.get_url(input, state.strict_or(self.strict))?; @@ -236,7 +237,7 @@ impl Validator for MultiHostUrlValidator { } impl MultiHostUrlValidator { - fn get_url<'s, 'data>(&'s self, input: &impl Input<'data>, strict: bool) -> ValResult { + fn get_url<'py>(&self, input: &(impl Input<'py> + ?Sized), strict: bool) -> ValResult { match input.validate_str(strict, false) { Ok(val_match) => { let either_str = val_match.into_inner(); @@ -264,7 +265,7 @@ impl MultiHostUrlValidator { } } - fn check_length<'s, 'data, F>(&self, input: &impl Input<'data>, func: F) -> ValResult<()> + fn check_length<'py, F>(&self, input: &(impl Input<'py> + ?Sized), func: F) -> ValResult<()> where F: FnOnce() -> usize, { @@ -283,9 +284,9 @@ impl MultiHostUrlValidator { } } -fn parse_multihost_url<'url, 'input>( - url_str: &'url str, - input: &impl Input<'input>, +fn parse_multihost_url<'py>( + url_str: &str, + input: &(impl Input<'py> + ?Sized), strict: bool, ) -> ValResult { macro_rules! parsing_err { @@ -402,7 +403,7 @@ fn parse_multihost_url<'url, 'input>( } } -fn parse_url<'url, 'input>(url_str: &'url str, input: &impl Input<'input>, strict: bool) -> ValResult { +fn parse_url(url_str: &str, input: impl ToErrorValue, strict: bool) -> ValResult { if url_str.is_empty() { return Err(ValError::new( ErrorType::UrlParsing { diff --git a/src/validators/uuid.rs b/src/validators/uuid.rs index ab452a21f1..460a618349 100644 --- a/src/validators/uuid.rs +++ b/src/validators/uuid.rs @@ -89,8 +89,8 @@ impl Validator for UuidValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { let class = get_uuid_type(py)?; if let Some(py_input) = input.input_is_instance(class) { @@ -150,7 +150,7 @@ impl Validator for UuidValidator { } impl UuidValidator { - fn get_uuid<'s, 'data>(&'s self, input: &impl Input<'data>) -> ValResult { + fn get_uuid<'py>(&self, input: &(impl Input<'py> + ?Sized)) -> ValResult { let uuid = match input.exact_str().ok() { Some(either_string) => { let cow = either_string.as_cow()?; diff --git a/src/validators/validation_state.rs b/src/validators/validation_state.rs index 61de64fd64..d7a831aee6 100644 --- a/src/validators/validation_state.rs +++ b/src/validators/validation_state.rs @@ -9,15 +9,15 @@ pub enum Exactness { Exact, } -pub struct ValidationState<'a> { +pub struct ValidationState<'a, 'py> { pub recursion_guard: &'a mut RecursionState, pub exactness: Option, // deliberately make Extra readonly - extra: Extra<'a>, + extra: Extra<'a, 'py>, } -impl<'a> ValidationState<'a> { - pub fn new(extra: Extra<'a>, recursion_guard: &'a mut RecursionState) -> Self { +impl<'a, 'py> ValidationState<'a, 'py> { + pub fn new(extra: Extra<'a, 'py>, recursion_guard: &'a mut RecursionState) -> Self { Self { recursion_guard, // Don't care about exactness unless doing union validation exactness: None, @@ -27,8 +27,8 @@ impl<'a> ValidationState<'a> { pub fn with_new_extra<'r, R: 'r>( &mut self, - extra: Extra<'_>, - f: impl for<'s> FnOnce(&'s mut ValidationState<'_>) -> R, + extra: Extra<'_, 'py>, + f: impl for<'s> FnOnce(&'s mut ValidationState<'_, 'py>) -> R, ) -> R { // TODO: It would be nice to implement this function with a drop guard instead of a closure, // but lifetimes get in a tangle. Maybe someone brave wants to have a go at unpicking lifetimes. @@ -52,8 +52,8 @@ impl<'a> ValidationState<'a> { /// When `ValidationStateWithReboundExtra` drops, the extra field is restored to its original value. pub fn rebind_extra<'state>( &'state mut self, - f: impl FnOnce(&mut Extra<'a>), - ) -> ValidationStateWithReboundExtra<'state, 'a> { + f: impl FnOnce(&mut Extra<'a, 'py>), + ) -> ValidationStateWithReboundExtra<'state, 'a, 'py> { #[allow(clippy::unnecessary_struct_initialization)] let old_extra = Extra { data: self.extra.data.clone(), @@ -63,7 +63,7 @@ impl<'a> ValidationState<'a> { ValidationStateWithReboundExtra { state: self, old_extra } } - pub fn extra(&self) -> &'_ Extra<'a> { + pub fn extra(&self) -> &'_ Extra<'a, 'py> { &self.extra } @@ -89,32 +89,32 @@ impl<'a> ValidationState<'a> { } } -impl ContainsRecursionState for ValidationState<'_> { +impl ContainsRecursionState for ValidationState<'_, '_> { fn access_recursion_state(&mut self, f: impl FnOnce(&mut RecursionState) -> R) -> R { f(self.recursion_guard) } } -pub struct ValidationStateWithReboundExtra<'state, 'a> { - state: &'state mut ValidationState<'a>, - old_extra: Extra<'a>, +pub struct ValidationStateWithReboundExtra<'state, 'a, 'py> { + state: &'state mut ValidationState<'a, 'py>, + old_extra: Extra<'a, 'py>, } -impl<'a> std::ops::Deref for ValidationStateWithReboundExtra<'_, 'a> { - type Target = ValidationState<'a>; +impl<'a, 'py> std::ops::Deref for ValidationStateWithReboundExtra<'_, 'a, 'py> { + type Target = ValidationState<'a, 'py>; fn deref(&self) -> &Self::Target { self.state } } -impl<'a> std::ops::DerefMut for ValidationStateWithReboundExtra<'_, 'a> { +impl std::ops::DerefMut for ValidationStateWithReboundExtra<'_, '_, '_> { fn deref_mut(&mut self) -> &mut Self::Target { self.state } } -impl Drop for ValidationStateWithReboundExtra<'_, '_> { +impl Drop for ValidationStateWithReboundExtra<'_, '_, '_> { fn drop(&mut self) { std::mem::swap(&mut self.state.extra, &mut self.old_extra); } diff --git a/src/validators/with_default.rs b/src/validators/with_default.rs index 06ab2159a6..e03830e774 100644 --- a/src/validators/with_default.rs +++ b/src/validators/with_default.rs @@ -137,8 +137,8 @@ impl Validator for WithDefaultValidator { fn validate<'py>( &self, py: Python<'py>, - input: &impl Input<'py>, - state: &mut ValidationState, + input: &(impl Input<'py> + ?Sized), + state: &mut ValidationState<'_, 'py>, ) -> ValResult { if input.to_object(py).is(&self.undefined) { Ok(self.default_value(py, None::, state)?.unwrap()) @@ -157,11 +157,11 @@ impl Validator for WithDefaultValidator { } } - fn default_value( + fn default_value<'py>( &self, - py: Python<'_>, + py: Python<'py>, outer_loc: Option>, - state: &mut ValidationState, + state: &mut ValidationState<'_, 'py>, ) -> ValResult> { match self.default.default_value(py)? { Some(stored_dft) => {