Skip to content

Commit bb45696

Browse files
authored
Merge pull request RustPython#1668 from RustPython/coolreader18/exc-ser
Make PyBaseExceptionRef serializable and use it to improve WASM errors
2 parents bc0baa4 + c5264c9 commit bb45696

File tree

7 files changed

+189
-104
lines changed

7 files changed

+189
-104
lines changed

Cargo.lock

Lines changed: 48 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vm/src/exceptions.rs

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ use crate::obj::objstr::{PyString, PyStringRef};
44
use crate::obj::objtraceback::PyTracebackRef;
55
use crate::obj::objtuple::{PyTuple, PyTupleRef};
66
use crate::obj::objtype::{self, PyClass, PyClassRef};
7+
use crate::py_serde;
78
use crate::pyobject::{
89
PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
910
TypeProtocol,
1011
};
1112
use crate::types::create_type;
12-
use crate::vm::VirtualMachine;
13+
use crate::VirtualMachine;
1314
use itertools::Itertools;
1415
use std::cell::{Cell, RefCell};
1516
use std::fmt;
@@ -245,10 +246,8 @@ pub fn write_exception_inner<W: Write>(
245246
) -> io::Result<()> {
246247
if let Some(tb) = exc.traceback.borrow().clone() {
247248
writeln!(output, "Traceback (most recent call last):")?;
248-
let mut tb = Some(&tb);
249-
while let Some(traceback) = tb {
250-
write_traceback_entry(output, traceback)?;
251-
tb = traceback.next.as_ref();
249+
for tb in tb.iter() {
250+
write_traceback_entry(output, &tb)?;
252251
}
253252
}
254253

@@ -660,3 +659,71 @@ pub fn init(ctx: &PyContext) {
660659
"reason" => ctx.new_property(make_arg_getter(3)),
661660
});
662661
}
662+
663+
pub struct SerializeException<'s> {
664+
vm: &'s VirtualMachine,
665+
exc: &'s PyBaseExceptionRef,
666+
}
667+
668+
impl<'s> SerializeException<'s> {
669+
pub fn new(vm: &'s VirtualMachine, exc: &'s PyBaseExceptionRef) -> Self {
670+
SerializeException { vm, exc }
671+
}
672+
}
673+
674+
impl serde::Serialize for SerializeException<'_> {
675+
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
676+
use serde::ser::*;
677+
678+
let mut struc = s.serialize_struct("PyBaseException", 7)?;
679+
struc.serialize_field("exc_type", &self.exc.class().name)?;
680+
let tbs = {
681+
struct Tracebacks(PyTracebackRef);
682+
impl serde::Serialize for Tracebacks {
683+
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
684+
let mut s = s.serialize_seq(None)?;
685+
for tb in self.0.iter() {
686+
s.serialize_element(&*tb)?;
687+
}
688+
s.end()
689+
}
690+
}
691+
self.exc.traceback().map(Tracebacks)
692+
};
693+
struc.serialize_field("traceback", &tbs)?;
694+
struc.serialize_field(
695+
"cause",
696+
&self.exc.cause().as_ref().map(|e| Self::new(self.vm, e)),
697+
)?;
698+
struc.serialize_field(
699+
"context",
700+
&self.exc.context().as_ref().map(|e| Self::new(self.vm, e)),
701+
)?;
702+
struc.serialize_field("suppress_context", &self.exc.suppress_context.get())?;
703+
704+
let args = {
705+
struct Args<'vm>(&'vm VirtualMachine, PyTupleRef);
706+
impl serde::Serialize for Args<'_> {
707+
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
708+
s.collect_seq(
709+
self.1
710+
.as_slice()
711+
.iter()
712+
.map(|arg| py_serde::PyObjectSerializer::new(self.0, arg)),
713+
)
714+
}
715+
}
716+
Args(self.vm, self.exc.args())
717+
};
718+
struc.serialize_field("args", &args)?;
719+
720+
let rendered = {
721+
let mut rendered = Vec::<u8>::new();
722+
write_exception(&mut rendered, self.vm, &self.exc).map_err(S::Error::custom)?;
723+
String::from_utf8(rendered).map_err(S::Error::custom)?
724+
};
725+
struc.serialize_field("rendered", &rendered)?;
726+
727+
struc.end()
728+
}
729+
}

0 commit comments

Comments
 (0)