mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-09 22:49:57 +09:00
Merge pull request #1668 from RustPython/coolreader18/exc-ser
Make PyBaseExceptionRef serializable and use it to improve WASM errors
This commit is contained in:
@@ -4,12 +4,13 @@ use crate::obj::objstr::{PyString, PyStringRef};
|
||||
use crate::obj::objtraceback::PyTracebackRef;
|
||||
use crate::obj::objtuple::{PyTuple, PyTupleRef};
|
||||
use crate::obj::objtype::{self, PyClass, PyClassRef};
|
||||
use crate::py_serde;
|
||||
use crate::pyobject::{
|
||||
PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
|
||||
TypeProtocol,
|
||||
};
|
||||
use crate::types::create_type;
|
||||
use crate::vm::VirtualMachine;
|
||||
use crate::VirtualMachine;
|
||||
use itertools::Itertools;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt;
|
||||
@@ -245,10 +246,8 @@ pub fn write_exception_inner<W: Write>(
|
||||
) -> io::Result<()> {
|
||||
if let Some(tb) = exc.traceback.borrow().clone() {
|
||||
writeln!(output, "Traceback (most recent call last):")?;
|
||||
let mut tb = Some(&tb);
|
||||
while let Some(traceback) = tb {
|
||||
write_traceback_entry(output, traceback)?;
|
||||
tb = traceback.next.as_ref();
|
||||
for tb in tb.iter() {
|
||||
write_traceback_entry(output, &tb)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,3 +659,71 @@ pub fn init(ctx: &PyContext) {
|
||||
"reason" => ctx.new_property(make_arg_getter(3)),
|
||||
});
|
||||
}
|
||||
|
||||
pub struct SerializeException<'s> {
|
||||
vm: &'s VirtualMachine,
|
||||
exc: &'s PyBaseExceptionRef,
|
||||
}
|
||||
|
||||
impl<'s> SerializeException<'s> {
|
||||
pub fn new(vm: &'s VirtualMachine, exc: &'s PyBaseExceptionRef) -> Self {
|
||||
SerializeException { vm, exc }
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for SerializeException<'_> {
|
||||
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
use serde::ser::*;
|
||||
|
||||
let mut struc = s.serialize_struct("PyBaseException", 7)?;
|
||||
struc.serialize_field("exc_type", &self.exc.class().name)?;
|
||||
let tbs = {
|
||||
struct Tracebacks(PyTracebackRef);
|
||||
impl serde::Serialize for Tracebacks {
|
||||
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
let mut s = s.serialize_seq(None)?;
|
||||
for tb in self.0.iter() {
|
||||
s.serialize_element(&*tb)?;
|
||||
}
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
self.exc.traceback().map(Tracebacks)
|
||||
};
|
||||
struc.serialize_field("traceback", &tbs)?;
|
||||
struc.serialize_field(
|
||||
"cause",
|
||||
&self.exc.cause().as_ref().map(|e| Self::new(self.vm, e)),
|
||||
)?;
|
||||
struc.serialize_field(
|
||||
"context",
|
||||
&self.exc.context().as_ref().map(|e| Self::new(self.vm, e)),
|
||||
)?;
|
||||
struc.serialize_field("suppress_context", &self.exc.suppress_context.get())?;
|
||||
|
||||
let args = {
|
||||
struct Args<'vm>(&'vm VirtualMachine, PyTupleRef);
|
||||
impl serde::Serialize for Args<'_> {
|
||||
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
s.collect_seq(
|
||||
self.1
|
||||
.as_slice()
|
||||
.iter()
|
||||
.map(|arg| py_serde::PyObjectSerializer::new(self.0, arg)),
|
||||
)
|
||||
}
|
||||
}
|
||||
Args(self.vm, self.exc.args())
|
||||
};
|
||||
struc.serialize_field("args", &args)?;
|
||||
|
||||
let rendered = {
|
||||
let mut rendered = Vec::<u8>::new();
|
||||
write_exception(&mut rendered, self.vm, &self.exc).map_err(S::Error::custom)?;
|
||||
String::from_utf8(rendered).map_err(S::Error::custom)?
|
||||
};
|
||||
struc.serialize_field("rendered", &rendered)?;
|
||||
|
||||
struc.end()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,24 @@ impl PyTraceback {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyTracebackRef {
|
||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = PyTracebackRef> + 'a {
|
||||
std::iter::successors(Some(self.clone()), |tb| tb.next.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
PyTraceback::extend_class(context, &context.types.traceback_type);
|
||||
}
|
||||
|
||||
impl serde::Serialize for PyTraceback {
|
||||
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
use serde::ser::SerializeStruct;
|
||||
|
||||
let mut struc = s.serialize_struct("PyTraceback", 3)?;
|
||||
struc.serialize_field("name", &self.frame.code.obj_name)?;
|
||||
struc.serialize_field("lineno", &self.lineno)?;
|
||||
struc.serialize_field("filename", &self.frame.code.source_path)?;
|
||||
struc.end()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user