use pyo3::create_exception; use pyo3::exceptions::PyException; use pyo3::exceptions::PyNotImplementedError; use pyo3::prelude::*; use pyo3::types::PyModule; use qroissant_transport::TransportError; use thiserror::Error; create_exception!( qroissant, QroissantError, PyException, "Base exception for qroissant errors." ); create_exception!( qroissant, DecodeError, QroissantError, "Raised when q IPC payload decoding fails." ); create_exception!( qroissant, ProtocolError, QroissantError, "Raised when q IPC framing or protocol validation fails." ); create_exception!( qroissant, TransportErrorPy, QroissantError, "Raised when transport IO or socket operations fail." ); create_exception!( qroissant, OperationError, QroissantError, "Raised when an operation is unsupported in the current state." ); create_exception!( qroissant, QRuntimeError, QroissantError, "Raised when the remote q process returns an error response." ); create_exception!( qroissant, PoolError, QroissantError, "Raised when connection pool management fails." ); create_exception!( qroissant, PoolClosedError, PoolError, "Raised when a closed pool is used." ); #[derive(Debug, Error)] pub enum PythonError { #[error("{0}")] Decode(String), #[error("{0}")] Protocol(String), #[error("{0}")] Transport(String), #[error("{0}")] Operation(String), #[error("{0}")] QRuntime(String), #[error("{0}")] Pool(String), #[error("connection pool is closed")] PoolClosed, #[error("{0}")] NotImplemented(String), } pub type PythonResult = Result; pub fn register(module: &Bound<'_, PyModule>) -> PyResult<()> { let py = module.py(); module.add("QroissantError", py.get_type::())?; module.add("DecodeError", py.get_type::())?; module.add("ProtocolError", py.get_type::())?; module.add("TransportError", py.get_type::())?; module.add("OperationError", py.get_type::())?; module.add("QRuntimeError", py.get_type::())?; module.add("PoolError", py.get_type::())?; module.add("PoolClosedError", py.get_type::())?; Ok(()) } pub fn to_py_err(error: PythonError) -> PyErr { match error { PythonError::Decode(message) => DecodeError::new_err(message), PythonError::Protocol(message) => ProtocolError::new_err(message), PythonError::Transport(message) => TransportErrorPy::new_err(message), PythonError::Operation(message) => OperationError::new_err(message), PythonError::QRuntime(message) => QRuntimeError::new_err(message), PythonError::Pool(message) => PoolError::new_err(message), PythonError::PoolClosed => PoolClosedError::new_err("connection pool is closed"), PythonError::NotImplemented(message) => PyNotImplementedError::new_err(message), } } pub fn map_transport_error(error: TransportError) -> PythonError { match error { TransportError::Closed => PythonError::Operation(error.to_string()), TransportError::Protocol(_) => PythonError::Protocol(error.to_string()), TransportError::Io(_) | TransportError::InvalidEndpoint(_) | TransportError::InvalidQueryLength(_) => PythonError::Transport(error.to_string()), } }