-
Notifications
You must be signed in to change notification settings - Fork 124
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
hookwrappers can't modify the in-flight exception without skipping later hookwrapper teardowns #244
Comments
We should definitely fix this if it's still present in Pytest 5! |
moved this to pluggy as its clearly a pluggy issue (imho), we might need to have a tracking one in pytest for pinning later on |
Hi, I have encountered the same problem, despite the fact that raising from teardown never seemed to be a good idea for me :) What is the desired solution for this?
What do you think? Best regards, |
I think I have a pure pluggy example (no pytest involved) demonstrating that after exception tear down functions are called through garbage collector instead of hook runner from __future__ import print_function
import pluggy
import sys
hookspec = pluggy.HookspecMarker('pluxample')
hookimpl = pluggy.HookimplMarker('pluxample')
class PluxampleSpec(object):
@hookspec
def call():
pass
class OuterHookWrapper:
@hookimpl(hookwrapper=True)
def call(self):
print('OuterHookWrapper prepare')
try:
yield
finally:
print('OuterHookWrapper **cleanup**')
class HookWithFailingCleanup:
@hookimpl(hookwrapper=True)
def call(self):
print('HookWithFailingCleanup prepare')
yield
print('HookWithFailingCleanup throw')
raise RuntimeError('HookWithFailingCleanup Failed!')
class FunHook:
@hookimpl
def call(self):
print('FunHook')
return 10
def main(early):
print('main begin')
pm = pluggy.PluginManager('pluxample')
pm.add_hookspecs(PluxampleSpec)
pm.register(FunHook())
pm.register(HookWithFailingCleanup())
pm.register(OuterHookWrapper())
exit = 1
try:
result = pm.hook.call()
print('main result %r' % (result,))
exit = 0
except Exception as ex:
print('main exception **handler**: %r' % (ex,))
# It is important where exit is called
if early:
print('exit failure')
sys.exit(exit)
print('exit %s' % ('success' if exit == 0 else 'failure',))
sys.exit(exit)
if __name__ == '__main__':
if len(sys.argv) == 2:
if sys.argv[1] == 'early':
main(early=True)
elif sys.argv[1] == 'late':
main(early=False)
else:
print('Usage:\n %s { early | late }' % sys.argv[0]) Expectation is that
with
I suspect is that the problem cause is around Line 205 in 30a2f7c
where only StopIteration exception is caught
|
PR #389 provides a way to handle this (provided new-style wrappers are used) |
Hookwrappers do not currently provide a public, proper way to override or force an exception. Raising directly from the hookwrapper causes further wrappers to be skipped, but this is not something we want to change at this point, for fear of breaking things, and because we are adding a replacement. See pytest-dev#244 on this issue.
Hookwrappers do not currently provide a public, proper way to override or force an exception. Raising directly from the hookwrapper causes further wrappers to be skipped, but this is not something we want to change at this point, for fear of breaking things, and because we are adding a replacement. See pytest-dev#244 on this issue.
Suppose you want to write a pytest plugin that transforms some exceptions in a test into different exceptions. As I understand it, this can be done with a hookwrapper, something like this:
And this works great, as long as you only have one such wrapper. But if you have two, then raising an exception in the "inner" one will skip the teardown portion of the "outer" one. A complete example:
Notably missing from the "Captured stdout call":
after 1
.I encountered this when trying to use
pytest_runtest_call
as the wrapper;_pytest.logging
uses apytest_runtest_call
wrapper to add the captured logging to the test report, so logging would mysteriously fail to be captured.A workaround is possible by assigning to
result._excinfo
instead of re-raising, but it would be nice to have a supported mechanism for this so as not to need to reach into internals.This issue was seen with pytest 4.3.1 and pluggy 0.9.0 on Linux. I'm not immediately able to test with a newer version, but the relevant code (pluggy.callers._multicall) doesn't seem to have changed recently.
The text was updated successfully, but these errors were encountered: