@@ -7,7 +7,7 @@ use pyo3::ffi::{self, c_str};
7
7
use pyo3:: intern;
8
8
use pyo3:: prelude:: * ;
9
9
use pyo3:: sync:: GILOnceCell ;
10
- use pyo3:: types:: { PyDict , PyList , PyString , PyType } ;
10
+ use pyo3:: types:: { PyDict , PyList , PyString , PyTuple , PyType } ;
11
11
use serde:: ser:: { Error , SerializeMap , SerializeSeq } ;
12
12
use serde:: { Serialize , Serializer } ;
13
13
@@ -57,12 +57,19 @@ impl ValidationError {
57
57
) -> PyErr {
58
58
match error {
59
59
ValError :: LineErrors ( raw_errors) => {
60
- let line_errors: Vec < PyLineError > = match outer_location {
60
+ let line_errors = match outer_location {
61
61
Some ( outer_location) => raw_errors
62
62
. into_iter ( )
63
- . map ( |e| e. with_outer_location ( outer_location. clone ( ) ) . into_py ( py) )
63
+ . map ( |e| PyLineError :: from_val_line_error ( py, e. with_outer_location ( outer_location. clone ( ) ) ) )
64
+ . collect ( ) ,
65
+ None => raw_errors
66
+ . into_iter ( )
67
+ . map ( |e| PyLineError :: from_val_line_error ( py, e) )
64
68
. collect ( ) ,
65
- None => raw_errors. into_iter ( ) . map ( |e| e. into_py ( py) ) . collect ( ) ,
69
+ } ;
70
+ let line_errors = match line_errors {
71
+ Ok ( errors) => errors,
72
+ Err ( err) => return err,
66
73
} ;
67
74
let validation_error = Self :: new ( line_errors, title, input_type, hide_input) ;
68
75
match Py :: new ( py, validation_error) {
@@ -117,15 +124,17 @@ impl ValidationError {
117
124
context : _,
118
125
} = & line_error. error_type
119
126
{
120
- let note: PyObject = if let Location :: Empty = & line_error. location {
121
- "Pydantic: cause of loc: root" . into_py ( py )
127
+ let note = if let Location :: Empty = & line_error. location {
128
+ PyString :: new ( py , "Pydantic: cause of loc: root" )
122
129
} else {
123
- format ! (
124
- "Pydantic: cause of loc: {}" ,
125
- // Location formats with a newline at the end, hence the trim()
126
- line_error. location. to_string( ) . trim( )
130
+ PyString :: new (
131
+ py,
132
+ & format ! (
133
+ "Pydantic: cause of loc: {}" ,
134
+ // Location formats with a newline at the end, hence the trim()
135
+ line_error. location. to_string( ) . trim( )
136
+ ) ,
127
137
)
128
- . into_py ( py)
129
138
} ;
130
139
131
140
// Notes only support 3.11 upwards:
@@ -144,7 +153,7 @@ impl ValidationError {
144
153
{
145
154
use pyo3:: exceptions:: PyUserWarning ;
146
155
147
- let wrapped = PyUserWarning :: new_err ( ( note, ) ) ;
156
+ let wrapped = PyUserWarning :: new_err ( ( note. unbind ( ) , ) ) ;
148
157
wrapped. set_cause ( py, Some ( PyErr :: from_value ( err. clone_ref ( py) . into_bound ( py) ) ) ) ;
149
158
user_py_errs. push ( wrapped) ;
150
159
}
@@ -159,7 +168,7 @@ impl ValidationError {
159
168
#[ cfg( Py_3_11 ) ]
160
169
let cause = {
161
170
use pyo3:: exceptions:: PyBaseExceptionGroup ;
162
- Some ( PyBaseExceptionGroup :: new_err ( ( title, user_py_errs) ) . into_py ( py) )
171
+ Some ( PyBaseExceptionGroup :: new_err ( ( title, user_py_errs) ) . into_value ( py) )
163
172
} ;
164
173
165
174
// Pre 3.11 ExceptionGroup support, use the python backport instead:
@@ -170,7 +179,7 @@ impl ValidationError {
170
179
match py. import ( "exceptiongroup" ) {
171
180
Ok ( py_mod) => match py_mod. getattr ( "ExceptionGroup" ) {
172
181
Ok ( group_cls) => match group_cls. call1 ( ( title, user_py_errs) ) {
173
- Ok ( group_instance) => Some ( group_instance. into_py ( py ) ) ,
182
+ Ok ( group_instance) => Some ( group_instance) ,
174
183
Err ( _) => None ,
175
184
} ,
176
185
Err ( _) => None ,
@@ -308,10 +317,13 @@ impl ValidationError {
308
317
return py. None ( ) ;
309
318
}
310
319
e. as_dict ( py, url_prefix, include_context, self . input_type , include_input)
311
- . unwrap_or_else ( |err| {
312
- iteration_error = Some ( err) ;
313
- py. None ( )
314
- } )
320
+ . map_or_else (
321
+ |err| {
322
+ iteration_error = Some ( err) ;
323
+ py. None ( )
324
+ } ,
325
+ Into :: into,
326
+ )
315
327
} ) ,
316
328
) ?;
317
329
if let Some ( err) = iteration_error {
@@ -379,7 +391,7 @@ impl ValidationError {
379
391
self . __repr__ ( py)
380
392
}
381
393
382
- fn __reduce__ < ' py > ( slf : & Bound < ' py , Self > ) -> PyResult < ( Bound < ' py , PyAny > , PyObject ) > {
394
+ fn __reduce__ < ' py > ( slf : & Bound < ' py , Self > ) -> PyResult < ( Bound < ' py , PyAny > , Bound < ' py , PyTuple > ) > {
383
395
let py = slf. py ( ) ;
384
396
let callable = slf. getattr ( "from_exception_data" ) ?;
385
397
let borrow = slf. try_borrow ( ) ?;
@@ -389,7 +401,7 @@ impl ValidationError {
389
401
borrow. input_type . into_pyobject ( py) ?,
390
402
borrow. hide_input ,
391
403
)
392
- . into_py ( slf. py ( ) ) ;
404
+ . into_pyobject ( slf. py ( ) ) ? ;
393
405
Ok ( ( callable, args) )
394
406
}
395
407
}
@@ -418,16 +430,6 @@ pub struct PyLineError {
418
430
input_value : PyObject ,
419
431
}
420
432
421
- impl IntoPy < PyLineError > for ValLineError {
422
- fn into_py ( self , py : Python < ' _ > ) -> PyLineError {
423
- PyLineError {
424
- error_type : self . error_type ,
425
- location : self . location ,
426
- input_value : self . input_value . to_object ( py) ,
427
- }
428
- }
429
- }
430
-
431
433
impl From < PyLineError > for ValLineError {
432
434
/// Used to extract line errors from a validation error for wrap functions
433
435
fn from ( other : PyLineError ) -> ValLineError {
@@ -464,7 +466,7 @@ impl TryFrom<&Bound<'_, PyAny>> for PyLineError {
464
466
let location = Location :: try_from ( dict. get_item ( "loc" ) ?. as_ref ( ) ) ?;
465
467
466
468
let input_value = match dict. get_item ( "input" ) ? {
467
- Some ( i) => i. into_py ( py ) ,
469
+ Some ( i) => i. unbind ( ) ,
468
470
None => py. None ( ) ,
469
471
} ;
470
472
@@ -477,18 +479,26 @@ impl TryFrom<&Bound<'_, PyAny>> for PyLineError {
477
479
}
478
480
479
481
impl PyLineError {
482
+ pub fn from_val_line_error ( py : Python , error : ValLineError ) -> PyResult < Self > {
483
+ Ok ( Self {
484
+ error_type : error. error_type ,
485
+ location : error. location ,
486
+ input_value : error. input_value . into_pyobject ( py) ?. unbind ( ) ,
487
+ } )
488
+ }
489
+
480
490
fn get_error_url ( & self , url_prefix : & str ) -> String {
481
491
format ! ( "{url_prefix}{}" , self . error_type. type_string( ) )
482
492
}
483
493
484
- pub fn as_dict (
494
+ pub fn as_dict < ' py > (
485
495
& self ,
486
- py : Python ,
496
+ py : Python < ' py > ,
487
497
url_prefix : Option < & str > ,
488
498
include_context : bool ,
489
499
input_type : InputType ,
490
500
include_input : bool ,
491
- ) -> PyResult < PyObject > {
501
+ ) -> PyResult < Bound < ' py , PyDict > > {
492
502
let dict = PyDict :: new ( py) ;
493
503
dict. set_item ( "type" , self . error_type . type_string ( ) ) ?;
494
504
dict. set_item ( "loc" , self . location . to_object ( py) ) ?;
@@ -511,7 +521,7 @@ impl PyLineError {
511
521
}
512
522
}
513
523
}
514
- Ok ( dict. into_py ( py ) )
524
+ Ok ( dict)
515
525
}
516
526
517
527
fn pretty (
0 commit comments