Skip to content

How to reuse same fixture implementation with different scopes? #3425

Closed
@ghost

Description

Hello!

I am looking for a way to reuse same fixture or same fixture implementation in different scopes. I would like to avoid copy-pasting implementation in multiple fixtures with different scopes defined. What would be recommended approach?

So far I have thought about (ab)using yield from as in following example. Not sure if this can lead to some unexpected issues.

@pytest.fixture(session='function')
def my_fixture_fun():
    yield from fixture_impl()

@pytest.fixture(scope='module')
def my_fixture_mod():
    yield from fixture_impl()

@pytest.fixture(scope='session')
def my_fixture_ses():
    yield from fixture_impl()

def fixture_impl():
    # Rather long on complicated fixture implementation here
    print('SETUP: Fixture implmentation')
    yield
    print('TEARDOWN: Fixture implmentation')

Any other ideas or suggestions?
Thanks!

Activity

pytestbot

pytestbot commented on Apr 24, 2018

@pytestbot
Contributor

GitMate.io thinks possibly related issues are #538 (Fixture scope documentation), #1552 (Suggestion: add new 'parametrization' fixture scope), #2732 (Fixture scope mixing?), #3393 (Customize the fixture ordering on the same scope level), and #668 (autouse fixtures break scope rules).

RonnyPfannschmidt

RonnyPfannschmidt commented on Apr 24, 2018

@RonnyPfannschmidt
Member

iriginally multi scoped fixtures was planned for pytest 3.0, but it demonstrated impossible to implement without a major refactoring, what you do there is the common workaround, but its suggested to use a contextmanager instead of yield from

ghost

ghost commented on Apr 24, 2018

@ghost

@RonnyPfannschmidt Thanks for such a prompt response. As per your suggestions of using contexmanager instead, do you mean something along these lines?

@pytest.fixture(scope='module')
def my_fixture_mod():
    with fixture_impl():
        pass


@contextmanager
def fixture_impl():
    print('BEFORE: Fixture implmentation')
    yield
    print('AFTER: Fixture implmentation')
RonnyPfannschmidt

RonnyPfannschmidt commented on Apr 24, 2018

@RonnyPfannschmidt
Member

@jurisbu correct

with fixture_impl(...) as result:
   yield result
ghost

ghost commented on Apr 24, 2018

@ghost

Satisfactory answer received. Closing.

ghost closed this as completedon Apr 24, 2018
iAnanich

iAnanich commented on Aug 6, 2021

@iAnanich

Same idea can be applied to async fixtures/tests:

@pytest.fixture(scope='module')
async def my_fixture_mod():
    async with fixture_impl() as result:
        yield result


@asynccontextmanager
async def fixture_impl():
    print('BEFORE: Fixture implementation')
    yield
    print('AFTER: Fixture implementation')
oleg-kondaurov

oleg-kondaurov commented on Oct 13, 2021

@oleg-kondaurov

@RonnyPfannschmidt @jurisbu @iAnanich Is it possible to somehow trigger the test state to become error or fail in case if an exception is raised in setup or teardown block of the contextmanager?

Current example causes the unhandled exception and pytest process close:

@pytest.fixture(scope='module')
def my_fixture_mod():
    with fixture_impl(...) as result:
       yield result

@contextmanager
def fixture_impl():
    print('raise exception in BEFORE...')
    print(1/0)
    yield
    print('raise exception in AFTER...')
    print(1/0)
dmos62

dmos62 commented on May 19, 2022

@dmos62

I've been doing this:

def _some_fixture(a_dependency_fixture):
    def __some_fixture(x):
        return x
    yield __some_fixture

some_temp_fixture = pytest.fixture(_some_fixture, scope="function")
some_module_fixture = pytest.fixture(_some_fixture, scope="module")
some_session_fixture = pytest.fixture(_some_fixture, scope="session")

Seemed more straightforward than a context manager. Any downsides to this?

nicoddemus

nicoddemus commented on May 19, 2022

@nicoddemus
Member

Any downsides to this?

Currently we add an attribute to the function decorated by @pytest.fixture:

function._pytestfixturefunction = self # type: ignore[attr-defined]

So the fixtures above will actually point to the wrong definition... I'm surprised it works.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: fixturesanything involving fixtures directly or indirectlytype: questiongeneral question, might be closed after 2 weeks of inactivity

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @RonnyPfannschmidt@nicoddemus@dmos62@pytestbot@iAnanich

        Issue actions

          How to reuse same fixture implementation with different scopes? · Issue #3425 · pytest-dev/pytest