Tox-Driven Python Development
Going through Julian Berman’s jsonschema repo (some of the cleanest Python code I’ve read, by the way), I stumbled upon a recommendation that greatly improved my Python workflow. I’m talking about Tox, the Python testing automaton.
Tox allows you to test your code against multiple versions of Python (yes, PyPy included!) with a single command:
It uses virtualenv to create a virtual Python environment for each Python version you want to support, installs your dependencies as well as the package you are currently developing in each of these enviroments and runs a sequence of testing commands of your choice in each environment.
Tox is great for Test-driven development (TDD). In fact, I no longer need to activate a virtual environment during development. My workflow now looks like this:
1. Write a test 1. Write some code 1. Run tox and tweak code until test passes
If you think your code works on all versions of Python just because it works on your development version, think again!
- pip install tox. As long as tox is in your PATH, you don’t need to set up a virtual environment.
- Add /.tox to your .gitignore file.
- Create a setup.py file for your package. This is still a complicated matter in Python. setuptools is old, distribute is going in the trash, distutils2 is the future. For now, use setuptools. Specify dependencies using install_requires. Testing dependencies (such as nose) will be specified later. If you depend on a version of a package that is not distributed on PyPI, use dependency_links as follows:
install_requires = [ "jsonschema==0.7-patched", ], dependency_links = [ # Patched version to support a special feature "http://github.com/boronine/jsonschema/tarball\ /391916e71b946db3bf5d92cbb767f620a869fc82#egg=jsonschema-0.7-patched" ]
- Create a MANIFEST.in file to make sure your package includes auxiliary files:
include tox.ini # If your tests aren't part of the distributed package, make sure to include them recursive-include tests *
- Configure Tox with tox.ini. Testing dependencies go in deps.
[tox] envlist = py26, py27, pypy [testenv] deps = nose unittest2 commands = nosetests
- Run tox. The first run will take a minute because it has to generate the virtual environments. The subsequent runs will be fast.