@@ -17,8 +17,7 @@ use pyo3::types::{PyBytes, PyComplex, PyFloat, PyFrozenSet, PyIterator, PyMappin
1717use serde:: { ser:: Error , Serialize , Serializer } ;
1818
1919use crate :: errors:: {
20- py_err_string, sequence_valid_as_partial, ErrorType , ErrorTypeDefaults , InputValue , ToErrorValue , ValError ,
21- ValLineError , ValResult ,
20+ py_err_string, ErrorType , ErrorTypeDefaults , InputValue , LocItem , ToErrorValue , ValError , ValLineError , ValResult ,
2221} ;
2322use crate :: py_gc:: PyGcTraverse ;
2423use crate :: tools:: { extract_i64, extract_int, new_py_string, py_err} ;
@@ -131,7 +130,6 @@ pub(crate) fn validate_iter_to_vec<'py>(
131130 let mut errors: Vec < ValLineError > = Vec :: new ( ) ;
132131 let mut index = 0 ;
133132 for item_result in iter {
134- index += 1 ;
135133 let item = item_result. map_err ( |e| any_next_error ! ( py, e, max_length_check. input, index) ) ?;
136134 match validator. validate ( py, item. borrow_input ( ) , state) {
137135 Ok ( item) => {
@@ -148,6 +146,7 @@ pub(crate) fn validate_iter_to_vec<'py>(
148146 Err ( ValError :: Omit ) => ( ) ,
149147 Err ( err) => return Err ( err) ,
150148 }
149+ index += 1 ;
151150 }
152151
153152 if errors. is_empty ( ) || sequence_valid_as_partial ( state, index, & errors) {
@@ -157,6 +156,23 @@ pub(crate) fn validate_iter_to_vec<'py>(
157156 }
158157}
159158
159+ /// If we're in `allow_partial` mode, whether all errors occurred in the last element of the input.
160+ pub fn sequence_valid_as_partial ( state : & ValidationState , input_length : usize , errors : & [ ValLineError ] ) -> bool {
161+ if !state. extra ( ) . allow_partial {
162+ false
163+ } else {
164+ // for the error to be in the last element, the index of all errors must be `input_length - 1`
165+ let last_index = ( input_length - 1 ) as i64 ;
166+ errors. iter ( ) . all ( |error| {
167+ if let Some ( LocItem :: I ( loc_index) ) = error. first_loc_item ( ) {
168+ * loc_index == last_index
169+ } else {
170+ false
171+ }
172+ } )
173+ }
174+ }
175+
160176pub trait BuildSet {
161177 fn build_add ( & self , item : PyObject ) -> PyResult < ( ) > ;
162178
@@ -202,7 +218,6 @@ pub(crate) fn validate_iter_to_set<'py>(
202218 let mut errors: Vec < ValLineError > = Vec :: new ( ) ;
203219 let mut index = 0 ;
204220 for item_result in iter {
205- index += 1 ;
206221 let item = item_result. map_err ( |e| any_next_error ! ( py, e, input, index) ) ?;
207222 match validator. validate ( py, item. borrow_input ( ) , state) {
208223 Ok ( item) => {
@@ -233,6 +248,7 @@ pub(crate) fn validate_iter_to_set<'py>(
233248 if fail_fast && !errors. is_empty ( ) {
234249 return Err ( ValError :: LineErrors ( errors) ) ;
235250 }
251+ index += 1 ;
236252 }
237253
238254 if errors. is_empty ( ) || sequence_valid_as_partial ( state, index, & errors) {
0 commit comments