Skip to content

Commit

Permalink
Add type info to conversion errors.
Browse files Browse the repository at this point in the history
  • Loading branch information
sebpuetz committed Jul 18, 2020
1 parent 264e885 commit 6bda2f9
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 12 deletions.
20 changes: 16 additions & 4 deletions src/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,10 @@ where
if T::is_instance(value) {
Ok(Self::try_from_unchecked(value))
} else {
Err(PyDowncastError)
Err(PyDowncastError::new(
Some(value.get_type().name().as_ref()),
Some(T::NAME),
))
}
}
}
Expand All @@ -375,7 +378,10 @@ where
if T::is_exact_instance(value) {
Ok(Self::try_from_unchecked(value))
} else {
Err(PyDowncastError)
Err(PyDowncastError::new(
Some(value.get_type().name().as_ref()),
Some(T::NAME),
))
}
}
}
Expand All @@ -396,7 +402,10 @@ where
if T::is_instance(value) {
Ok(Self::try_from_unchecked(value))
} else {
Err(PyDowncastError)
Err(PyDowncastError::new(
Some(value.get_type().name().as_ref()),
Some(T::NAME),
))
}
}
}
Expand All @@ -406,7 +415,10 @@ where
if T::is_exact_instance(value) {
Ok(Self::try_from_unchecked(value))
} else {
Err(PyDowncastError)
Err(PyDowncastError::new(
Some(value.get_type().name().as_ref()),
Some(T::NAME),
))
}
}
}
Expand Down
43 changes: 38 additions & 5 deletions src/err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::gil::ensure_gil;
use crate::panic::PanicException;
use crate::type_object::PyTypeObject;
use crate::types::PyType;
use crate::{exceptions, ffi};
use crate::{exceptions, ffi, PyTypeInfo};
use crate::{
AsPyPointer, FromPy, FromPyPointer, IntoPy, IntoPyPointer, Py, PyAny, PyNativeType, PyObject,
Python, ToBorrowedObject, ToPyObject,
Expand Down Expand Up @@ -56,7 +56,29 @@ pub struct PyErr {
pub type PyResult<T> = Result<T, PyErr>;

/// Marker type that indicates an error while downcasting
pub struct PyDowncastError;
pub struct PyDowncastError {
from: Option<String>,
to: Option<String>,
}

impl PyDowncastError {
pub fn new(from: Option<&str>, to: Option<&str>) -> Self {
PyDowncastError {
from: from.map(Into::into),
to: to.map(Into::into),
}
}

pub fn from_types<T1, T2>() -> Self
where
T1: PyTypeInfo,
T2: PyTypeInfo,
{
let from = Some(T1::NAME.into());
let to = Some(T2::NAME.into());
PyDowncastError { from, to }
}
}

/// Helper conversion trait that allows to use custom arguments for exception constructor.
pub trait PyErrArguments {
Expand Down Expand Up @@ -450,14 +472,25 @@ impl<'a> IntoPy<PyObject> for &'a PyErr {

/// Convert `PyDowncastError` to Python `TypeError`.
impl std::convert::From<PyDowncastError> for PyErr {
fn from(_err: PyDowncastError) -> PyErr {
exceptions::TypeError.into()
fn from(err: PyDowncastError) -> PyErr {
match (err.from, err.to) {
(Some(from), Some(to)) => {
exceptions::TypeError::py_err(format!("Failed to convert from {} to {}", from, to))
}
(Some(from), None) => {
exceptions::TypeError::py_err(format!("Failed to convert from {}", from))
}
(None, Some(to)) => {
exceptions::TypeError::py_err(format!("Failed to convert to {}", to))
}
(None, None) => exceptions::TypeError::py_err("Failed to convert"),
}
}
}

impl<'p> std::fmt::Debug for PyDowncastError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f.write_str("PyDowncastError")
write!(f, "PyDowncastError from {:?} to {:?}", self.from, self.to)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/types/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<'p> PyIterator<'p> {
// Returns NULL if an object cannot be iterated.
if ptr.is_null() {
PyErr::fetch(py);
return Err(PyDowncastError);
return Err(PyDowncastError::new(None, Some("Iterator")));
}

if ffi::PyIter_Check(ptr) != 0 {
Expand All @@ -50,7 +50,7 @@ impl<'p> PyIterator<'p> {
// GILPool does not take ownership of the reference.
Ok(PyIterator(py.from_borrowed_ptr(ptr)))
} else {
Err(PyDowncastError)
Err(PyDowncastError::new(None, Some("Iterator")))
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/types/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,10 @@ impl<'v> PyTryFrom<'v> for PySequence {
if ffi::PySequence_Check(value.as_ptr()) != 0 {
Ok(<PySequence as PyTryFrom>::try_from_unchecked(value))
} else {
Err(PyDowncastError)
Err(PyDowncastError::new(
Some(value.get_type().name().as_ref()),
Some("Sequence"),
))
}
}
}
Expand Down

0 comments on commit 6bda2f9

Please sign in to comment.