pytest-dev/pytest-cov

__del__ method incorrectly reported as missing in a problem with circular references

andymwood opened this issue · 1 comments

Summary

The following problem has two objects that reference each other and a __del__ method in one of the classes. pytest-cov incorrectly reports that the __del__ method hasn't been called.

Expected vs actual result

Expected 100% coverage. Get 91% coverage.

Reproducer

$ python3.10 -m venv venv
$ . venv/bin/activate
$ pip install pytest-cov
$ pytest --cov=. --cov-report=term-missing test_module.py 
================================================================== test session starts ===================================================================
platform linux -- Python 3.10.11, pytest-7.4.0, pluggy-1.2.0
rootdir: ...
plugins: cov-4.1.0
collected 1 item                                                                                                                                         

test_module.py .                                                                                                                                   [100%]
A.__del__


---------- coverage: platform linux, python 3.10.11-final-0 ----------
Name             Stmts   Miss  Cover   Missing
----------------------------------------------
test_module.py      10      1    90%   3
----------------------------------------------
TOTAL               10      1    90%


=================================================================== 1 passed in 0.06s ====================================================================

Versions

$ pip list
Package        Version
-------------- -------
coverage       7.2.7
exceptiongroup 1.1.2
iniconfig      2.0.0
packaging      23.1
pip            23.0.1
pluggy         1.2.0
pytest         7.4.0
pytest-cov     4.1.0
setuptools     65.5.0
tomli          2.0.1
$ python --version
Python 3.10.11

Code

test_module.py:

class A:
    def __del__(self):
        print('\nA.__del__')


class B:
    pass


def test_case():
    x = A()
    x.y = B()
    x.y.x = x
    assert x is not None
nedbat commented

__del__ methods are very difficult. In your case, the method is being called during interpreter shutdown, so possibly after coverage has stopped measurement. They can cause other troubles as well (see the pink warning box at https://docs.python.org/3/reference/datamodel.html#object.__del__). You might want to consider refactoring to avoid the need for __del__.

In the meantime, you can add a pragma comment to indicate that you understand the line will not be measured: https://coverage.readthedocs.io/en/7.2.7/excluding.html#excluding-code-from-coverage-py