Supporting All Versions of Python All The Time With Tox

Author: Kumar McMillan
Venue:PyCon 2011
Slides:http://farmdev.com/talks/tox/

We Are Python Developers

The Python Package Index

http://pypi.python.org/pypi

pip install numpy

Python 2

PYTHON 2

IS

DEPRECATED

How do we get on Python 3?

Developing in tandem with tox: http://codespeak.net/tox/

images/tandem.jpg

Developing a package

$ virtualenv ~/tmp/fudge
$ source ~/tmp/fudge/bin/activate
(fudge)$ python setup.py develop
(fudge)$ pip install Nose
(fudge)$ nosetests
......................................................................................................................................................................................
----------------------------------------------------------------------
Ran 182 tests in 0.589s

OK

Now ... with tox

tox lets you develop in multiple versions of Python

$ cd fudge
$ tox -e py26,py32

[demo]

tox.ini config

[tox]
envlist=py26,py32

[testenv]
deps=nose
commands=
  nosetests []

Test runner args

[tox]
envlist=py26,py32

[testenv]
deps=nose
commands=
  # tox -- --with-nicedots --stop
  nosetests []

Any test command

[tox]
envlist=py26,py32

[testenv]
deps=pytest
commands=
  py.test []

Python 3 Syntax

python3
>>> import fudge
Traceback (most recent call last):
  ...
  File "fudge/patcher.py", line 83
    raise etype, val, tb
               ^
SyntaxError: invalid syntax

Python 3 Syntax

Python 2:

print u'Hello %s' % name

Python 3:

print('Hello {0}'.format(name))

Dual platform setup.py

kw = {}
if sys.version_info >= (3,):
    kw['use_2to3'] = True

setup(name='YourModule',
      version='0.1',
      **kw)
$ python setup.py build

(requires distribute)

setup.py classifiers for PyPI

setup(
  name='YourModule',
  version='0.1',
  classifiers=[
    'Programming Language :: Python :: 3'
  ],
  **kw
)

Single Source for 2 and 3

Python 3 + tox: single source

images/py3-single-source.png

2to3: distributed tests

images/py3-distributed.png

2to3 w/ distributed tests

fudge/__init__.py
fudge/tests/__init__.py
[testenv]
deps=nose
commands=nosetests []

[testenv:py32]
commands=
  nosetests fudge.tests.all_tests

2to3: non-distributed tests

images/py3-non-distributed.png

2to3 w/ non-distributed tests

nose/__init__.py
unit_tests/
functional_tests/
[testenv:py32]
commands=
  {envpython} setup.py build_tests
  cd build/tests
  {envpython} runtests.py []

https://bitbucket.org/jpellerin/nose

Sphinx doctests

[testenv:docs]
changedir=docs
deps=sphinx
     nose
commands=
    make clean
    make doctest
    make html

[demo]

Test against Django trunk

[testenv]
deps=django
commands=python manage.py test

[testenv:trunk]
basepython=python2.6
deps=
  svn+http://.../svn/django/trunk/#egg=django

Built-in tox environments

(interpreters must be installed and in $PATH)

All Environments

LET'S

TEST

EVERYTHING

[demo]

Using tox in CI

Jenkins Matrix Build:

images/jenkins-matrix1.png

Jenkins Matrix Build

images/jenkins-matrix2.png
$TOXENV=py26
tox -e py26

Jenkins Matrix Build

images/jenkins-matrix3.png

Bootstrapping tox

# Python code for builder to execute:
url = "https://pytox.googlecode.com/hg/toxbootstrap.py"
d = dict(__file__='toxbootstrap.py')
exec urllib.urlopen(url).read() in d
d['cmdline'](['--recreate'])

Variables

Custom PyPI

[tox]
indexserver =
    DEV = http://mypypi.org

[testenv]
deps =
    docutils
    :DEV:yourmodule

Now you know...

How to support Python 3:

Questions?

tox: http://codespeak.net/tox/

Thank You