11use crate :: function:: PyFuncArgs ;
2- use crate :: obj:: objiter ;
2+ use crate :: obj:: objstr :: { PyString , PyStringRef } ;
33use crate :: obj:: objtraceback:: PyTracebackRef ;
44use crate :: obj:: objtuple:: { PyTuple , PyTupleRef } ;
5- use crate :: obj:: objtype;
65use crate :: obj:: objtype:: PyClassRef ;
76use crate :: pyobject:: {
87 IdProtocol , PyClassImpl , PyContext , PyIterable , PyObjectRef , PyRef , PyResult , PyValue ,
@@ -47,15 +46,15 @@ impl PyBaseException {
4746 #[ pyslot( new) ]
4847 fn tp_new (
4948 cls : PyClassRef ,
50- _args : PyFuncArgs ,
49+ args : PyFuncArgs ,
5150 vm : & VirtualMachine ,
5251 ) -> PyResult < PyBaseExceptionRef > {
5352 PyBaseException {
5453 traceback : RefCell :: new ( None ) ,
5554 cause : RefCell :: new ( None ) ,
5655 context : RefCell :: new ( None ) ,
5756 suppress_context : Cell :: new ( false ) ,
58- args : RefCell :: new ( PyTuple :: from ( vec ! [ ] ) . into_ref ( vm) ) ,
57+ args : RefCell :: new ( PyTuple :: from ( args . args ) . into_ref ( vm) ) ,
5958 }
6059 . into_ref_with_type ( vm, cls)
6160 }
@@ -66,8 +65,8 @@ impl PyBaseException {
6665 Ok ( ( ) )
6766 }
6867
69- #[ pyproperty]
70- fn args ( & self , _vm : & VirtualMachine ) -> PyTupleRef {
68+ #[ pyproperty( name = "args" ) ]
69+ fn get_args ( & self , _vm : & VirtualMachine ) -> PyTupleRef {
7170 self . args . borrow ( ) . clone ( )
7271 }
7372
@@ -127,6 +126,30 @@ impl PyBaseException {
127126 zelf. traceback . replace ( tb) ;
128127 Ok ( zelf. as_object ( ) . clone ( ) )
129128 }
129+
130+ #[ pymethod( name = "__str__" ) ]
131+ fn str ( & self , vm : & VirtualMachine ) -> PyStringRef {
132+ let str_args = exception_args_as_string ( vm, self . args ( ) , false ) ;
133+ match str_args. into_iter ( ) . exactly_one ( ) {
134+ Err ( i) if i. len ( ) == 0 => PyString :: from ( "" ) . into_ref ( vm) ,
135+ Ok ( s) => s,
136+ Err ( i) => PyString :: from ( format ! ( "({})" , i. format( ", " ) ) ) . into_ref ( vm) ,
137+ }
138+ }
139+
140+ #[ pymethod( name = "__repr__" ) ]
141+ fn repr ( zelf : PyRef < Self > , vm : & VirtualMachine ) -> String {
142+ let repr_args = exception_args_as_string ( vm, zelf. args ( ) , false ) ;
143+ let cls = zelf. class ( ) ;
144+ match repr_args. into_iter ( ) . exactly_one ( ) {
145+ Ok ( one) => format ! ( "{}({},)" , cls. name, one) ,
146+ Err ( i) => format ! ( "{}({})" , cls. name, i. format( ", " ) ) ,
147+ }
148+ }
149+
150+ pub fn args ( & self ) -> PyTupleRef {
151+ self . args . borrow ( ) . clone ( )
152+ }
130153}
131154
132155/// Print exception chain
@@ -207,27 +230,20 @@ pub fn print_exception_inner<W: Write>(
207230 vm : & VirtualMachine ,
208231 exc : & PyObjectRef ,
209232) -> io:: Result < ( ) > {
210- if let Ok ( tb) = vm. get_attribute ( exc. clone ( ) , "__traceback__" ) {
211- if objtype:: isinstance ( & tb, & vm. ctx . traceback_type ( ) ) {
212- writeln ! ( output, "Traceback (most recent call last):" ) ?;
213- let mut tb: PyTracebackRef = tb. downcast ( ) . expect ( " must be a traceback object" ) ;
214- loop {
215- print_traceback_entry ( & mut output, & tb) ?;
216- tb = match & tb. next {
217- Some ( tb) => tb. clone ( ) ,
218- None => break ,
219- } ;
220- }
233+ let exc: PyBaseExceptionRef = exc. clone ( ) . downcast ( ) . unwrap ( ) ;
234+
235+ if let Some ( tb) = exc. traceback . borrow ( ) . clone ( ) {
236+ writeln ! ( output, "Traceback (most recent call last):" ) ?;
237+ let mut tb = & Some ( tb) ;
238+ while let Some ( traceback) = tb {
239+ print_traceback_entry ( & mut output, traceback) ?;
240+ tb = & traceback. next ;
221241 }
222242 } else {
223243 writeln ! ( output, "No traceback set on exception" ) ?;
224244 }
225245
226- let varargs = vm
227- . get_attribute ( exc. clone ( ) , "args" )
228- . unwrap ( )
229- . downcast :: < PyTuple > ( )
230- . expect ( "'args' must be a tuple" ) ;
246+ let varargs = exc. args ( ) ;
231247 let args_repr = exception_args_as_string ( vm, varargs, true ) ;
232248
233249 let exc_name = exc. class ( ) . name . clone ( ) ;
@@ -247,73 +263,30 @@ fn exception_args_as_string(
247263 vm : & VirtualMachine ,
248264 varargs : PyTupleRef ,
249265 str_single : bool ,
250- ) -> Vec < String > {
266+ ) -> Vec < PyStringRef > {
251267 match varargs. elements . len ( ) {
252268 0 => vec ! [ ] ,
253269 1 => {
254270 let args0_repr = if str_single {
255- vm. to_pystr ( & varargs. elements [ 0 ] )
256- . unwrap_or_else ( |_| "<element str() failed>" . to_string ( ) )
271+ vm. to_str ( & varargs. elements [ 0 ] )
272+ . unwrap_or_else ( |_| PyString :: from ( "<element str() failed>" ) . into_ref ( vm ) )
257273 } else {
258274 vm. to_repr ( & varargs. elements [ 0 ] )
259- . map ( |s| s. as_str ( ) . to_owned ( ) )
260- . unwrap_or_else ( |_| "<element repr() failed>" . to_string ( ) )
275+ . unwrap_or_else ( |_| PyString :: from ( "<element repr() failed>" ) . into_ref ( vm) )
261276 } ;
262277 vec ! [ args0_repr]
263278 }
264279 _ => varargs
265280 . elements
266281 . iter ( )
267- . map ( |vararg| match vm . to_repr ( vararg ) {
268- Ok ( arg_repr ) => arg_repr . as_str ( ) . to_string ( ) ,
269- Err ( _ ) => "<element repr() failed>" . to_string ( ) ,
282+ . map ( |vararg| {
283+ vm . to_repr ( vararg )
284+ . unwrap_or_else ( |_| PyString :: from ( "<element repr() failed>" ) . into_ref ( vm ) )
270285 } )
271286 . collect ( ) ,
272287 }
273288}
274289
275- fn exception_str ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
276- arg_check ! (
277- vm,
278- args,
279- required = [ ( exc, Some ( vm. ctx. exceptions. exception_type. clone( ) ) ) ]
280- ) ;
281- let args = vm
282- . get_attribute ( exc. clone ( ) , "args" )
283- . unwrap ( )
284- . downcast :: < PyTuple > ( )
285- . expect ( "'args' must be a tuple" ) ;
286- let args_str = exception_args_as_string ( vm, args, false ) ;
287- let joined_str = match args_str. len ( ) {
288- 0 => "" . to_string ( ) ,
289- 1 => args_str. into_iter ( ) . next ( ) . unwrap ( ) ,
290- _ => format ! ( "({})" , args_str. into_iter( ) . format( ", " ) ) ,
291- } ;
292- Ok ( vm. new_str ( joined_str) )
293- }
294-
295- fn exception_repr ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
296- arg_check ! (
297- vm,
298- args,
299- required = [ ( exc, Some ( vm. ctx. exceptions. exception_type. clone( ) ) ) ]
300- ) ;
301- let args = vm
302- . get_attribute ( exc. clone ( ) , "args" )
303- . unwrap ( )
304- . downcast :: < PyTuple > ( )
305- . expect ( "'args' must be a tuple" ) ;
306- let args_repr = exception_args_as_string ( vm, args, false ) ;
307-
308- let exc_name = exc. class ( ) . name . clone ( ) ;
309- let joined_str = match args_repr. len ( ) {
310- 0 => format ! ( "{}()" , exc_name) ,
311- 1 => format ! ( "{}({},)" , exc_name, args_repr[ 0 ] ) ,
312- _ => format ! ( "{}({})" , exc_name, args_repr. join( ", " ) ) ,
313- } ;
314- Ok ( vm. new_str ( joined_str) )
315- }
316-
317290#[ derive( Debug ) ]
318291pub struct ExceptionZoo {
319292 pub arithmetic_error : PyClassRef ,
@@ -508,10 +481,7 @@ impl ExceptionZoo {
508481 }
509482}
510483
511- fn import_error_init ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
512- let exc_self = args. args [ 0 ] . clone ( ) ;
513-
514- vm. set_attr ( & exc_self, "args" , vm. ctx . new_tuple ( args. args [ 1 ..] . to_vec ( ) ) ) ?;
484+ fn import_error_init ( exc_self : PyObjectRef , args : PyFuncArgs , vm : & VirtualMachine ) -> PyResult < ( ) > {
515485 vm. set_attr (
516486 & exc_self,
517487 "name" ,
@@ -528,12 +498,7 @@ fn import_error_init(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
528498 . cloned ( )
529499 . unwrap_or_else ( || vm. get_none ( ) ) ,
530500 ) ?;
531- vm. set_attr (
532- & exc_self,
533- "msg" ,
534- args. args . get ( 1 ) . cloned ( ) . unwrap_or_else ( || vm. get_none ( ) ) ,
535- ) ?;
536- Ok ( vm. get_none ( ) )
501+ Ok ( ( ) )
537502}
538503
539504fn none_getter ( _obj : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
@@ -556,11 +521,6 @@ pub fn init(ctx: &PyContext) {
556521
557522 PyBaseException :: extend_class ( ctx, & excs. base_exception_type ) ;
558523
559- extend_class ! ( ctx, & excs. exception_type, {
560- "__str__" => ctx. new_rustfunc( exception_str) ,
561- "__repr__" => ctx. new_rustfunc( exception_repr) ,
562- } ) ;
563-
564524 extend_class ! ( ctx, & excs. syntax_error, {
565525 "msg" => ctx. new_property( make_arg_getter( 0 ) ) ,
566526 "filename" => ctx. new_property( make_arg_getter( 1 ) ) ,
@@ -570,13 +530,12 @@ pub fn init(ctx: &PyContext) {
570530 } ) ;
571531
572532 extend_class ! ( ctx, & excs. import_error, {
573- "__init__" => ctx. new_rustfunc( import_error_init)
533+ "__init__" => ctx. new_rustfunc( import_error_init) ,
534+ "msg" => ctx. new_property( make_arg_getter( 0 ) ) ,
574535 } ) ;
575536
576537 extend_class ! ( ctx, & excs. stop_iteration, {
577- "value" => ctx. new_rustfunc( |obj: PyObjectRef , vm: & VirtualMachine | {
578- objiter:: stop_iter_value( vm, & obj)
579- } ) ,
538+ "value" => ctx. new_property( make_arg_getter( 0 ) ) ,
580539 } ) ;
581540
582541 extend_class ! ( ctx, & excs. unicode_decode_error, {
0 commit comments