Skip to content

Commit c563a6d

Browse files
committed
Convert Python errors to JS errors with row
1 parent 5569f8d commit c563a6d

File tree

2 files changed

+54
-11
lines changed

2 files changed

+54
-11
lines changed

wasm/lib/src/browser_module.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,7 @@ fn promise_then(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
221221
}
222222
}
223223
};
224-
ret.map(|val| convert::py_to_js(vm, val))
225-
.map_err(|err| convert::py_to_js(vm, err))
224+
convert::pyresult_to_jsresult(vm, ret)
226225
});
227226

228227
let ret_promise = future_to_promise(ret_future);
@@ -254,9 +253,8 @@ fn promise_catch(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
254253
.upgrade()
255254
.expect("that the vm is valid when the promise resolves");
256255
let err = convert::js_to_py(vm, err);
257-
vm.invoke(on_reject, PyFuncArgs::new(vec![err], vec![]))
258-
.map(|val| convert::py_to_js(vm, val))
259-
.map_err(|err| convert::py_to_js(vm, err))
256+
let res = vm.invoke(on_reject, PyFuncArgs::new(vec![err], vec![]));
257+
convert::pyresult_to_jsresult(vm, res)
260258
}
261259
});
262260

wasm/lib/src/convert.rs

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,59 @@
11
use crate::browser_module;
22
use crate::vm_class::{AccessibleVM, WASMVirtualMachine};
33
use js_sys::{Array, ArrayBuffer, Object, Promise, Reflect, Uint8Array};
4-
use rustpython_vm::obj::{objbytes, objtype};
5-
use rustpython_vm::pyobject::{self, DictProtocol, PyFuncArgs, PyObjectRef, PyResult};
4+
use num_traits::cast::ToPrimitive;
5+
use rustpython_vm::obj::{objbytes, objint, objsequence, objtype};
6+
use rustpython_vm::pyobject::{
7+
self, AttributeProtocol, DictProtocol, PyFuncArgs, PyObjectRef, PyResult,
8+
};
69
use rustpython_vm::VirtualMachine;
710
use wasm_bindgen::{closure::Closure, prelude::*, JsCast};
811

9-
pub fn py_str_err(vm: &mut VirtualMachine, py_err: &PyObjectRef) -> String {
10-
vm.to_pystr(&py_err)
11-
.unwrap_or_else(|_| "Error, and error getting error message".into())
12+
pub fn py_err_to_js_err(vm: &mut VirtualMachine, py_err: &PyObjectRef) -> JsValue {
13+
macro_rules! map_exceptions {
14+
($py_exc:ident, $msg:expr, { $($py_exc_ty:expr => $js_err_new:expr),*$(,)? }) => {
15+
$(if objtype::isinstance($py_exc, $py_exc_ty) {
16+
JsValue::from($js_err_new($msg))
17+
} else)* {
18+
JsValue::from(js_sys::Error::new($msg))
19+
}
20+
};
21+
}
22+
let msg = match py_err
23+
.get_attr("msg")
24+
.and_then(|msg| vm.to_pystr(&msg).ok())
25+
{
26+
Some(msg) => msg,
27+
None => return js_sys::Error::new("error getting error").into(),
28+
};
29+
let js_err = map_exceptions!(py_err,& msg, {
30+
// TypeError is sort of a catch-all for "this value isn't what I thought it was like"
31+
&vm.ctx.exceptions.type_error => js_sys::TypeError::new,
32+
&vm.ctx.exceptions.value_error => js_sys::TypeError::new,
33+
&vm.ctx.exceptions.index_error => js_sys::TypeError::new,
34+
&vm.ctx.exceptions.key_error => js_sys::TypeError::new,
35+
&vm.ctx.exceptions.attribute_error => js_sys::TypeError::new,
36+
&vm.ctx.exceptions.name_error => js_sys::ReferenceError::new,
37+
&vm.ctx.exceptions.syntax_error => js_sys::SyntaxError::new,
38+
});
39+
if let Some(tb) = py_err.get_attr("__traceback__") {
40+
if objtype::isinstance(&tb, &vm.ctx.list_type()) {
41+
let elements = objsequence::get_elements(&tb).to_vec();
42+
if let Some(top) = elements.get(0) {
43+
if objtype::isinstance(&top, &vm.ctx.tuple_type()) {
44+
let element = objsequence::get_elements(&top);
45+
46+
if let Some(lineno) = objint::to_int(vm, &element[1], 10)
47+
.ok()
48+
.and_then(|lineno| lineno.to_u32())
49+
{
50+
Reflect::set(&js_err, &"row".into(), &lineno.into());
51+
}
52+
}
53+
}
54+
}
55+
}
56+
js_err
1257
}
1358

1459
pub fn js_py_typeerror(vm: &mut VirtualMachine, js_err: JsValue) -> PyObjectRef {
@@ -110,7 +155,7 @@ pub fn object_entries(obj: &Object) -> impl Iterator<Item = Result<(JsValue, JsV
110155
pub fn pyresult_to_jsresult(vm: &mut VirtualMachine, result: PyResult) -> Result<JsValue, JsValue> {
111156
result
112157
.map(|value| py_to_js(vm, value))
113-
.map_err(|err| py_str_err(vm, &err).into())
158+
.map_err(|err| py_err_to_js_err(vm, &err).into())
114159
}
115160

116161
pub fn js_to_py(vm: &mut VirtualMachine, js_val: JsValue) -> PyObjectRef {

0 commit comments

Comments
 (0)