Pytest: Session fixture keeps frames of other fixtures alive

Created on 30 Nov 2017  路  3Comments  路  Source: pytest-dev/pytest

Consider this test file:

import pytest
import weakref

class SomeObj:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return '<SomeObj "{}">'.format(self.name)

ref = None
session_ref = None

@pytest.fixture(scope='session')
def session_fix():
    global session_ref
    session_obj = SomeObj('session')
    session_ref = weakref.ref(session_obj)
    return session_obj

@pytest.fixture
def fix(session_fix):
    global ref
    obj = SomeObj('local')
    ref = weakref.ref(obj)
    return obj

def test1(fix):
    assert ref() is fix

def test2():
    assert ref() is None

This fails with:

============================= test session starts =============================
platform win32 -- Python 3.6.3, pytest-3.3.1.dev26+gfdfc194, py-1.5.2, pluggy-0.6.0 -- c:\sybil\.env36\scripts\python.exe
cachedir: .cache
rootdir: C:\pytest\.tmp, inifile: pytest.ini
collected 2 items

test_leak.py::test1 PASSED                                               [ 50%]
test_leak.py::test2 FAILED                                               [100%]

================================== FAILURES ===================================
____________________________________ test2 ____________________________________

    def test2():
>       assert ref() is None
E       assert <SomeObj "local"> is None
E        +  where <SomeObj "local"> = ref()

test_leak.py:31: AssertionError
===================== 1 failed, 1 passed in 0.04 seconds ======================

So for some reason the object created in fix is being kept alive after test1 has finished. This is caused by session_fix and can be verified by changing test1 to no longer require session_fix in which case both tests pass.

This seems to reproduce the errors reported in #2968 and #2970 because both tests pass in 3.2.5. 馃槗

fixtures bug

All 3 comments

Just ran the fix from #3030 locally, this also fixes an issue we encountered where our connections to postgresql were not closed, resulting in:
(psycopg2.OperationalError) FATAL: remaining connection slots are reserved for non-replication superuser connections and
(psycopg2.OperationalError) FATAL: sorry, too many clients already
If the test role was a superuser.

Just for anyone else coming across this issue.

Thanks @nicoddemus and the rest of the pytest team for all the work you do. 馃帄

Thanks @JacobSMoller for testing the PR! 馃憤 馃榿

Glad this fixed your problem, but I would recommend regardless to explicitly close your connections and do not rely on the garbage collector for that.

@nicoddemus just wanted to say thanks for your work on this! We'll be upgrading immediately and will let you know if we run into any issues.

Was this page helpful?
0 / 5 - 0 ratings