@@ -5,19 +5,20 @@ use crate::obj::objstr::{PyString, PyStringRef};
5
5
use crate :: obj:: objtraceback:: PyTracebackRef ;
6
6
use crate :: obj:: objtuple:: { PyTuple , PyTupleRef } ;
7
7
use crate :: obj:: objtype:: { self , PyClass , PyClassRef } ;
8
- use crate :: py_serde ;
8
+ use crate :: py_io :: { self , Write } ;
9
9
use crate :: pyobject:: {
10
10
PyClassImpl , PyContext , PyIterable , PyObjectRef , PyRef , PyResult , PyValue , TryFromObject ,
11
11
TypeProtocol ,
12
12
} ;
13
13
use crate :: slots:: PyTpFlags ;
14
14
use crate :: types:: create_type;
15
15
use crate :: VirtualMachine ;
16
+ use crate :: { py_serde, sysmodule} ;
16
17
17
18
use itertools:: Itertools ;
18
19
use std:: fmt;
19
20
use std:: fs:: File ;
20
- use std:: io:: { self , BufRead , BufReader , Write } ;
21
+ use std:: io:: { self , BufRead , BufReader } ;
21
22
22
23
use crossbeam_utils:: atomic:: AtomicCell ;
23
24
@@ -146,18 +147,35 @@ impl PyBaseException {
146
147
}
147
148
}
148
149
149
- /// Print exception chain
150
- pub fn print_exception ( vm : & VirtualMachine , exc : & PyBaseExceptionRef ) {
151
- let stderr = io:: stderr ( ) ;
152
- let mut stderr = stderr. lock ( ) ;
153
- let _ = write_exception ( & mut stderr, vm, exc) ;
150
+ /// Print exception chain by calling sys.excepthook
151
+ pub fn print_exception ( vm : & VirtualMachine , exc : PyBaseExceptionRef ) {
152
+ let write_fallback = |exc, errstr| {
153
+ if let Ok ( stderr) = sysmodule:: get_stderr ( vm) {
154
+ let mut stderr = py_io:: PyWriter ( stderr, vm) ;
155
+ // if this fails stderr might be closed -- ignore it
156
+ let _ = writeln ! ( stderr, "{}" , errstr) ;
157
+ let _ = write_exception ( & mut stderr, vm, exc) ;
158
+ } else {
159
+ eprintln ! ( "{}\n lost sys.stderr" , errstr) ;
160
+ let _ = write_exception ( & mut io:: stderr ( ) , vm, exc) ;
161
+ }
162
+ } ;
163
+ if let Ok ( excepthook) = vm. get_attribute ( vm. sys_module . clone ( ) , "excepthook" ) {
164
+ let ( exc_type, exc_val, exc_tb) = split ( exc, vm) ;
165
+ if let Err ( eh_exc) = vm. invoke ( & excepthook, vec ! [ exc_type, exc_val, exc_tb] ) {
166
+ write_fallback ( & eh_exc, "Error in sys.excepthook:" ) ;
167
+ write_fallback ( & eh_exc, "Original exception was:" ) ;
168
+ }
169
+ } else {
170
+ write_fallback ( & exc, "missing sys.excepthook" ) ;
171
+ }
154
172
}
155
173
156
174
pub fn write_exception < W : Write > (
157
175
output : & mut W ,
158
176
vm : & VirtualMachine ,
159
177
exc : & PyBaseExceptionRef ,
160
- ) -> io :: Result < ( ) > {
178
+ ) -> Result < ( ) , W :: Error > {
161
179
if let Some ( cause) = exc. cause ( ) {
162
180
write_exception ( output, vm, & cause) ?;
163
181
writeln ! (
@@ -175,7 +193,11 @@ pub fn write_exception<W: Write>(
175
193
write_exception_inner ( output, vm, exc)
176
194
}
177
195
178
- fn print_source_line < W : Write > ( output : & mut W , filename : & str , lineno : usize ) -> io:: Result < ( ) > {
196
+ fn print_source_line < W : Write > (
197
+ output : & mut W ,
198
+ filename : & str ,
199
+ lineno : usize ,
200
+ ) -> Result < ( ) , W :: Error > {
179
201
// TODO: use io.open() method instead, when available, according to https://github.com/python/cpython/blob/master/Python/traceback.c#L393
180
202
// TODO: support different encodings
181
203
let file = match File :: open ( filename) {
@@ -198,7 +220,10 @@ fn print_source_line<W: Write>(output: &mut W, filename: &str, lineno: usize) ->
198
220
}
199
221
200
222
/// Print exception occurrence location from traceback element
201
- fn write_traceback_entry < W : Write > ( output : & mut W , tb_entry : & PyTracebackRef ) -> io:: Result < ( ) > {
223
+ fn write_traceback_entry < W : Write > (
224
+ output : & mut W ,
225
+ tb_entry : & PyTracebackRef ,
226
+ ) -> Result < ( ) , W :: Error > {
202
227
let filename = tb_entry. frame . code . source_path . to_owned ( ) ;
203
228
writeln ! (
204
229
output,
@@ -215,7 +240,7 @@ pub fn write_exception_inner<W: Write>(
215
240
output : & mut W ,
216
241
vm : & VirtualMachine ,
217
242
exc : & PyBaseExceptionRef ,
218
- ) -> io :: Result < ( ) > {
243
+ ) -> Result < ( ) , W :: Error > {
219
244
if let Some ( tb) = exc. traceback . read ( ) . clone ( ) {
220
245
writeln ! ( output, "Traceback (most recent call last):" ) ?;
221
246
for tb in tb. iter ( ) {
@@ -341,6 +366,14 @@ impl ExceptionCtor {
341
366
}
342
367
}
343
368
369
+ pub fn split (
370
+ exc : PyBaseExceptionRef ,
371
+ vm : & VirtualMachine ,
372
+ ) -> ( PyObjectRef , PyObjectRef , PyObjectRef ) {
373
+ let tb = exc. traceback ( ) . map_or ( vm. get_none ( ) , |tb| tb. into_object ( ) ) ;
374
+ ( exc. class ( ) . into_object ( ) , exc. into_object ( ) , tb)
375
+ }
376
+
344
377
/// Similar to PyErr_NormalizeException in CPython
345
378
pub fn normalize (
346
379
exc_type : PyObjectRef ,
0 commit comments