In pytest fixtures nuts and bolts, I noted that you can specify session scope so that a fixture will only run once per test session and be available across multiple test functions, classes, and modules.

In this post, I’m going to show a simple example so you can see it in action.

Here’s the table from the previous post:

<td align="left">
  Run once per test
<td align="left">
  Run once per class of tests
<td align="left">
  Run once per module
<td align="left">
  Run once per session

A separate file for fixtures,

With function, class, and module scope, it is completely reasonable for the fixture code to be in the same file as the tests.
But now suddenly, with session, that doesn’t make sense anymore.

We can put them in This is a special named file that pytest looks for.
The documentation says that it’s for local plugins, but we can use it for local fixtures as well. See the site for placement and scope of

Simple example of session scope fixtures

I think it’s clearest to just see this in action.

I’ve got 4 files:

    • 2 fixtures
    • my_own_session_run_at_beginning, an autouse fixture with session scope
    • some_resource, a normal non-autouse fixture with session scope
    • 2 simple test functions
    • test_alpha_1, has no named fixtures
    • test_alpha_2, has one named fixture, some_resource
    • similar to, but with unittest based tests
    • similar to, but with class based tests `

import pytest

@pytest.fixture(scope="session", autouse=True)
def my_own_session_run_at_beginning(request):
    print('\nIn my_own_session_run_at_beginning()')

    def my_own_session_run_at_end():
            print('In my_own_session_run_at_end()')

def some_resource(request):
    print('\nIn some_resource()')

    def some_resource_fin():
            print('\nIn some_resource_fin()')

` `

def test_alpha_1():
    print('\nIn test_alpha_1()')

def test_alpha_2(some_resource):
    print('\nIn test_alpha_2()')

` `

import unittest
import pytest

class BetaTest(unittest.TestCase):
    def test_unit_beta_1(self):
        print('\nIn test_unit_beta_1()')

    def test_unit_beta_2(self):
        print('\nIn test_unit_beta_2()')

` `

class TestGamma:
    def test_gamma_1(self):
        print('\nIn test_gamma_1()')

    def test_gamma_2(self, some_resource):
        print('\nIn test_gamma_2()')



Run with pytest -s -v

============================= test session starts ==============================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collecting ... collected 6 items test_alpha_1 
In my_own_session_run_at_beginning()

In test_alpha_1()
PASSED test_alpha_2 
In some_resource()

In test_alpha_2()
PASSED BetaTest.test_unit_beta_1 
In test_unit_beta_1()
PASSED BetaTest.test_unit_beta_2 
In test_unit_beta_2()
PASSED TestGamma.test_gamma_1 
In test_gamma_1()
PASSED TestGamma.test_gamma_2 
In test_gamma_2()
In some_resource_fin()
In my_own_session_run_at_end()
=========================== 6 passed in 0.04 seconds ===========================

Mixing function, module, and session scope

Let’s say I’ve got:

  • a function scope fixture ‘resource_c’
  • that uses a module scoped fixture ‘fixture_b’
  • that uses a session scoped fixture ‘fixture_a’

This all works fine.
Also in this example, I’ve added a few autouse fixtures just for fun. `

import pytest

def resource_a(request):
    print('In resource_a()')

    def resource_a_fin():
            print('\nIn resource_a_fin()')

def resource_b(request, resource_a):
    print('In resource_b()')

    def resource_b_fin():
            print('\nIn resource_b_fin()')

def resource_c(request, resource_b):
    print('In resource_c()')

    def resource_c_fin():
            print('\nIn resource_c_fin()')

# these are just some fun dividiers to make the output pretty
# completely unnecessary, I was just playing with autouse fixtures
@pytest.fixture(scope="function", autouse=True)
def divider_function(request):
    print('\n        --- function %s() start ---' % request.function.__name__)
    def fin():
            print('        --- function %s() done ---' % request.function.__name__)

@pytest.fixture(scope="module", autouse=True)
def divider_module(request):
    print('\n    ------- module %s start ---------' % request.module.__name__)
    def fin():
            print('    ------- module %s done ---------' % request.module.__name__)

@pytest.fixture(scope="session", autouse=True)
def divider_session(request):
    print('\n----------- session start ---------------')
    def fin():
            print('----------- session done ---------------')

` `

def test_one(resource_c):
    print('In test_one()')

def test_two(resource_c):
    print('\nIn test_two()')

` `

def test_three(resource_c):
    print('\nIn test_three()')

def test_four(resource_c):
    print('\nIn test_four()')


This seems reasonable to me.
What do you think will happen?

output: `

$ py.test -s -v
==================================== test session starts ====================================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 4 items test_one 
----------- session start ---------------

    ------- module test_one_two start ---------

        --- function test_one() start ---
In resource_a()
In resource_b()
In resource_c()
In test_one()
In resource_c_fin()
        --- function test_one() done --- test_two 
        --- function test_two() start ---
In resource_c()

In test_two()
In resource_c_fin()
        --- function test_two() done ---

In resource_b_fin()
    ------- module test_one_two done --------- test_three 
    ------- module test_three_four start ---------

        --- function test_three() start ---
In resource_b()
In resource_c()

In test_three()
In resource_c_fin()
        --- function test_three() done --- test_four 
        --- function test_four() start ---
In resource_c()

In test_four()
In resource_c_fin()
        --- function test_four() done ---

In resource_b_fin()
    ------- module test_three_four done ---------

In resource_a_fin()
----------- session done ---------------

================================= 4 passed in 0.02 seconds ==================================


WARNING: you gotta use bigger and bigger scope

If you do this in the wrong order, things go haywire.

Let’s swap scope on a couple of items. `

@pytest.fixture(scope="module")   # session -> module
def resource_a(request):
    print('In resource_a()')

    def resource_a_fin():
            print('\nIn resource_a_fin()')

@pytest.fixture(scope="session")   # module -> session
def resource_b(request, resource_a):


We will get some warning like this (or several): `

E           ScopeMismatchError: You tried to access the 'module' scoped fixture 'resource_a' 
... with a 'session' scoped request object, involved factories
E   def resource_c(request, resource_b)
E   def resource_b(request, resource_a)
E   def resource_a(request)


So. Don’t do that.

Warning applies to built in fixtures

Pytest includes some built in fixtures. I believe all of them are function scoped.
This means that you cannot use them from anything other than functions or function scoped fixtures.

Taking it further

The code I’ve shown is for simple run at the beginning and end type fixtures.
However, there’s more you can do with session fixtures.
The site has a cool example, A session-fixture which can look at all collected tests.

What are you using session fixtures for?

I’d love to hear examples and use cases for session fixtures.
Please leave a comment or let me know @brianokken of how you are using them.