@@ -47,17 +47,16 @@ impl Context {
47
47
///
48
48
/// This function panics if it fails to create the context.
49
49
#[ allow( clippy:: new_without_default) ]
50
+ #[ track_caller]
50
51
pub fn new ( ) -> Self {
51
52
Python :: with_gil ( Self :: new_with_gil)
52
53
}
53
54
55
+ #[ track_caller]
54
56
pub ( crate ) fn new_with_gil ( py : Python ) -> Self {
55
57
match Self :: try_new ( py) {
56
58
Ok ( x) => x,
57
- Err ( error) => {
58
- error. print ( py) ;
59
- panic ! ( "failed to create Python context" ) ;
60
- }
59
+ Err ( err) => panic ! ( "{}" , panic_string( py, & err) ) ,
61
60
}
62
61
}
63
62
@@ -80,10 +79,7 @@ impl Context {
80
79
Err ( _) | Ok ( None ) => panic ! ( "Python context does not contain a variable named `{}`" , name) ,
81
80
Ok ( Some ( value) ) => match FromPyObject :: extract_bound ( & value) {
82
81
Ok ( value) => value,
83
- Err ( e) => {
84
- e. print ( py) ;
85
- panic ! ( "Unable to convert `{}` to `{}`" , name, std:: any:: type_name:: <T >( ) ) ;
86
- }
82
+ Err ( e) => panic ! ( "Unable to convert `{}` to `{}`: {e}" , name, std:: any:: type_name:: <T >( ) ) ,
87
83
} ,
88
84
} )
89
85
}
@@ -92,11 +88,9 @@ impl Context {
92
88
///
93
89
/// This function panics if the conversion fails.
94
90
pub fn set < T : for < ' p > IntoPyObject < ' p > > ( & self , name : & str , value : T ) {
95
- Python :: with_gil ( |py| match self . globals ( ) . bind ( py) . set_item ( name, value) {
96
- Ok ( ( ) ) => ( ) ,
97
- Err ( e) => {
98
- e. print ( py) ;
99
- panic ! ( "Unable to set `{}` from a `{}`" , name, std:: any:: type_name:: <T >( ) ) ;
91
+ Python :: with_gil ( |py| {
92
+ if let Err ( e) = self . globals ( ) . bind ( py) . set_item ( name, value) {
93
+ panic ! ( "Unable to set `{}` from a `{}`: {e}" , name, std:: any:: type_name:: <T >( ) ) ;
100
94
}
101
95
} )
102
96
}
@@ -127,10 +121,9 @@ impl Context {
127
121
pub fn add_wrapped ( & self , wrapper : & impl Fn ( Python ) -> PyResult < Bound < ' _ , PyCFunction > > ) {
128
122
Python :: with_gil ( |py| {
129
123
let obj = wrapper ( py) . unwrap ( ) ;
130
- let name = obj. getattr ( "__name__" ) . expect ( "Missing __name__" ) ;
131
- if let Err ( e) = self . globals ( ) . bind ( py) . set_item ( name, obj) {
132
- e. print ( py) ;
133
- panic ! ( "Unable to add wrapped function" ) ;
124
+ let name = obj. getattr ( "__name__" ) . expect ( "wrapped item should have a __name__" ) ;
125
+ if let Err ( err) = self . globals ( ) . bind ( py) . set_item ( name, obj) {
126
+ panic ! ( "{}" , panic_string( py, & err) ) ;
134
127
}
135
128
} )
136
129
}
@@ -153,14 +146,28 @@ impl Context {
153
146
Python :: with_gil ( |py| self . run_with_gil ( py, code) ) ;
154
147
}
155
148
156
- pub ( crate ) fn run_with_gil < F : FnOnce ( & Bound < PyDict > ) > ( & self , py : Python < ' _ > , code : PythonBlock < F > ) {
157
- ( code. set_variables ) ( self . globals ( ) . bind ( py) ) ;
158
- match run_python_code ( py, self , code. bytecode ) {
159
- Ok ( _) => ( ) ,
160
- Err ( e) => {
161
- e. print ( py) ;
162
- panic ! ( "{}" , "python!{...} failed to execute" ) ;
163
- }
149
+ pub ( crate ) fn run_with_gil < F : FnOnce ( & Bound < PyDict > ) > ( & self , py : Python < ' _ > , block : PythonBlock < F > ) {
150
+ ( block. set_variables ) ( self . globals ( ) . bind ( py) ) ;
151
+ if let Err ( err) = run_python_code ( py, self , block. bytecode ) {
152
+ ( block. panic ) ( panic_string ( py, & err) ) ;
164
153
}
165
154
}
166
155
}
156
+
157
+ fn panic_string ( py : Python , err : & PyErr ) -> String {
158
+ match py_err_to_string ( py, & err) {
159
+ Ok ( msg) => msg,
160
+ Err ( _) => err. to_string ( ) ,
161
+ }
162
+ }
163
+
164
+ /// Print the error while capturing stderr into a String.
165
+ fn py_err_to_string ( py : Python , err : & PyErr ) -> Result < String , PyErr > {
166
+ let sys = py. import ( "sys" ) ?;
167
+ let stderr = py. import ( "io" ) ?. getattr ( "StringIO" ) ?. call0 ( ) ?;
168
+ let original_stderr = sys. dict ( ) . get_item ( "stderr" ) ?;
169
+ sys. dict ( ) . set_item ( "stderr" , & stderr) ?;
170
+ err. print ( py) ;
171
+ sys. dict ( ) . set_item ( "stderr" , original_stderr) ?;
172
+ stderr. call_method0 ( "getvalue" ) ?. extract ( )
173
+ }
0 commit comments