Testing against Multiple Versions of Python with tox - goerz/cookiecutter-pypackage GitHub Wiki

The recommended way to support testing against multiple versions of Python is to use tox. It is configured by a file tox.ini in the root of the project folder. It is configured by a file tox.ini in the root of the project folder.

The following is an annotated walk-through for a typical tox.ini file:

[tox]
minversion = 3.7
envlist = py35-{test,runcmd}, py36-{test,runcmd}, py37-{test,runcmd}, run-{cmd,blackcheck,black,isort,isortcheck}, docs, coverage

The minversion is the minimum required version of tox, not the version of Python. The envlist is a generative specification of all the testing environments. It expands to py35-test, py35-runcmd, py36-test, py36-runcmd, py37-test, py37-runcmd, un-cmd, run-blackcheck, run-black, run-isort, run-isortcheck, docs, and coverage. This is for a package that supports Python 3.5-3.7, where only the most current version Python 3.7 is used for running various linting tools or generating the documentation. In order for tox to run, all required Python versions must be available in the current shell environment. You will have to use pyenv to ensure this. An alternative would be to use the tox-conda plugin. You can do this by appending the line

requires = tox-conda

to the above [tox] section. You should not install tox-conda into your normal Python environment, as this will enable the use of conda for all invocations of tox in all projects (see tox-conda#14).

[testenv:.tox]
envdir = {toxworkdir}/.tox

The .tox testenv is used if the system tox does not meet the minversion defined earlier, or if you use tox-conda ("auto-provisioning"

[testenv]
basepython =
    py37,run,docs,coverage: python3.7
    py36: python3.6
    py35: python3.5
envdir =
    py37,run,docs,coverage: {toxworkdir}/py37
    py36: {toxworkdir}/py36
    py35: {toxworkdir}/py35
deps=
    cython
    numpy
    scipy
usedevelop = true
extras=
    dev
setenv =
    MATPLOTLIBRC = tests
    SPELLCHECK = en_US
description =
    py{36,37}-test: Run tests in the corresponding environment
    py{36,37}-runcmd: Run arbitrary command following "--" in the corresponding environment
commands_pre =
    python -V
commands =
    py{35,36,37}-runcmd: {posargs:python -c 'print("No command")'}
    py{35,36,37}-test: py.test -vvv --doctest-modules --cov=krotov --nbval --sanitize-with docs/nbval_sanitize.cfg --durations=10 -x -s {posargs:src tests docs README.rst}

The [testenv] section of tox.ini defines the settings for all environments that do not override any settings. This uses some factor-conditional settings to compress the configuration , providing the commands for default *-runcmd and *-test environments. We also re-use the same environment folder depending only on the version of Python. That is, py37-test, py37-runcmd, run-cmd, run-blackcheck, run-black, run-isort, run-isortcheck, docs, and coverage, which all use Python 3.7, all use the same environment directory .tox/py37

The package to be tested gets installed in development mode (pip install -e ., due to usedevelop = true, which will also install all dev-dependencies defined in setup.py (due to extras=dev), The deps defined in tox.ini are dependencies that must be installed into the tox environment before the package to be tested itself gets installed (in this case, one of the dev-dependencies in setup.py builds extension modules, and thus requires cython and numpy/scipy development headers. If you've used tox-conda earlier, replace devs with e.g.

conda_deps =
    qutip
conda_channels=
    default
    conda-forge

This will install qutip from the conda-forge channel.

The rest of the tox.ini file overrides commands for particular environments:

[testenv:docs]
description = Generate the docs
commands =
    sphinx-build docs docs/_build {posargs:--color}

[testenv:coverage]
description = "Generate a coverage report"
depends = py37-test
commands =
    coverage html
    python -c 'import pathlib; print("coverage report available in \{\}".format(pathlib.Path(".") / "htmlcov" / "index.html"))'

[testenv:run-cmd]
description = Run arbitrary command following "--" in the latest venv, e.g. "tox -e run-cmd -- ipython"
commands = {posargs:python -c 'print("No command")'}

[testenv:run-black]
description = Run black formatter in the latest venv
commands = python -m black --skip-string-normalization --line-length 79 src tests

[testenv:run-blackcheck]
description = Run black formatter check in the latext venv
commands = python -m black --skip-string-normalization --line-length 79 --check src tests

[testenv:run-isort]
description = Run isort formatter in the latest venv
commands = python -m isort --recursive src tests

[testenv:run-isortcheck]
description = Run isort formatter check in the latest venv
commands = python -m isort --recursive --check-only src tests

[testenv:run-flake8]
description = Run flake8 formatter check in the latest venv
commands = python -m flake8 src tests

[testenv:run-pylint]
description = Run pylint formatter check in the latest venv
commands = python -m pylint -j 0 src
⚠️ **GitHub.com Fallback** ⚠️