Skip to content

Session fixture is being activated second time #8328

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

Closed
dina809 opened this issue Feb 8, 2021 · 21 comments
Closed

Session fixture is being activated second time #8328

dina809 opened this issue Feb 8, 2021 · 21 comments
Assignees
Labels
status: help wanted developers would like help from experts on this topic topic: fixtures anything involving fixtures directly or indirectly type: question general question, might be closed after 2 weeks of inactivity

Comments

@dina809
Copy link

dina809 commented Feb 8, 2021

Hi

we have a session fixture that receives parameters.
when running 2 tests using this fixture, it is being activated also for the second test.

how can we make it to run 1 time only (despite the fact it has parameters)?

using pytest 5.4.2 (python 3.7.4)

@RonnyPfannschmidt RonnyPfannschmidt added the status: needs information reporter needs to provide more information; can be closed after 2 or more weeks of inactivity label Feb 8, 2021
@RonnyPfannschmidt
Copy link
Member

your setup is not clear, in general when it gets parameters, it gets enabled for every parameter

if you need a intermediate fixture, its necessary to have a fixture without parameters to do the heavy lifting and a parameter using fixture to do the little bits

@RonnyPfannschmidt RonnyPfannschmidt added the type: question general question, might be closed after 2 weeks of inactivity label Feb 8, 2021
@Zac-HD Zac-HD added the topic: fixtures anything involving fixtures directly or indirectly label Feb 9, 2021
@Formartha
Copy link

@RonnyPfannschmidt - So you are saying that fixutre in session scope shouldn't get parameters? and if it does, than it becomes a function scope fixture?

Thanks.

@RonnyPfannschmidt
Copy link
Member

no, im saying at the session scope the fixture is set up for each parameter,, si its activated once for each parameter

parameters also exist at session scope and dont force function scope

@dina809
Copy link
Author

dina809 commented Feb 9, 2021

@RonnyPfannschmidt - thanks for the help, but still need to clarify something.
session scope fixtures supposed to be executed once per session (fixture without parameters)
if i have session fixture with parameters then it will be activated per each parameter. is it correct to assume that if the fixture is called twice (from 2 diff functions) with SAME parameter it will be activated only one time?

i tried this example and the fixture activated each call. so not sure what is the difference between function scope fixture and session scope fixture with parameters

here is the example:

@pytest.fixture(scope="session")
def prepare_dict(request):
    """ dict for example """
    print("parameter is {}".format(request.param["name"]))


@pytest.mark.parametrize('prepare_dict', [{"name": "dina"}], indirect=True)
def test_example(prepare_dict):
    print("Test1 done\n")

@pytest.mark.parametrize('prepare_dict', [{"name": "mor"}], indirect=True)
def test_example_2(prepare_dict):
    print("Test2 done\n")

@pytest.mark.parametrize('prepare_dict', [{"name": "dina"}], indirect=True)
def test_example_3(prepare_dict):
    print("Test3 done\n")

output

parameter is dina
Test1 done
parameter is mor
Test2 done
parameter is dina
Test3 done

@RonnyPfannschmidt
Copy link
Member

Oh, you are hitting a bug there, the Parametrize turns the scope to function

Please set scope to session there as well, i believe more recent pytest handles this Better

@dina809
Copy link
Author

dina809 commented Feb 9, 2021

@RonnyPfannschmidt - I'v upgraded pytest to 6.2.2 and added scope parameter to the parameterize so it is looking like this:

@pytest.fixture(scope="session")
def prepare_dict(request):
    """ dict for example """
    print("parameter is {}".format(request.param["name"]))


@pytest.mark.parametrize('prepare_dict', [{"name": "dina"}], indirect=True, scope="session")
def test_example(prepare_dict):
    print("Test1 done\n")

@pytest.mark.parametrize('prepare_dict', [{"name": "mor"}], indirect=True, scope="session")
def test_example_2(prepare_dict):
    print("Test2 done\n")


@pytest.mark.parametrize('prepare_dict', [{"name": "dina"}], indirect=True, scope="session")
def test_example_3(prepare_dict):
    print("Test3 done\n")

but still it is activated 3 times..
using python 3.7.4

@dina809
Copy link
Author

dina809 commented Feb 14, 2021

@RonnyPfannschmidt - Hi Ronny, any updates on this? should i convert this issue to a bug?
thanks.

@RonnyPfannschmidt
Copy link
Member

thanks for the ping, this went under, i'll test this today

@dina809
Copy link
Author

dina809 commented Feb 14, 2021

@RonnyPfannschmidt - ok, thanks! waiting for an update :)

@RonnyPfannschmidt
Copy link
Member

ok, i understood the issue

i adopted the test script a bit to experiment with different parameter passing

import pytest


@pytest.fixture(scope="session")
def prepare_dict(request):
    """ dict for example """
    print("\nparameter is {}".format(request.param))

dina = {"name": "dina"}
mor = {"name": "mor"}

def deco(name):
    return pytest.mark.parametrize('prepare_dict', [name["name"]], indirect=True, scope="session", ids=lambda x:x["name"] if isinstance(x, dict) else x)


@deco(dina)
def test_example(prepare_dict):
    print("Test1 done\n")

@deco(mor)
def test_example_2(prepare_dict):
    print("Test2 done\n")


@deco(dina)
def test_example_3(prepare_dict):
    print("Test3 done\n")

as far as i gathered pytest does not consider them the same identity in any case and thus does not reorder tests to avoid setup/teardown

this could also be a edge case bug in the test reordering

@Formartha
Copy link

Thanks @RonnyPfannschmidt,
Both me and Dina are trying to understand what shall we do next? as in, how to workaround this issue? any ideas?
I'm thinking that all the fixtures are kept in memory, thus a singleton might help to determine if a fixture ran or not.

I'm not sure if there are other options (maybe register a attribute on request object might help), but we'll appreciate your guidence.

Thanks,
Mor

@BorjaEst
Copy link

BorjaEst commented Feb 17, 2021

Same issue here I think:

See this example.

import pytest

@pytest.fixture(scope="session")
def param1(request):
    print("session param1 is {}".format(request.param))

@pytest.fixture(scope="session")
def param2(request):
    print("session param2 is {}".format(request.param))

@pytest.mark.parametrize('param1', [1, 2], indirect=True)
@pytest.mark.parametrize('param2', [1, 2], indirect=True)
def test_example(param1, param2):
    print("Test done\n")

Provides the following output.

$ pytest -s
========================= test session starts =========================
platform linux -- Python 3.8.3, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: /home/.../Temp/test
collected 4 items

test_example.py session param1 is 1
session param2 is 1    # <-- FIRST execution of param2 with 1
Test done

.session param2 is 2
Test done

.session param1 is 2
Test done

.session param2 is 1   # <-- SECOND execution of param2 with 1
Test done

.

========================== 4 passed in 0.01s ==========================

As I defined the fixture as "session" I do not expect to have the fixture running a second time with the same parameter...

@RonnyPfannschmidt
Copy link
Member

Different issue, fixture variants with different parameters currently cannot coexist, so multiple setups for one have to happen

@dina809
Copy link
Author

dina809 commented Feb 23, 2021

@RonnyPfannschmidt - Hi Ronny, so should we change this issue to a bug?

@RonnyPfannschmidt
Copy link
Member

That's not clear to me, I'd like to get the opinion of @nicoddemus

@dina809
Copy link
Author

dina809 commented Feb 28, 2021

Hi @nicoddemus
can you please assist?

Thanks.

@Zac-HD Zac-HD added status: help wanted developers would like help from experts on this topic and removed status: needs information reporter needs to provide more information; can be closed after 2 or more weeks of inactivity labels Mar 29, 2021
@nicoddemus
Copy link
Member

Sorry missed this.

as far as i gathered pytest does not consider them the same identity in any case and thus does not reorder tests to avoid setup/teardown

Did you remember why they are not considered the same identity in this case @RonnyPfannschmidt ?

@RonnyPfannschmidt
Copy link
Member

Unfortunately absolutely no idea

@nicoddemus
Copy link
Member

Reduced the example further:

import pytest

@pytest.fixture(scope="session")
def prepare(request):
    print("\nprepare setup with {!r}".format(request.param))

@pytest.mark.parametrize('prepare', ["dina"], indirect=True, scope="session")
def test_1(prepare):
    print("Test1 done\n")

@pytest.mark.parametrize('prepare', ["mor"], indirect=True, scope="session")
def test_2(prepare):
    print("Test2 done\n")

@pytest.mark.parametrize('prepare', ["dina"], indirect=True, scope="session")
def test_3(prepare):
    print("Test3 done\n")

I get this output:

λ pytest .tmp\test_fix_session.py -sq

prepare setup with 'dina'
Test1 done

.
prepare setup with 'mor'
Test2 done

.
prepare setup with 'dina'
Test3 done

.
3 passed in 0.02s

We would expect it to reorder the tests to [test_1, test_3, test_2] so the fixture would execute only twice, instead of 3 times as it is doing now, so definitely looks like a bug (unless I'm missing something).

If this looks right, I suggest we open a new issue with this final example/description, so one doesn't need to read the whole thread to get to the central point of the problem. What do you folks think?

@RonnyPfannschmidt
Copy link
Member

Go ahead

@nicoddemus
Copy link
Member

Done, closing this then in favor of #8914.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: help wanted developers would like help from experts on this topic topic: fixtures anything involving fixtures directly or indirectly type: question general question, might be closed after 2 weeks of inactivity
Projects
None yet
Development

No branches or pull requests

6 participants