-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
fixture finalizer dependency incorrect when using autouse or getfuncargvalue #1489
Comments
Hi @amosonn, Thanks for taking the time to write down this report. (I edited your post to add syntax highlight to your examples to make them easier to read, hope you don't mind). |
I thought I could use autouse fixtures to do some setup and teardown, but since the teardown part is not garanteed to come after the teardown of non-autouse fixtures, it's not straightforward. Here is a more compact and modern test case that shows the problem (the scope could also be set to package or session): import pytest
@pytest.fixture(scope='module', autouse=True)
def fixture_autouse():
print('\nSETUP FIXTURE AUTOUSE')
yield
print('\nTEARDOWN FIXTURE AUTOUSE')
@pytest.fixture(scope='module')
def fixture_test():
print('\nSETUP FIXTURE TEST')
yield
print('\nTEARDOWN FIXTURE TEST')
def test_1(fixture_test):
pass
def test_2():
pass running the test gives:
which shows that the autouse fixture teardown does not come after that of the non-autouse fixture. Since the autouse fixture setup comes first wrt non-autouse setups, it is expected that their teardowns come last. |
+1 ran into this bug. This behavior is different from the documented expected behavior that finalizers will run in reverse order to the order the fixtures were initialized. From https://docs.pytest.org/en/6.2.x/fixture.html#yield-fixtures-recommended :
Perhaps adding a caveat to the documentation would be good until this is fixed? |
Started looking into this, and it's actually not import pytest
@pytest.fixture(scope='module')
def fixture_1():
print('\nSETUP FIXTURE 1')
yield
print('\nTEARDOWN FIXTURE 1')
@pytest.fixture(scope='module')
def fixture_2():
print('\nSETUP FIXTURE 2')
yield
print('\nTEARDOWN FIXTURE 2')
def test_1(fixture_1, fixture_2):
pass
def test_2(fixture_1):
pass
if the test order is reversed, or [<bound method Node.teardown of <Module mytest2.py>>,
functools.partial(<bound method FixtureDef.finish of <FixtureDef argname='fixture_1' scope='module' baseid='testing/python/mytest2.py'>>, request=<SubRequest 'fixture_1' for <Function test_1>>),
functools.partial(<bound method FixtureDef.finish of <FixtureDef argname='fixture_2' scope='module' baseid='testing/python/mytest2.py'>>, request=<SubRequest 'fixture_2' for <Function test_1>>),
functools.partial(<bound method FixtureDef.finish of <FixtureDef argname='fixture_1' scope='module' baseid='testing/python/mytest2.py'>>, request=<SubRequest 'fixture_1' for <Function test_2>>)] it processes it from the end, tearing down My current best-guess on how to fix it is to add some logic to runner.py:SetupState.addfinalizer so we only add a finalizer for a given fixture once. |
Calling fixture finalizers in the correct order works by dependent fixtures registering their finalizer in their dependency (see python.FixtureDef.execute+10).
However, this only happens for fixtures explicitly requested in args, not for autouse or getfuncargvalue fixtures.
This code:
gives with
py.test --capture=no test.py
:as does this code:
The text was updated successfully, but these errors were encountered: