Allow constructing PyTraceback - #5857
Conversation
608cc0d to
e082d4f
Compare
911f992 to
5096f1f
Compare
|
Interesting, I would be very curious to know how this looks for injecting Rust call frames into Python tracebacks. |
Did some testing using |
| .unwrap_or_else(|| { | ||
| let frame = PyFrame::new(py, c"<unknown>", c"<unknown>", 0)?; | ||
| PyTraceback::new(py, None, frame, 0, 0) | ||
| }) |
There was a problem hiding this comment.
Rather than a null frame, should this just result Result<Option<...>> and let the user handle the empty case?
We could experiment with creating |
7185363 to
d9ca236
Compare
|
Might be nice to find a way to do this in abi3 as well. Does someone have an idea how to do that? |
|
|
|
We could potentially open an upstream CPython issue asking for a way to create dummy Rust tracebacks in the stable ABI; this sort of mixed-language traceback might be a nice ergonomics win for some projects. On the other hand, perhaps debugging the Rust frames is most useful when debugging the Rust module itself, at which time it won't be for distribution so using the limited API might be acceptable... |
I could not find a way to construct a frame with python, so might not be possible.
I think for now this is acceptable as a first step. |
|
Found a way to make this work on let code = PyCode::compile(py, c"raise Exception()", file_name, PyCodeInput::File)?;
let kwargs = [
("co_firstlineno", line_number.into_py_any(py)?),
("co_name", func_name.into_py_any(py)?),
]
.into_py_dict(py)?;
let traceback = code
.call_method("replace", (), Some(&kwargs))
.cast_into::<PyCode>()?
.run(None, None)
.unwrap_err()
.traceback(py)
.expect("traceback should be present");
traceback.getattr("tb_frame").cast_into() |
7a18642 to
9f2498b
Compare
| /// Creates a new traceback object from an iterator of frames. | ||
| /// | ||
| /// The frames should be ordered from newest to oldest, i.e. the first frame in the iterator | ||
| /// will be the innermost frame in the traceback. | ||
| #[cfg(all(not(Py_LIMITED_API), not(PyPy), not(GraalPy)))] | ||
| pub fn from_frames<'py, I>( | ||
| py: Python<'py>, | ||
| frames: I, | ||
| ) -> PyResult<Option<Bound<'py, PyTraceback>>> | ||
| where | ||
| I: IntoIterator, | ||
| I::Item: IntoPyObject<'py,> | ||
| { | ||
| frames.into_iter().try_fold(None, |prev, frame| { | ||
| let frame = frame.into_pyobject(py).map_err(Into::into)?.into_bound(); | ||
| let line_number = frame.line_number(); | ||
| PyTraceback::new(py, prev, frame, 0, line_number).map(Some) | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
I'm not sure about this api yet. Should I remove it from this MR so we can iterate on the design later?
There was a problem hiding this comment.
I've removed PyTraceback::from_frames for now. So this is ready for final review.
There was a problem hiding this comment.
Seems reasonable to me to play it slow 👍
9f2498b to
4c436a4
Compare
4c436a4 to
e343e24
Compare
e343e24 to
88eaa0d
Compare
850ed1c to
efe5c89
Compare
davidhewitt
left a comment
There was a problem hiding this comment.
Thanks, this seems good to me!
No description provided.