From 82277ca7513eff82365ed54fe9836aae5bd45fe1 Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Thu, 10 Jul 2025 16:36:42 +0200 Subject: refactor(crates/yt_dlp): Port to `pyo3` again Rustpyton is slower, does not implement everything correctly and worst of all, contains code produced by LLM's. Using the freethreaded mode of pyo3 also works nicely around the GIL, and enables parallel execution. --- crates/yt_dlp/src/python_error.rs | 105 ++++++++------------------------------ 1 file changed, 22 insertions(+), 83 deletions(-) (limited to 'crates/yt_dlp/src/python_error.rs') diff --git a/crates/yt_dlp/src/python_error.rs b/crates/yt_dlp/src/python_error.rs index 9513956..0c442b3 100644 --- a/crates/yt_dlp/src/python_error.rs +++ b/crates/yt_dlp/src/python_error.rs @@ -8,109 +8,48 @@ // You should have received a copy of the License along with this program. // If not, see . -use std::fmt::Display; +use std::fmt::{self, Display}; use log::{Level, debug, log_enabled}; -use rustpython::vm::{ - AsObject, PyPayload, PyRef, VirtualMachine, - builtins::{PyBaseException, PyBaseExceptionRef, PyStr}, - py_io::Write, - suggestion::offer_suggestions, -}; +use pyo3::{PyErr, Python, types::PyTracebackMethods}; #[derive(thiserror::Error, Debug)] pub struct PythonError(pub String); +pub(crate) trait IntoPythonError: Sized { + fn wrap_exc(self, py: Python<'_>) -> Result; +} + +impl IntoPythonError for Result { + fn wrap_exc(self, py: Python<'_>) -> Result { + self.map_err(|exc| PythonError::from_exception(py, &exc)) + } +} + impl Display for PythonError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Python threw an exception: {}", self.0) } } impl PythonError { - pub(super) fn from_exception(vm: &VirtualMachine, exc: &PyRef) -> Self { - let buffer = process_exception(vm, exc); + pub(super) fn from_exception(py: Python<'_>, exc: &PyErr) -> Self { + let buffer = process_exception(py, exc); Self(buffer) } } -pub(super) fn process_exception(vm: &VirtualMachine, err: &PyBaseExceptionRef) -> String { - let mut buffer = String::new(); - write_exception(vm, &mut buffer, err) - .expect("We are writing into an *in-memory* string, it will always work"); - +pub(super) fn process_exception(py: Python<'_>, err: &PyErr) -> String { if log_enabled!(Level::Debug) { - let mut output = String::new(); - vm.write_exception(&mut output, err) - .expect("We are writing into an *in-memory* string, it will always work"); - debug!("Python threw an exception: {output}"); - } + let mut output = err.to_string(); - buffer -} - -// Inlined and changed from `vm.write_exception_inner` -fn write_exception( - vm: &VirtualMachine, - output: &mut W, - exc: &PyBaseExceptionRef, -) -> Result<(), W::Error> { - let varargs = exc.args(); - let args_repr = { - match varargs.len() { - 0 => vec![], - 1 => { - let args0_repr = if true { - varargs[0] - .str(vm) - .unwrap_or_else(|_| PyStr::from("").into_ref(&vm.ctx)) - } else { - varargs[0].repr(vm).unwrap_or_else(|_| { - PyStr::from("").into_ref(&vm.ctx) - }) - }; - vec![args0_repr] - } - _ => varargs - .iter() - .map(|vararg| { - vararg.repr(vm).unwrap_or_else(|_| { - PyStr::from("").into_ref(&vm.ctx) - }) - }) - .collect(), + if let Some(tb) = err.traceback(py) { + output.push('\n'); + output.push_str(&tb.format().unwrap()); } - }; - let exc_class = exc.class(); - - if exc_class.fast_issubclass(vm.ctx.exceptions.syntax_error) { - unreachable!( - "A syntax error should never be raised, \ - as yt_dlp should not have them and neither our embedded code" - ); + debug!("Python threw an exception: {output}"); } - let exc_name = exc_class.name(); - match args_repr.len() { - 0 => write!(output, "{exc_name}"), - 1 => write!(output, "{}: {}", exc_name, args_repr[0]), - _ => write!( - output, - "{}: ({})", - exc_name, - args_repr - .iter() - .map(|val| val.as_str()) - .collect::>() - .join(", "), - ), - }?; - - match offer_suggestions(exc, vm) { - Some(suggestions) => { - write!(output, ". Did you mean: '{suggestions}'?") - } - None => Ok(()), - } + err.to_string() } -- cgit 1.4.1