Skip to content

Pytest holds on to fixtures too long causing a memory leak #5642

@matham

Description

@matham

Pytest seems to hold on to the object yielded, even after the test is done, sometimes, even until all the tests are done.

The following code:

import pytest
import gc
import weakref


class SomethingInteresting(object):

	def check_app(self):
		assert True
		print('app checked')


@pytest.fixture
def my_app():
	app = SomethingInteresting()
	yield app

	app = weakref.ref(app)
	gc.collect()
	print('app is', app())
	if app() is not None:
		assert False


def test_my_app(my_app):
	my_app.check_app()

Results in this:

pytest /g/Python/libs/Playground/src/playground15.py
============================================================================================================= test session starts ============================================================================================================= platform win32 -- Python 3.7.3, pytest-4.6.3, py-1.8.0, pluggy-0.12.0
rootdir: G:\Python\libs\Playground
collected 1 item

..\Playground\src\playground15.py .E                                                                                                                                                                                                     [100%]

=================================================================================================================== ERRORS ==================================================================================================================== ______________________________________________________________________________________________________ ERROR at teardown of test_my_app _______________________________________________________________________________________________________

    @pytest.fixture
    def my_app():
        app = SomethingInteresting()
        yield app

        app = weakref.ref(app)
        gc.collect()
        print('app is', app())
        if app() is not None:
>               assert False
E     assert False

..\Playground\src\playground15.py:22: AssertionError
------------------------------------------------------------------------------------------------------------ Captured stdout call ------------------------------------------------------------------------------------------------------------- app checked
---------------------------------------------------------------------------------------------------------- Captured stdout teardown ----------------------------------------------------------------------------------------------------------- app is <src.playground15.SomethingInteresting object at 0x0000021F5F295908>
====================================================================================================== 1 passed, 1 error in 0.09 seconds ======================================================================================================

I tried to investigate using objgraph, and various pytest modules (e.g. warning) were blamed depending on the exact code. When I tested the app after the fixture has fully returned at the next test, then the app seemed to have been released.

However, in a more complex app that I have, pytest seemed to hold on to the app fixture instances forever, untill all the test has finished. I'm attaching what objgraph shows for this case that Terminal reporter is holding on to it.
sample-graph

Tested on Windows10, py3.7.

pytest                        4.6.3
pytest-cov                    2.7.1
pytest-trio                   0.5.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: needs informationreporter needs to provide more information; can be closed after 2 or more weeks of inactivitytopic: fixturesanything involving fixtures directly or indirectlytype: performanceperformance or memory problem/improvement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions