-
-
Notifications
You must be signed in to change notification settings - Fork 364
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
Emit all errors in hooks #1806
Emit all errors in hooks #1806
Conversation
@jaraco only changelog shows up in the PR diff. Did you forget to commit something? |
…rrors using the multi-exception handling on Python 3. Fixes #1770.
f22c70d
to
0cf207c
Compare
This comment has been minimized.
This comment has been minimized.
I started this work in maint/17.x as it was requested to be included in the 17.x line, but I realized that the benefits only apply to Python 3 anyway, so I'm proposing merging this only to master. |
try: | ||
hook() | ||
except quiet_errors: | ||
cls.run_hooks(safe) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is hard to follow the control flow with this recursive iterator shrinking.
Any ideas on how to improve the readability here?
Also, I'd maybe create a partial out of this before the loop to better communicate the intent:
run_rest_of_safe_hooks = functools.partial(cls.run_hooks, safe) # Will not enter an infinite loop because it's bound to the same iterator and the loop in the previous invocation on stack consumes failed callbacks.
Is there any way to avoid recursion? This looks like a case for TCO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't think of a way without recursion to (a) catch an exception and (b) within the caught exception resume processing.
I agree it's hard to read; there's a lot going on in just a few lines, and it's incorporating a lot of rarely incorporated language features.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can work on refining the implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation will create an exception chain whether they'll be "causes" of one another which is not exactly true and may be misleading.
Other way to do this is to chain exceptions manually setting the previous ones as exc.__reason__
. The only difference would be a text message saying that the previous exception is the cause of the current one as opposed to saying that the previous exception happened while handling the current one.
Would this help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure these exceptions should be chained at all. They are all somewhat independent errors... their common thread is that they're part of the same hooks on the same request. That is, I don't think they're associated as "reason for exception X is exception Y", so __reason__
doesn't sound like the right approach.
Co-Authored-By: Sviatoslav Sydorenko <wk@sydorenko.org.ua>
Also, I should have said that I haven't tested this other than to run the cherrypy tests. I think this behavior deserves at least a demonstration that it achieves the desired behavior, even if it's not part of a unit test. |
I don't understand why the tests are failing. They pass for me locally. I think there's something configured in Travis to cause warnings as errors. I'm not sure where that is. |
Oh, maybe it was that tests were passing on the maint/17.x branch. I hadn't tested since merging with master. |
Right, so I see |
On further consideration, I see that the error was actually in the new code, with the check for |
I created this repro, which if run on master, produces:
whereas with the patch applied, the result includes both exceptions that occurred:
I believe this effectively demonstrates the effectiveness of the change. Because this relies on Python 3 to achieve its ends, I'm not going to attempt to back port this to 17.x, although I welcome others to try. |
What kind of change does this PR introduce?
What is the related issue number (starting with
#
)#1770
Other information:
This alternative implementation is based on the one I proposed in #1771. It uses recursion and the exception handling inherent to Python to emit multiple tracebacks. This works because
run_hooks
method receives an iterable, so whatever is inhooks
during the recursive call are the hooks that have not yet run.Checklist:
and description in grammatically correct, complete sentences