Closed Redoubts closed 7 months ago
Thanks for the bug report and reproduction.
This regressed with commit 63b7e908b4b22c30d86cd2cff240b3b7aa6da596 - pluggy 1.1.0.
In this commit I made an optimization such that the list of hook implementations of a hook (_hookimpls
) is no longer copied on every call to the hook. But I neglected to think about the case when _hookimpls
is modified by calling the hook itself. This is what happens in your reproduction:
pytest_configure
hookplugin2.pytest_configure
calls pm.register(Plugin3())
Plugin3
implements pytest_configure
Why is plugin3 called twice? First time, because pytest_configure
is an historic hook and so it's called by the register()
.
Second time, because its registration modifies _hookimpls
while it is being iterated and it ends up being included in the call.
Why is the conftest getting skipped? Because it's something that can happen when invalidating an iterator. Example:
l = [0, 1, 2]
for x in reversed(l):
print(x)
if x == 1:
l.insert(0, -1)
This prints 2, 1, -1
and 0
is skipped.
BTW, if I modify pluggy to avoid the reverse
, then the conftest isn't skipped. But this is incidental, it could have just as well caused an infinite loop (try removing reversed
from the snippet above).
First solution is to bring back the copy.
Second solution is to disallow doing this in one way or another. However pytest explicitly documents this patten so this may be out of the question.
Third solution is to somehow make this work without the copy.
ty for addressing!
Wanted to cross post https://github.com/pytest-dev/pytest/issues/11365 here, in case it might be on the pluggy side: