Tox is a relatively new tool that does one thing very well: test a python package in a set of virtual environments. This roughly translates to something like:

A minimal tox.ini looks like this:

That will run py.test with both Python 2.7 and 3.4.

There are probably other tools I haven't considered, feel free to comment, if you still think there's something better than tox . :-)

There are some alternatives to tox , however, they have some disadvantages:

There are several advantages of using tox :

Effective use *

Because tox was designed for the aforementioned workflow some things are hard to do, or the best way is unclear. I'm going to go over few less known tricks and patterns.

Command overriding * I usually allow overriding the test command . This allows me to use tox for ad-hoc development. [testenv] deps = pytest commands = {posargs:py.test} With that you can conveniently do any of: tox -- py.test -k test_something to run tests matching test_something in all the environments.

to run tests matching in all the environments. tox -e py34 -- python to get the python REPL in that environment.

to get the python REPL in that environment. tox -e py27 -- django-admin runserver to run the Django development server in that environment. And that would be run over all the available environments.

Lack of packaging * Sometimes you lack a setup.py and it doesn't make sense to have one. But you still want to use tox because you want to use virtualenvs and run something in them. To make that work have this in your tox.ini : [tox] skipsdist = true Note that this applies to all environments you use.

Compact configuration * Using conditional settings you can make tox.ini a lot more brief. Compare this: [tox] envlist = py2.7-A,py3.4-A,py2.7-B,py3.4-B [testenv:py2.7-A] commands = <do some stuff with A> [testenv:py2.7-B] commands = <do some stuff with B> [testenv:py3.4-A] commands = <do some stuff with A> [testenv:py3.4-B] commands = <do some stuff with B> [tox] envlist = py{2.7,3.4}-{A,B} [testenv] commands = A: <do some stuff with A> B: <do some stuff with A> Way more brief :-)

Environment reuse * Sometimes you want to run several commands. Now you have two choices: Have one environment with all the commands. This makes it hard to select an individual command.

Have a environment for each command. This makes command line selection very neat. However, now you have a virtualenv for each environment, which makes everything very slow unless ... ... you have all the environments use the same virtualenv directory! As seen here, you can use a specific directory that doesn't need to be unique: [tox] skipsdist = true envlist = build [testenv] envdir = {toxinidir}/.env commands = build: pelican --output output --settings settings.py --delete-output-directory [] watch: pelican --output output --settings settings.py --delete-output-directory --autoreload [] run: twistd -n web --path=. publish: python ghp-import.py -m "Update gh-pages." output publish: git push origin master publish: git push origin gh-pages deps = pelican==3.5.0 twisted==15.0.0 With such an configuration you can do any of: tox -e build,publish to build and deploy

to build and deploy tox -e watch to build and rebuild on file changes

to build and rebuild on file changes tox -e run to just run a webserver Note the [] in the build command allows adding extra arguments. Example: tox -e build -- --debug to get some verbose logging.

When it inevitably leads to shell scripts * This is one thing that's annoying to do in Tox - sometimes you do want to run some shell scripts, as bad as they are. Suppose you have a test.sh in your project's root: [testenv] commands = test.sh This will work fine, however, on Windows you need a different shell script. Currently tox doesn't have conditional settings for the platform so you need to have a script that can run both as Shell and Batch (for Windows). A way to solve this is to have something like this in tox.ini : [testenv] commands = test.cmd Then you make test.cmd executable and have this peculiar mash-up of heredocs ( <<END ... END ), labels ( :end ) and goto : #!/bin/bash -eE : <<"::batch" @ echo off powershell -ExecutionPolicy ByPass -File test.ps1 %* goto : end : :batch test.sh $* exit $? : <<"::done" : end : :done And then you write regular Bash code in test.sh and PowerShell (on Windows) in test.ps1 . The ExecutionPolicy ByPass is required because PowerShell doesn't allow external scripts to run by default (the default is a sort of "interactive only" mode) .

Partial environment reuse * Suppose you want to test a set of configurations. Using a conditional settings you can have something like this: [tox] envlist = {2.7,3.4}-{A,B,C} [testenv] basepython = 2.7: python2.7 3.4: python3.4 # {toxworkdir} defaults to .tox envdir = 2.7: {toxworkdir}/2.7 3.4: {toxworkdir}/3.4 # I'm building here on the previous example but we could have any other command here ... commands = {2.7,3.4}-A: {toxinidir}/test.cmd A {2.7,3.4}-B: {toxinidir}/test.cmd B {2.7,3.4}-C: {toxinidir}/test.cmd C With that you'll have only 2 environments and that will significantly reduce environment rebuild time.