-
Notifications
You must be signed in to change notification settings - Fork 66
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
Fixtures not torn down after timeout #134
Comments
I continued digging into my issue. def timeout_timer(item, timeout):
....
try:
....
except Exception:
traceback.print_exc()
finally:
sys.stdout.flush()
sys.stderr.flush()
os._exit(1) Would it be possible to add a |
So with the For the |
Thanks for the answer! So if I understand (for the the def timeout_timer(item, timeout):
....
try:
....
finally:
item.handler()
sys.stdout.flush()
sys.stderr.flush()
os._exit(1) But I could also not modify at all I'm kind of new with pytest hooks so I try to get a better understanding of it all 🙂 However I admit that your solution of adding a layer around As for the |
On Wed 06 Jul 2022 at 02:41 -0700, ClementMabileau wrote:
So if I understand (for the the `thread` method), it would be
technically feasible to insert a call to a custom function in
`timeout_timer(item, timeout)` but it is just not the "spirit" of the
method because it can alter its reliability (which I totally
understand)?
Some random code you could execute, but it executes in a different
thread so something like fixture teardown would not work unless the
fixture is designed in a way that allows it to be done from a different
thread so that requires intricate interaction.
But just to learn a bit:
If I'd want to do it anyway I could fork `pytest-timeout` and insert this call, for example to `handler` (which would be a `Callable`) passed as parameter of ***@***.***(X, method="thread", func_only=True, handler=my_callable)`? And after some modification to `Settings` and `pytest_timeout_set_timer(item, settings)` do:
```py
def timeout_timer(item, timeout):
....
try:
....
finally:
item.handler()
sys.stdout.flush()
sys.stderr.flush()
os._exit(1)
```
**But** I could also not modify at all `pytest-timeout` and simply
reimplement the `pytest_timeout_set_timer` hook (I couldn't pass
`my_callable` in the marker but I could execute some code anyway), is
that right ?
Yes you can use the hooks to achieve this, if you look at the existing
hook you can basically see how to do this:
- Start a timer thread with the code to run in case of timeout.
- Attach the cancel method to the item, or implement the
`pytest_timeout_cancel_timer hook`.
Problem is that the `timeout_timer()` logic is not public currently, I
guess this could be made more reusable for custom implementations like
you want to have.
As for the `signal` method I found out that I can't use it because I
also use `xmlrpc.client` to communicate with my other process through
a socket and it seems that underlying (maybe in `httplib` or `socket`)
it uses SIGALRM too, making the timeout to never be triggered. But
that's actually another topic 😄
Oh, that's actually kind of interesting especially if that's from the
stdlib.
|
Yes I understand this thanks a lot for the explanation !
That's actually the issue I encountered trying to implement
My mistake! SIGALRM was not use in these libs I was just using it elsewhere and forget it... So I guess in the end the better solution is by far using the |
I'm facing a related case: I'm testing a lot of numba-compiled CUDA kernels. For test speed, I cache them (bytecode is written to pycache). Every once in a while, one hangs, and "signal" method doesn't work in this case. "Thread" method does interrupt, but next time I run the cached bytecode is often corrupt and segfaults. I can of course delete all the caches, but then slow testing runs 5x slower. I would like to be able to clear the caches for just kernels that have been compiled in current session when I interrupt with "thread" method. Can I do this using a hook? |
@shaunc So, instead of trying to recover (or tear down) from a However if you're absolutely sure that you don't want to do that then you could probably do it with a hook as suggested by flub but I don't if you'll have access to session's informaztion to clear the right cached info, you could also modify the Hope that's helping you 😉 |
@shaunc Thread method means no cleanup by the pytest process itself, nothing that can be done about that. What @ctmbl suggests to figure out why signal method doesn't work is one option. Another way it so add cleanup in a separate process wrapping pytest. Or yet another option for your case is to write some kind of lock file in the test setup (i.e. a fixture) and remove it in the teardown (i.e. fixture finaliser). That way on the next run when the fixure finds the lockfile because the test timed out and the finaliser was not run, you it can remove the possibly corrupt cache. |
All I really want is to know what has been executed so I can clear the cached info. The finalizer method sounds promising - thanks! |
Understanding
As I understand the README, and the behavior I'm noticing about
pytest-timeout
, fixtures teardown may not be executed if timeout is triggered. Even if usingfunc_only=True
fixtures aren't torn down, I must confess I was expecting that, using this parameter, timeout would apply to the test only, but that fixtures would be torn down as expected when using pytest.Problem
The test suite I'm running, starts a process using
subprocess.Popen
and not tearing down that fixture is thus creating a remaining zombie process which makes it mandatory to being executed.Hope and Questions
I also must admit that I'm really not familiar with the internal principle of
signal
ofthread
methods. Even if I think I understand their differences, I can't really see their "natural" limitations.That's why I'm making this Issue: Would there be a way to implement
pytest-timeout
that would allow to execute the tearing down of (at least) one fixture when using@pytest.mark.timeout(X, func_only=True)?
Would it depends on the used
method
?Is the only solution would be to "force" the execution of the fixture (for example using a custom hook like proposing in the README section
Extending pytest-timeout with plugings
)? Is it even possible to force a fixture to be executed using pytest (it doesn't seem to be really the pytest way to do things...)?Not satisfying solution so far
So far I tried to go with the whole "forcing the tearing down" thing and I found pytest-dev/pytest#1738 this solution but that doesn't seems really satisfying so I keep looking !
I would really like any help, on my understanding of this plugin as well as on any solution you could think of !
Thanks a lot !
The text was updated successfully, but these errors were encountered: