// yt - A fully featured command line YouTube client // // Copyright (C) 2025 Benedikt Peetz // SPDX-License-Identifier: GPL-3.0-or-later // // This file is part of Yt. // // You should have received a copy of the License along with this program. // If not, see . use std::fmt::{self, Display}; use log::{Level, debug, log_enabled}; 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 fmt::Formatter<'_>) -> fmt::Result { write!(f, "Python threw an exception: {}", self.0) } } impl PythonError { pub(super) fn from_exception(py: Python<'_>, exc: &PyErr) -> Self { let buffer = process_exception(py, exc); Self(buffer) } } pub(super) fn process_exception(py: Python<'_>, err: &PyErr) -> String { if log_enabled!(Level::Debug) { let mut output = err.to_string(); if let Some(tb) = err.traceback(py) { output.push('\n'); output.push_str(&tb.format().unwrap()); } debug!("Python threw an exception: {output}"); } err.to_string() }