Skip to content

Commit

Permalink
Merge pull request #3249 from a-feld/request-fixture-reference-cycle
Browse files Browse the repository at this point in the history
Fix PseudoFixtureDef reference cycle.
  • Loading branch information
nicoddemus authored Feb 22, 2018
2 parents 1127d51 + 4854876 commit bedceaa
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 4 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,4 @@ Xuan Luong
Xuecong Liao
Zoltán Máté
Roland Puntaier
Allan Feldman
13 changes: 9 additions & 4 deletions _pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
from _pytest.outcomes import fail, TEST_OUTCOME


@attr.s(frozen=True)
class PseudoFixtureDef(object):
cached_result = attr.ib()
scope = attr.ib()


def pytest_sessionstart(session):
import _pytest.python
import _pytest.nodes
Expand Down Expand Up @@ -440,10 +446,9 @@ def _get_active_fixturedef(self, argname):
fixturedef = self._getnextfixturedef(argname)
except FixtureLookupError:
if argname == "request":
class PseudoFixtureDef(object):
cached_result = (self, [0], None)
scope = "function"
return PseudoFixtureDef
cached_result = (self, [0], None)
scope = "function"
return PseudoFixtureDef(cached_result, scope)
raise
# remove indent to prevent the python3 exception
# from leaking into the call
Expand Down
1 change: 1 addition & 0 deletions changelog/3249.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix reference cycle generated when using the ``request`` fixture.
35 changes: 35 additions & 0 deletions testing/python/fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,41 @@ def test_method(self, something):
assert len(arg2fixturedefs) == 1
assert arg2fixturedefs['something'][0].argname == "something"

def test_request_garbage(self, testdir):
testdir.makepyfile("""
import sys
import pytest
import gc
@pytest.fixture(autouse=True)
def something(request):
# this method of test doesn't work on pypy
if hasattr(sys, "pypy_version_info"):
yield
else:
original = gc.get_debug()
gc.set_debug(gc.DEBUG_SAVEALL)
gc.collect()
yield
gc.collect()
leaked_types = sum(1 for _ in gc.garbage
if 'PseudoFixtureDef' in str(_))
gc.garbage[:] = []
try:
assert leaked_types == 0
finally:
gc.set_debug(original)
def test_func():
pass
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)

def test_getfixturevalue_recursive(self, testdir):
testdir.makeconftest("""
import pytest
Expand Down

0 comments on commit bedceaa

Please sign in to comment.