@@ -4,8 +4,7 @@ use crate::obj::objtraceback::PyTracebackRef;
44use crate :: obj:: objtuple:: { PyTuple , PyTupleRef } ;
55use crate :: obj:: objtype:: PyClassRef ;
66use crate :: pyobject:: {
7- IdProtocol , PyClassImpl , PyContext , PyIterable , PyObjectRef , PyRef , PyResult , PyValue ,
8- TypeProtocol ,
7+ PyClassImpl , PyContext , PyIterable , PyObjectRef , PyRef , PyResult , PyValue , TypeProtocol ,
98} ;
109use crate :: types:: create_type;
1110use crate :: vm:: VirtualMachine ;
@@ -18,8 +17,8 @@ use std::io::{self, BufRead, BufReader, Write};
1817#[ pyclass]
1918pub struct PyBaseException {
2019 traceback : RefCell < Option < PyTracebackRef > > ,
21- cause : RefCell < Option < PyObjectRef > > ,
22- context : RefCell < Option < PyObjectRef > > ,
20+ cause : RefCell < Option < PyBaseExceptionRef > > ,
21+ context : RefCell < Option < PyBaseExceptionRef > > ,
2322 suppress_context : Cell < bool > ,
2423 args : RefCell < PyTupleRef > ,
2524}
@@ -83,12 +82,12 @@ impl PyBaseException {
8382 }
8483
8584 #[ pyproperty( name = "__traceback__" , setter) ]
86- fn set_traceback ( & self , traceback : Option < PyTracebackRef > , _vm : & VirtualMachine ) {
85+ fn setter_traceback ( & self , traceback : Option < PyTracebackRef > , _vm : & VirtualMachine ) {
8786 self . traceback . replace ( traceback) ;
8887 }
8988
9089 #[ pyproperty( name = "__cause__" ) ]
91- fn get_cause ( & self , _vm : & VirtualMachine ) -> Option < PyObjectRef > {
90+ fn get_cause ( & self , _vm : & VirtualMachine ) -> Option < PyBaseExceptionRef > {
9291 self . cause . borrow ( ) . clone ( )
9392 }
9493
@@ -98,7 +97,7 @@ impl PyBaseException {
9897 }
9998
10099 #[ pyproperty( name = "__context__" ) ]
101- fn get_context ( & self , _vm : & VirtualMachine ) -> Option < PyObjectRef > {
100+ fn get_context ( & self , _vm : & VirtualMachine ) -> Option < PyBaseExceptionRef > {
102101 self . context . borrow ( ) . clone ( )
103102 }
104103
@@ -150,51 +149,67 @@ impl PyBaseException {
150149 pub fn args ( & self ) -> PyTupleRef {
151150 self . args . borrow ( ) . clone ( )
152151 }
152+
153+ pub fn traceback ( & self ) -> Option < PyTracebackRef > {
154+ self . traceback . borrow ( ) . clone ( )
155+ }
156+ pub fn set_traceback ( & self , tb : Option < PyTracebackRef > ) {
157+ self . traceback . replace ( tb) ;
158+ }
159+
160+ pub fn cause ( & self ) -> Option < PyBaseExceptionRef > {
161+ self . cause . borrow ( ) . clone ( )
162+ }
163+ pub fn set_cause ( & self , cause : Option < PyBaseExceptionRef > ) {
164+ self . cause . replace ( cause) ;
165+ }
166+
167+ pub fn context ( & self ) -> Option < PyBaseExceptionRef > {
168+ self . context . borrow ( ) . clone ( )
169+ }
170+ pub fn set_context ( & self , context : Option < PyBaseExceptionRef > ) {
171+ self . context . replace ( context) ;
172+ }
153173}
154174
155175/// Print exception chain
156- pub fn print_exception ( vm : & VirtualMachine , exc : & PyObjectRef ) {
157- let _ = write_exception ( io:: stdout ( ) , vm, exc) ;
176+ pub fn print_exception ( vm : & VirtualMachine , exc : & PyBaseExceptionRef ) {
177+ let stdout = io:: stdout ( ) ;
178+ let mut stdout = stdout. lock ( ) ;
179+ let _ = write_exception ( & mut stdout, vm, exc) ;
158180}
159181
160182pub fn write_exception < W : Write > (
161- mut output : W ,
183+ output : & mut W ,
162184 vm : & VirtualMachine ,
163- exc : & PyObjectRef ,
185+ exc : & PyBaseExceptionRef ,
164186) -> io:: Result < ( ) > {
165- let mut had_cause = false ;
166- if let Ok ( cause) = vm. get_attribute ( exc. clone ( ) , "__cause__" ) {
167- if !vm. get_none ( ) . is ( & cause) {
168- had_cause = true ;
169- print_exception ( vm, & cause) ;
187+ let cause = exc. cause ( ) ;
188+ if let Some ( cause) = & cause {
189+ write_exception ( output, vm, cause) ?;
190+ writeln ! (
191+ output,
192+ "\n The above exception was the direct cause of the following exception:\n "
193+ ) ?;
194+ }
195+ if cause. is_none ( ) {
196+ if let Some ( context) = exc. context ( ) {
197+ write_exception ( output, vm, & context) ?;
170198 writeln ! (
171199 output,
172- "\n The above exception was the direct cause of the following exception:\n "
200+ "\n During handling of the above exception, another exception occurred :\n "
173201 ) ?;
174202 }
175203 }
176- if !had_cause {
177- if let Ok ( context) = vm. get_attribute ( exc. clone ( ) , "__context__" ) {
178- if !vm. get_none ( ) . is ( & context) {
179- print_exception ( vm, & context) ;
180- writeln ! (
181- output,
182- "\n During handling of the above exception, another exception occurred:\n "
183- ) ?;
184- }
185- }
186- }
187- print_exception_inner ( output, vm, exc)
204+ write_exception_inner ( output, vm, exc)
188205}
189206
190- fn print_source_line < W : Write > ( mut output : W , filename : & str , lineno : usize ) -> io:: Result < ( ) > {
207+ fn print_source_line < W : Write > ( output : & mut W , filename : & str , lineno : usize ) -> io:: Result < ( ) > {
191208 // TODO: use io.open() method instead, when available, according to https://github.com/python/cpython/blob/master/Python/traceback.c#L393
192209 // TODO: support different encodings
193210 let file = match File :: open ( filename) {
194211 Ok ( file) => file,
195- Err ( _) => {
196- return Ok ( ( ) ) ;
197- }
212+ Err ( _) => return Ok ( ( ) ) ,
198213 } ;
199214 let file = BufReader :: new ( file) ;
200215
@@ -212,7 +227,7 @@ fn print_source_line<W: Write>(mut output: W, filename: &str, lineno: usize) ->
212227}
213228
214229/// Print exception occurrence location from traceback element
215- fn print_traceback_entry < W : Write > ( mut output : W , tb_entry : & PyTracebackRef ) -> io:: Result < ( ) > {
230+ fn write_traceback_entry < W : Write > ( output : & mut W , tb_entry : & PyTracebackRef ) -> io:: Result < ( ) > {
216231 let filename = tb_entry. frame . code . source_path . to_string ( ) ;
217232 writeln ! (
218233 output,
@@ -225,19 +240,17 @@ fn print_traceback_entry<W: Write>(mut output: W, tb_entry: &PyTracebackRef) ->
225240}
226241
227242/// Print exception with traceback
228- pub fn print_exception_inner < W : Write > (
229- mut output : W ,
243+ pub fn write_exception_inner < W : Write > (
244+ output : & mut W ,
230245 vm : & VirtualMachine ,
231- exc : & PyObjectRef ,
246+ exc : & PyBaseExceptionRef ,
232247) -> io:: Result < ( ) > {
233- let exc: PyBaseExceptionRef = exc. clone ( ) . downcast ( ) . unwrap ( ) ;
234-
235248 if let Some ( tb) = exc. traceback . borrow ( ) . clone ( ) {
236249 writeln ! ( output, "Traceback (most recent call last):" ) ?;
237- let mut tb = & Some ( tb) ;
250+ let mut tb = Some ( & tb) ;
238251 while let Some ( traceback) = tb {
239- print_traceback_entry ( & mut output, traceback) ?;
240- tb = & traceback. next ;
252+ write_traceback_entry ( output, traceback) ?;
253+ tb = traceback. next . as_ref ( ) ;
241254 }
242255 } else {
243256 writeln ! ( output, "No traceback set on exception" ) ?;
@@ -505,14 +518,14 @@ fn none_getter(_obj: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
505518 vm. get_none ( )
506519}
507520
508- fn make_arg_getter ( idx : usize ) -> impl Fn ( PyBaseExceptionRef , & VirtualMachine ) -> PyResult {
521+ fn make_arg_getter ( idx : usize ) -> impl Fn ( PyBaseExceptionRef , & VirtualMachine ) -> PyObjectRef {
509522 move |exc, vm| {
510523 exc. args
511524 . borrow ( )
512525 . elements
513526 . get ( idx)
514527 . cloned ( )
515- . ok_or_else ( || vm. new_value_error ( format ! ( "couldn't get arg {} of exception" , idx ) ) )
528+ . unwrap_or_else ( || vm. get_none ( ) )
516529 }
517530}
518531
0 commit comments