request.getfixturevalue crashes in certain cases.
See original GitHub issueconftest.py
import pytest
@pytest.fixture
def fixture_a(request):
yield 'a'
@pytest.fixture(scope="session")
def accumulator():
# This fixture that accumulates info from each test case (via the record_data fixture)
# and then writes it to a database once we're all done
accumulator = []
yield accumulator
# IRL we'd upload this to a database or something. In this minimum repro we'll just print it.
print(f'Printed by accumulator. All tests recorded {accumulator}')
@pytest.fixture
def record_data(accumulator, request):
test_data = {}
yield test_data
print(f"Printed by record_data fixture - test provided data: {test_data}")
# If fixture_a was used by the test case, record its value too.
if 'fixture_a' in request.fixturenames:
test_data['fixture_a'] = request.getfixturevalue('fixture_a')
accumulator.append(test_data)
I have a fixture called record_data that lets a test case store some extra info and then send it off to a database once all the tests are done running. If I run the following test case:
def test_01(record_data):
record_data['foo'] = 'blah'
assert True
I get the following output:
Printed by record_data fixture - test provided data: {'foo': 'blah'}
Printed by accumulator. All tests recorded [{'foo': 'blah'}]
If I add a second test case that uses fixture_a then the record_data fixture will pick that up and record some information about fixture_a too:
def test_02(fixture_a, record_data):
record_data['foo'] = 'blah from test_02'
assert fixture_a == 'a'
Now I get this output:
Printed by record_data fixture - test provided data: {'foo': 'blah'}
Printed by record_data fixture - test provided data: {'foo': 'blah from test_02'}
Printed by accumulator. All tests recorded [{'foo': 'blah'}, {'foo': 'blah from test_02', 'fixture_a': 'a'}]
By using request.fixturenames and request.getfixturevalue I can snoop the value of fixture_a without explicitly adding it to the arg list of record_data and thus not forcing tests to use fixture_a. I thought this was pretty smart and clever. Unforunately, this working appears to depend on the order that the fixtures are listed in the arg list. If I do
def test_03(record_data, fixture_a): # The only change is the order of the fixtures
record_data['foo'] = 'test_03 is where the bug happens'
assert fixture_a == 'a'
Then things go wrong and I get the following error message:
@pytest.fixture
def record_data(accumulator, request):
test_data = {}
yield test_data
print(f'Printed by record_data fixture - test provided data: {test_data}')
# If fixture_a was used by the test case, record its value too.
if 'fixture_a' in request.fixturenames:
> test_data['fixture_a'] = request.getfixturevalue('fixture_a')
E AssertionError
I dove in with my trusty debugger. The AssertionError I’m getting comes from request.getfixturevalue because cached_result got set to None here when the fixture was finalized.
Here’s the version of everything I’m using:
(pytest_venv) petebman@petebman:~/pytest_fixture_bug$ python3 -m pip freeze
attrs==21.4.0
iniconfig==1.1.1
packaging==21.3
pluggy==1.0.0
py==1.11.0
pyparsing==3.0.9
pytest==7.1.2
tomli==2.0.1
I originally ran into this issue in pytest version 6.2.3 but I did the minimum viable repro on the latest version to make sure I wasn’t complaining about something that had already been fixed.
I wonder if there’s a way to keep track of which fixtures have been finalized and which ones haven’t yet other than setting cached_value to None? Alternatively is there a different way I should try to do what I’m trying to do here? It seems reasonable that if a fixture’s name is in request.fixturenames then you should be able to get a value via request.getfixturevalue.
Issue Analytics
- State:
- Created a year ago
- Comments:6 (6 by maintainers)

Top Related StackOverflow Question
imho its fair to fail, you request a fixture in teardown
we should actually let it fail in the teardown phase as its simply wrong to call that api there
put your getfixturevalue before the yield
@petebman certainly 👍