Skip to content

Commit

Permalink
fix: improve caching of parameterized fixtures
Browse files Browse the repository at this point in the history
The fix for Issue pytest-dev#6541 caused regression where cache hits became
cache misses, unexpectedly.  Attempt to restore the previous behavior,
while also retaining the fix for the bug.

Fixes: Issue pytest-dev#6962
  • Loading branch information
nisimond authored and nicoddemus committed Jul 17, 2024
1 parent 400b22d commit d434bcf
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 3 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ Nicholas Devenish
Nicholas Murphy
Niclas Olofsson
Nicolas Delaby
Nicolas Simonds
Nico Vidal
Nikolay Kondratyev
Nipunn Koorapati
Expand Down
1 change: 1 addition & 0 deletions changelog/6962.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed bug where parametrized fixtures were not being cached correctly, being recreated every time.
13 changes: 10 additions & 3 deletions src/_pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -1056,9 +1056,16 @@ def execute(self, request: SubRequest) -> FixtureValue:
my_cache_key = self.cache_key(request)
if self.cached_result is not None:
cache_key = self.cached_result[1]
# note: comparison with `==` can fail (or be expensive) for e.g.
# numpy arrays (#6497).
if my_cache_key is cache_key:

# note: `__eq__` is not required to return a bool, and sometimes
# doesn't, e.g., numpy arrays (#6497). Coerce the comparison
# into a bool, and if that fails, fall back to an identity check.
try:
cache_hit = bool(my_cache_key == cache_key)
except (ValueError, RuntimeError):
cache_hit = my_cache_key is cache_key

if cache_hit:
if self.cached_result[2] is not None:
exc, exc_tb = self.cached_result[2]
raise exc.with_traceback(exc_tb)
Expand Down
31 changes: 31 additions & 0 deletions testing/python/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,37 @@ def test_printer_2(self):
result = pytester.runpytest()
result.stdout.fnmatch_lines(["* 2 passed in *"])

def test_parameterized_fixture_caching(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
from itertools import count
CACHE_MISSES = count(0)
def pytest_generate_tests(metafunc):
if "my_fixture" in metafunc.fixturenames:
param = "d%s" % "1"
print("param id=%d" % id(param), flush=True)
metafunc.parametrize("my_fixture", [param, "d2"], indirect=True)
@pytest.fixture(scope='session')
def my_fixture(request):
next(CACHE_MISSES)
def test1(my_fixture):
pass
def test2(my_fixture):
pass
def teardown_module():
assert next(CACHE_MISSES) == 2
"""
)
result = pytester.runpytest()
result.stdout.no_fnmatch_line("* ERROR at teardown *")


class TestFixtureManagerParseFactories:
@pytest.fixture
Expand Down

0 comments on commit d434bcf

Please sign in to comment.