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 finalization is delayed #687

Closed
pytestbot opened this Issue Feb 23, 2015 · 11 comments

Comments

Projects
None yet
5 participants
@pytestbot

pytestbot commented Feb 23, 2015

Originally reported by: Thomas Tanner (BitBucket: ttanner, GitHub: ttanner)


According to the documentation http://pytest.org/latest/fixture.html#fixture-finalization-executing-teardown-code
"The fin function will execute when the last test using the fixture in the module has finished execution."

Either the documentation is wrong, misleading or there is a bug in pytest.

Example:

#!python

from pytest import fixture

@fixture(scope='session')
def fix1(request):
    print 'fix1'
    def fin(): print '-fix1'
    request.addfinalizer(fin)
    return 'fix1'

@fixture(scope='session')
def fix2(request):
    print 'fix2'
    def fin(): print '-fix2'
    request.addfinalizer(fin)
    return 'fix2'

def test_f1(fix1):
    print 'f1',fix1

def test_f2(fix2):
    print 'f2',fix2

results in

#!

test.py::test_f1 fix1
f1 fix1
PASSED
test.py::test_f2 fix2
f2 fix2
PASSED-fix2
-fix1

as you can see, fin of fix1 is called not immediately after the last test depending on it (f1), but after all other tests (f2) and fix2's fin.

Just in case pytest won't guarantee finalization of a fixture after all its dependencies have been executed: what would be the best way to ensure mutually-exclusive (session) fixtures are finalized before the next one is setup?


@pytestbot pytestbot added the type: bug label Jun 15, 2015

@RonnyPfannschmidt

This comment has been minimized.

Member

RonnyPfannschmidt commented Jul 25, 2015

@ttanner that session scoped fixtures stay around mostly is kinda intentional, there is no direct concept of mutally exclusive fixtres yet

while parametrization of certain fixtures can solve it, its not yet possible in a general way spanning multiple fixtures

@oscarh

This comment has been minimized.

Contributor

oscarh commented Nov 9, 2016

Hi,

Old issue here, but I see the same behaviour today with module soped fixtures. Actually, the documentation referenced to above uses the scope='module' as examples it claims that "The fin function will execute when the last test using the fixture in the module has finished execution."

The yield type fixtures has similar documentation. I't would be of great use if I could get my module scoped fixtures to be finalized as soon as they aren't needed any more.

from time import sleep
from pytest import fixture


@fixture(scope='module')
def fixture1():
    print('Setup of fixture1')
    yield 'fixture1'
    print('Teardown of fixture1')


@fixture(scope='module')
def fixture2():
    print('Setup of fixture2')
    yield 'fixture2'
    print('Teardown of fixture2')


def test_1(fixture1):
    print('Running test with {}'.format(fixture1))
    sleep(.25)


def test_2(fixture1, fixture2):
    print('Running test with {} and {}'.format(fixture1, fixture2))
    sleep(0.25)


def test_3(fixture2):
    print('Running test with {}'.format(fixture2))
    sleep(0.25)
$ py.test -s -v --setup-show
====================================================== test session starts =======================================================

platform linux -- Python 3.4.3, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- /home/vagrant/tmp/fixture_lifetime/python-3-pytest-latest/bin/python3
cachedir: .cache
rootdir: /home/vagrant/tmp/fixture_lifetime/test, inifile: 
collected 3 items 

test_fixture_lifetime.py::test_1 Setup of fixture1

  SETUP    M fixture1
        test_fixture_lifetime.py::test_1 (fixtures used: fixture1)Running test with fixture1
PASSED
test_fixture_lifetime.py::test_2 Setup of fixture2

  SETUP    M fixture2
        test_fixture_lifetime.py::test_2 (fixtures used: fixture1, fixture2)Running test with fixture1 and fixture2
PASSED
test_fixture_lifetime.py::test_3 
        test_fixture_lifetime.py::test_3 (fixtures used: fixture2)Running test with fixture2
PASSEDTeardown of fixture2

  TEARDOWN M fixture2Teardown of fixture1

  TEARDOWN M fixture1

==================================================== 3 passed in 0.77 seconds ====================================================
@nicoddemus

This comment has been minimized.

Member

nicoddemus commented Nov 9, 2016

I agree we should fix this.

I thought the "setupstate" mechanism (which I don't know intimately) was suppose to take care of that. @RonnyPfannschmidt, do you have a comment about that? Is it a bug or a feature not implemented?

@RonnyPfannschmidt

This comment has been minimized.

Member

RonnyPfannschmidt commented Nov 9, 2016

@nicoddemus setupstate cannot fix this, since it has no idea about mutual exclusion

in fact, the current fixture mechanism is completely under-powered for such cases

@nicoddemus

This comment has been minimized.

Member

nicoddemus commented Nov 9, 2016

@RonnyPfannschmidt oh my bad, I completely misunderstood the issue! 😅

AFAIU the main problem with implementing this is that the run-test protocol (which handles fixture setup/run/teardown) currently only knows about the "next" test item. This means that when current item's module and the next-item's module are different the mechanism knows that it can safely tear down module-scoped fixtures at that point.

To change the mechanism so that module-scoped fixtures would be tore down when the last test that uses it in a module finishes, it would have to look at all items ahead of current item in the same module to be able to determine if a module-scoped fixture could be torn down at that point.

As this requires a non-trivial change in the run-test protocol, I would be happy to at least update the documentation for now to avoid confusion.

@RonnyPfannschmidt what do you think?

@oscarh

This comment has been minimized.

Contributor

oscarh commented Nov 9, 2016

To me its not so much about mutual exclusion, more about getting the
finalizers to run when the fixture goes out of scope. On the other hand, I
would use it for a kind of mutual exclusion.

Ronny Pfannschmidt notifications@github.com schrieb am Mi., 9. Nov. 2016,
15:42:

@nicoddemus https://github.com/nicoddemus setupstate cannot fix this,
since it has no idea about mutual exclusion

in fact, the current fixture mechanism is completely under-powered for
such cases


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#687 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEzpA-MRH_4Un6AdfC9oi3Sbryg_ssYks5q8drHgaJpZM4Ffp0K
.

@RonnyPfannschmidt

This comment has been minimized.

Member

RonnyPfannschmidt commented Nov 9, 2016

@oscarh one of the problems is, that session scope cannot be "left" for example, when iterating over mutually exclusive parameters tear-down is done, however distinct fixtures are not "mutually exclusive"

@oscarh

This comment has been minimized.

Contributor

oscarh commented Nov 10, 2016

@nicoddemus A documentation update would be good for now, as I don't seem to be the only interpretting the documentation as if this is supported.

Then I guess that this is more of a feature request than a bug. Would such a feature request be considered?

@nicoddemus

This comment has been minimized.

Member

nicoddemus commented Nov 11, 2016

@nicoddemus A documentation update would be good for now, as I don't seem to be the only interpretting the documentation as if this is supported.

If you would like to contribute a PR, we would really appreciate it. 😅

Then I guess that this is more of a feature request than a bug. Would such a feature request be considered?

Sure, but TBH I don't think that would happen soon, we have other priorities right now.

@DuncanBetts

This comment has been minimized.

Contributor

DuncanBetts commented Nov 26, 2016

With regards to changing the documentation, in the interests of it describing pytest's behaviour, I could change it to:

The fin function will execute when the last test has finished execution.

This is my understanding of what currently occurs.

@nicoddemus

This comment has been minimized.

Member

nicoddemus commented Nov 27, 2016

@DuncanBetts, Yes, when the last test in the module finishes execution.

This was referenced Mar 5, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment