|  | 
| 4 | 4 | //  git clone https://github.com/marcomq/tauri-plugin-python | 
| 5 | 5 | 
 | 
| 6 | 6 | #[cfg(feature = "pyo3")] | 
| 7 |  | -use pyo3::PyErr; | 
|  | 7 | +use pyo3::{prelude::*, PyErr}; | 
| 8 | 8 | use serde::{ser::Serializer, Serialize}; | 
| 9 | 9 | 
 | 
| 10 | 10 | pub type Result<T> = std::result::Result<T, Error>; | 
| @@ -63,9 +63,95 @@ impl From<rustpython_vm::PyRef<rustpython_vm::builtins::PyBaseException>> for Er | 
| 63 | 63 | #[cfg(feature = "pyo3")] | 
| 64 | 64 | impl From<PyErr> for Error { | 
| 65 | 65 |     fn from(error: PyErr) -> Self { | 
| 66 |  | -        let msg = error.to_string(); | 
| 67 |  | -        println!("error: {}", &msg); | 
| 68 |  | -        Error::String(msg) | 
|  | 66 | +        let error_msg = match pyo3::Python::with_gil(|py| -> Result<Vec<String>> { | 
|  | 67 | +            let traceback_module = py.import("traceback")?; | 
|  | 68 | +            let traceback_object = error | 
|  | 69 | +                .traceback(py) | 
|  | 70 | +                .ok_or(pyo3::exceptions::PyWarning::new_err("No traceback found."))?; | 
|  | 71 | +            let extract_traceback = traceback_module.getattr("extract_tb")?; | 
|  | 72 | + | 
|  | 73 | +            // Get the formatted traceback lines | 
|  | 74 | +            let result = extract_traceback.call1((traceback_object,)).and_then(|r| { | 
|  | 75 | +                match r.extract::<Vec<PyObject>>() { | 
|  | 76 | +                    Ok(v) => { | 
|  | 77 | +                        let mut formatted_lines = Vec::new(); | 
|  | 78 | +                        for arg in v.iter() { | 
|  | 79 | +                            let frame = arg.bind(py); | 
|  | 80 | + | 
|  | 81 | +                            // Extract filename | 
|  | 82 | +                            let filename = match frame.getattr("filename") { | 
|  | 83 | +                                Ok(f) => match f.extract::<String>() { | 
|  | 84 | +                                    Ok(s) if s == "<string>".to_string() => { | 
|  | 85 | +                                        // Special handling for <string> | 
|  | 86 | +                                        frame.setattr("filename", "main.py")?; | 
|  | 87 | +                                        let lineno = frame.getattr("lineno")?.extract::<usize>()?; | 
|  | 88 | +                                        frame.setattr("lineno", lineno - 2)?; | 
|  | 89 | +                                        "main.py".to_string() | 
|  | 90 | +                                    } | 
|  | 91 | +                                    Ok(s) => s, | 
|  | 92 | +                                    Err(_) => "<unknown>".to_string(), | 
|  | 93 | +                                }, | 
|  | 94 | +                                Err(_) => "<unknown>".to_string(), | 
|  | 95 | +                            }; | 
|  | 96 | + | 
|  | 97 | +                            // Extract line number | 
|  | 98 | +                            let lineno = match frame.getattr("lineno") { | 
|  | 99 | +                                Ok(l) => match l.extract::<usize>() { | 
|  | 100 | +                                    Ok(n) => n, | 
|  | 101 | +                                    Err(_) => 0, | 
|  | 102 | +                                }, | 
|  | 103 | +                                Err(_) => 0, | 
|  | 104 | +                            }; | 
|  | 105 | + | 
|  | 106 | +                            // Extract function name | 
|  | 107 | +                            let name = match frame.getattr("name") { | 
|  | 108 | +                                Ok(n) => match n.extract::<String>() { | 
|  | 109 | +                                    Ok(s) => s, | 
|  | 110 | +                                    Err(_) => "<unknown>".to_string(), | 
|  | 111 | +                                }, | 
|  | 112 | +                                Err(_) => "<unknown>".to_string(), | 
|  | 113 | +                            }; | 
|  | 114 | + | 
|  | 115 | +                            // Extract line content (if available) | 
|  | 116 | +                            let line = match frame.getattr("line") { | 
|  | 117 | +                                Ok(l) => match l.extract::<Option<String>>() { | 
|  | 118 | +                                    Ok(Some(s)) => format!("\t{}", s), | 
|  | 119 | +                                    _ => "".to_string(), | 
|  | 120 | +                                }, | 
|  | 121 | +                                Err(_) => "".to_string(), | 
|  | 122 | +                            }; | 
|  | 123 | + | 
|  | 124 | +                            // Format the line like requested | 
|  | 125 | +                            let formatted_line = format!( | 
|  | 126 | +                                "File \"{}\", line {}, in {}\n{}", | 
|  | 127 | +                                filename, lineno, name, line | 
|  | 128 | +                            ); | 
|  | 129 | + | 
|  | 130 | +                            formatted_lines.push(formatted_line); | 
|  | 131 | +                        } | 
|  | 132 | + | 
|  | 133 | +                        Ok(formatted_lines) | 
|  | 134 | +                    } | 
|  | 135 | +                    Err(_) => Err(PyErr::new::<pyo3::exceptions::PyValueError, _>( | 
|  | 136 | +                        "Failed to extract traceback", | 
|  | 137 | +                    )), | 
|  | 138 | +                } | 
|  | 139 | +            })?; | 
|  | 140 | + | 
|  | 141 | +            // Add traceback header | 
|  | 142 | +            let mut full_traceback = vec!["Traceback (most recent call last):".to_string()]; | 
|  | 143 | +            full_traceback.extend(result); | 
|  | 144 | + | 
|  | 145 | +            // Add error type and message | 
|  | 146 | +            full_traceback.push(error.to_string()); | 
|  | 147 | + | 
|  | 148 | +            Ok(full_traceback) | 
|  | 149 | +        }) { | 
|  | 150 | +            Ok(formatted) => formatted.join("\n"), | 
|  | 151 | +            Err(_) => error.to_string(), // Fall back to simple error message | 
|  | 152 | +        }; | 
|  | 153 | + | 
|  | 154 | +        Error::String(error_msg) | 
| 69 | 155 |     } | 
| 70 | 156 | } | 
| 71 | 157 | 
 | 
|  | 
0 commit comments