Coverage.py 使用 setuptools 调用时给出错误的统计信息

Coverage.py gives wrong stat when called with setuptools

设置

Pytest 和覆盖率设置

在我的 python 项目中 myproject 我使用以下 setup.cfg:

...
[aliases]
test = pytest

[tool:pytest]
addopts = --durations=5 --cov
testpaths = tests

[coverage:run]
branch = True
source = myproject
...

如您所见,我使用 pytest 并将其别名为 test,因此我可以通过设置工具调用它 (python setup.py test)。

目录布局

我的项目结构如下所示:

.
├── MANIFEST.in
├── README.rst
├── tests
│   └── test_version.py
└── myproject
    ├── __init__.py
    └── _version.py

请注意,没有 .coveragerc 文件,所以所有设置都来自 setup.py

问题

当我直接 运行 pytest 时,覆盖率给我正确的统计数据:

running pytest
running egg_info
writing requirements to myproject.egg-info/requires.txt
writing myproject.egg-info/PKG-INFO
writing top-level names to myproject.egg-info/top_level.txt
writing dependency_links to myproject.egg-info/dependency_links.txt
writing entry points to myproject.egg-info/entry_points.txt
reading manifest file 'myproject.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
warning: no previously-included files matching '*.pyo' found under directory 'tests'
writing manifest file 'myproject.egg-info/SOURCES.txt'
running build_ext
================================================================================ test session starts ================================================================================
platform darwin -- Python 2.7.13, pytest-3.0.7, py-1.4.33, pluggy-0.4.0 -- /Users/someuser/.virtualenvs/myproject/bin/python
cachedir: .cache
rootdir: /Users/someuser/Desktop/myproject, inifile: setup.cfg
plugins: cov-2.4.0
collected 7 items 

tests/test_version.py::test_versionInfoIsExposed PASSED
tests/test_version.py::test_versionInfoIsASemanticVersionTuple PASSED
tests/test_version.py::test_versionIsExposed PASSED
tests/test_version.py::test_versionIsASemanticVersionString PASSED
tests/test_version.py::test_versionLooksGeneratedFromVersionInfo PASSED

---------- coverage: platform darwin, python 2.7.13-final-0 ----------
Name                            Stmts   Miss Branch BrPart  Cover
-----------------------------------------------------------------
myproject/__init__.py               1      0      0      0   100%
myproject/_version.py               3      0      0      0   100%
-----------------------------------------------------------------
TOTAL                               4      0      0      0   100%
...

当我 运行 python setup test 时,报道给了我不同的(错误的)统计数据:

running pytest
running egg_info
writing requirements to myproject.egg-info/requires.txt
writing myproject.egg-info/PKG-INFO
writing top-level names to myproject.egg-info/top_level.txt
writing dependency_links to myproject.egg-info/dependency_links.txt
writing entry points to myproject.egg-info/entry_points.txt
reading manifest file 'myproject.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
warning: no previously-included files matching '*.pyo' found under directory 'tests'
writing manifest file 'myproject.egg-info/SOURCES.txt'
running build_ext
================================================================================ test session starts ================================================================================
platform darwin -- Python 2.7.13, pytest-3.0.7, py-1.4.33, pluggy-0.4.0 -- /Users/someuser/.virtualenvs/myproject/bin/python
cachedir: .cache
rootdir: /Users/someuser/Desktop/myproject, inifile: setup.cfg
plugins: cov-2.4.0
collected 7 items 

tests/test_version.py::test_versionInfoIsExposed PASSED
tests/test_version.py::test_versionInfoIsASemanticVersionTuple PASSED
tests/test_version.py::test_versionIsExposed PASSED
tests/test_version.py::test_versionIsASemanticVersionString PASSED
tests/test_version.py::test_versionLooksGeneratedFromVersionInfo PASSED

---------- coverage: platform darwin, python 2.7.13-final-0 ----------
Name                            Stmts   Miss Branch BrPart  Cover
-----------------------------------------------------------------
myproject/__init__.py               1      1      0      0     0%
myproject/_version.py               3      3      0      0     0%
-----------------------------------------------------------------
TOTAL                               4      4      0      0     0%
...

有人知道为什么会这样吗?

如果有人偶然发现了这个,我终于找到了解决方案。 在我的 setup.cfg 中,我在 metadata 部分中有以下行:

[metadata]
...
version = attr: myproject._version.__version__
...

这导致模块 myproject.__init__myproject._version.py 中的所有行在测试 运行 之前变为 运行,因此 coverage 没有机会告诉,这些行实际上被测试覆盖了。

为了解决这个问题,我只是阅读了 setup.py 中的 __version__ 信息,而没有导入模块:

# inside setup.py
_locals = {}
with open('sirup/_version.py') as fp:
    exec(fp.read(), None, _locals)
version = _locals['__version__']

setup(version=version)