Skip to content
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

parametrize with scope breaks fixture dependencies #13248

Open
Anton3 opened this issue Feb 24, 2025 · 4 comments · May be fixed by #13249
Open

parametrize with scope breaks fixture dependencies #13248

Anton3 opened this issue Feb 24, 2025 · 4 comments · May be fixed by #13249

Comments

@Anton3
Copy link
Contributor

Anton3 commented Feb 24, 2025

Reproducer:

import pytest


@pytest.fixture(scope="session")
def my_fixture(request):
    return getattr(request, "param", None)


@pytest.fixture(scope="session")
def another_fixture(my_fixture):
    return my_fixture


@pytest.mark.parametrize("my_fixture", ["a"], indirect=True, scope="function")
def test_foo(another_fixture):
    pass

Produces the following error:

ScopeMismatch: You tried to access the function scoped fixture my_fixture with a session scoped request object. Requesting fixture stack:

def another_fixture(my_fixture):

Requested fixture:
my_fixture

parametrize with scope is sometimes important for test isolation:
#9287 (comment)

The bug is not reproduced consistently, it may be hidden if the fixture is already evaluated by a function-scoped fixture. For example:

import pytest


@pytest.fixture(scope="session")
def my_fixture(request):
    return getattr(request, "param", None)


@pytest.fixture(scope="session")
def another_fixture(my_fixture):
    return my_fixture


# autouse to make this fixture run first.
@pytest.fixture(scope="function", autouse=True)
def hack(my_fixture):
    pass


@pytest.mark.parametrize("my_fixture", ["a"], indirect=True, scope="function")
def test_foo(hack, another_fixture):
    pass

This does not return any errors, works as expected.

@RonnyPfannschmidt
Copy link
Member

both variants should error - the fixture is defined as session scope and the parameterize is not allowed to change that

@Anton3
Copy link
Contributor Author

Anton3 commented Feb 24, 2025

@RonnyPfannschmidt From the documentation of scope:

        :param scope:
            If specified it denotes the scope of the parameters.
            The scope is used for grouping tests by parameter instances.
            It will also override any fixture-function defined scope, allowing
            to set a dynamic scope using test context or configuration.

I've found it very useful to narrow the fixture's scope this way to prevent side effects of a test (or a group of tests) with specific parameter value from leaking into other tests.

It completely solves #9287, in particular.

@Anton3
Copy link
Contributor Author

Anton3 commented Feb 24, 2025

scope parameter in parametrize should only affect caching behavior and should not affect actual rules by which fixtures are allowed to depend on each other. This is exactly what the PR fixes

@Anton3
Copy link
Contributor Author

Anton3 commented Feb 24, 2025

Notice the _check_scope call earlier in the same function:
https://github.com/pytest-dev/pytest/blob/8.3.x/src/_pytest/fixtures.py#L560

The form of late _check_scope call is quite obviously an oversight

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants