Here is a link to a project and output that you can use to reproduce the problem I describe below.
I'm using coverage with tox against multiple versions of python. My tox.ini file looks something like this:
[tox]
envlist =
py27
py34
[testenv]
deps =
coverage
commands =
coverage run --source=modules/ -m pytest
coverage report -m
My problem is that coverage will run using only one version of python (in my case, py27), not both py27 and py34. This is a problem whenever I have code execution dependent on the python version, e.g.:
def add(a, b):
import sys
if sys.version.startswith('2.7'):
print('2.7')
if sys.version.startswith('3'):
print('3')
return a + b
Running coverage against the above code will incorrectly report that line 6 ("print('3')") is "Missing" for both py27 and py34. It should only be Missing for py34.
I know why this is happening: coverage is installed on my base OS (which uses python2.7). Thus, when tox is run, it notices that coverage is already installed and inherits coverage from the base OS rather than installing it in the virtualenv it creates.
This is fine and dandy for py27, but causes incorrect results in the coverage report for py34. I have a hacky, temporary work-around: I require a slightly earlier version of coverage (relative to the one installed on my base OS) so that tox will be forced to install a separate copy of coverage in the virtualenv. E.g.
[testenv]
deps =
coverage==4.0.2
pytest==2.9.0
py==1.4.30
I don't like this workaround, but it's the best I've found for now. Any suggestions on a way to force tox to install the current version of coverage in its virtualenv's, even when I already have it installed on my base OS?
I came upon this problem today, but couldn't find an easy answer. So, for future reference, here is the solution that I came up with.
envlist
that contains each version of Python that will be tested and a custom env for cov
.COVERAGE_FILE
environment varible to store the .coverage
file in {envdir}
.cov
env I use two commands.
coverage combine
that combines the reports, andcoverage html
to generate the report and, if necessary, fail the test..coveragerc
file that contains a [paths]
section to lists the source=
locations.
tox.ini:
[tox]
envlist=py27,py36,py35,py34,py33,cov
[testenv]
deps=
pytest
pytest-cov
pytest-xdist
setenv=
py{27,36,35,34,33}: COVERAGE_FILE={envdir}/.coverage
commands=
py{27,36,35,34,33}: python -m pytest --cov=my_project --cov-report=term-missing --no-cov-on-fail
cov: /usr/bin/env bash -c '{envpython} -m coverage combine {toxworkdir}/py*/.coverage'
cov: coverage html --fail-under=85
.coveragerc:
[paths]
source=
src/
.tox/py*/lib/python*/site-packages/
The most peculiar part of the configuration is the invocation of coverage combine
. Here's a breakdown of the command:
tox
does not handle Shell expansions {toxworkdir}/py*/.coverage
, so we need to invoke a shell (bash -c
) to get the necessary expansion.
.coverage
file dependency for each pyNN
env./usr/bin/env bash -c '...'
to ensure we get the correct version of bash
. Using the fullpath to env
avoids the need for setting whitelist_externals
.'{envpython} -m coverage ...'
ensures that we invoke the correct python
and coverage
for the cov
env.cov
env is dependent on the invocation of py{27,36,35,34,33}
which has some not so desirable side effects.
cov
through tox
.tox -ecov
because, either
.coverage
file, ortox -epy27,py36,cov
), then wipe out the .tox
directory first (rm -rf .tox
) to avoid the missing .coverage
file problem.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With