Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass detailed error message to python when parsing an argument fails #2178

Merged
merged 3 commits into from
Feb 22, 2022
Merged

Pass detailed error message to python when parsing an argument fails #2178

merged 3 commits into from
Feb 22, 2022

Conversation

ricohageman
Copy link
Contributor

@ricohageman ricohageman commented Feb 21, 2022

This pull requests includes some changes related to issue #2177

Copy link
Member

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for looking into this; sorry I never found a chance to replying further to our conversation on Gitter.

You're right that this is definitely a bug. I wonder though, instead of flattening all the causes into a single exception, is it nicer to just preserve the existing cause, if any? See comment below...

Comment on lines 106 to 118
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))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, rather than flattening all the causes, should we be preserving the cause of the original error instead, like this:

Suggested change
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))
let remapped_error = PyTypeError::new_err(format!("argument '{}': {}", arg_name, error.value(py)));
remapped_error.set_cause(py, error.cause(py));
remapped_error

Then the error seen from Python might be more like this:

TypeError: 'str' object cannot be interpreted as an integer

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/david/Dev/pyo3-scratch/test.py", line 19, in <module>
    pyo3_scratch.function_to_call_with_value_class(ValueClass("unparsable string"))
TypeError: argument 'value': failed to extract field ValueClass.value

I think preserving the cause tree like this is probably more correct. For example, the argument conversion code could run any old Python code (not just our PyO3 code) which generates some exception with its own separate cause. I think PyO3 flattening those causes into a single error message is a mistake; it might lose valuable debugging information.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're totally right with this remark. Also, I didn't completely liked the flattening so this is a better approach while still preserving all the relevant information.

In addition, I tried to comply to rustfmt and clippy where relevant to this pull request. However, they were also marking parts that were untouched (some strict comparisons between floating points). Let's see if the workflows succeed.

Copy link
Member

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, many thanks!

@davidhewitt davidhewitt merged commit e354dbe into PyO3:main Feb 22, 2022
@ricohageman ricohageman deleted the improved_error_message branch February 22, 2022 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants