Pass detailed error message to python when parsing an argument fails

This commit is contained in:
Rico Hageman 2022-02-21 23:01:45 +01:00
parent 01788b7220
commit 597e3e17a9
2 changed files with 56 additions and 10 deletions

View File

@ -101,9 +101,21 @@ pub fn from_py_with_with_default<'py, T>(
/// single string.)
#[doc(hidden)]
#[cold]
pub fn argument_extraction_error(py: Python, arg_name: &str, error: PyErr) -> PyErr {
pub fn argument_extraction_error(py: Python, arg_name: &str, mut error: PyErr) -> PyErr {
if error.get_type(py) == PyTypeError::type_object(py) {
PyTypeError::new_err(format!("argument '{}': {}", arg_name, error.value(py)))
let mut reason = error
.value(py)
.str()
.unwrap_or_else(|_| PyString::new(py, ""))
.to_string();
while let Some(cause) = error.cause(py) {
reason.push_str(":\n\t");
reason.push_str(&cause.to_string());
error = cause
}
PyTypeError::new_err(format!("argument '{}': {}", arg_name, reason))
} else {
error
}

View File

@ -165,11 +165,21 @@ fn test_function_with_custom_conversion_error() {
);
}
#[derive(Debug, FromPyObject)]
struct ValueClass {
value: usize,
}
#[pyfunction]
fn conversion_error(str_arg: &str, int_arg: i64, tuple_arg: (&str, f64), option_arg: Option<i64>) {
fn conversion_error(str_arg: &str,
int_arg: i64,
tuple_arg: (&str, f64),
option_arg: Option<i64>,
struct_arg: Option<ValueClass>
) {
println!(
"{:?} {:?} {:?} {:?}",
str_arg, int_arg, tuple_arg, option_arg
"{:?} {:?} {:?} {:?} {:?}",
str_arg, int_arg, tuple_arg, option_arg, struct_arg
);
}
@ -182,38 +192,62 @@ fn test_conversion_error() {
py_expect_exception!(
py,
conversion_error,
"conversion_error(None, None, None, None)",
"conversion_error(None, None, None, None, None)",
PyTypeError,
"argument 'str_arg': 'NoneType' object cannot be converted to 'PyString'"
);
py_expect_exception!(
py,
conversion_error,
"conversion_error(100, None, None, None)",
"conversion_error(100, None, None, None, None)",
PyTypeError,
"argument 'str_arg': 'int' object cannot be converted to 'PyString'"
);
py_expect_exception!(
py,
conversion_error,
"conversion_error('string1', 'string2', None, None)",
"conversion_error('string1', 'string2', None, None, None)",
PyTypeError,
"argument 'int_arg': 'str' object cannot be interpreted as an integer"
);
py_expect_exception!(
py,
conversion_error,
"conversion_error('string1', -100, 'string2', None)",
"conversion_error('string1', -100, 'string2', None, None)",
PyTypeError,
"argument 'tuple_arg': 'str' object cannot be converted to 'PyTuple'"
);
py_expect_exception!(
py,
conversion_error,
"conversion_error('string1', -100, ('string2', 10.), 'string3')",
"conversion_error('string1', -100, ('string2', 10.), 'string3', None)",
PyTypeError,
"argument 'option_arg': 'str' object cannot be interpreted as an integer"
);
py_expect_exception!(
py,
conversion_error,
"
class ValueClass:
def __init__(self, value):
self.value = value
conversion_error('string1', -100, ('string2', 10.), None, ValueClass(\"no_expected_type\"))",
PyTypeError,
"argument 'struct_arg': failed to extract field ValueClass.value:\n\tTypeError: 'str' \
object cannot be interpreted as an integer"
);
py_expect_exception!(
py,
conversion_error,
"
class ValueClass:
def __init__(self, value):
self.value = value
conversion_error('string1', -100, ('string2', 10.), None, ValueClass(-5))",
PyTypeError,
"argument 'struct_arg': failed to extract field ValueClass.value:\n\tOverflowError: can't \
convert negative int to unsigned"
);
}
#[test]