Converting from Python 2 to 3

"You too can solder!"
“You too can solder!”

And here’s a clip I took a while back too: Crissy Field, SF CA

I found a hierarchical tagging Django app called django-categories that I wanted to use in a project. There were a couple of things that I wanted to fix so I forked it and for one reason or another started to build in Python 3 support.

I’ve heard about Python 3. I’ve even written some small programs in it. But library support wasn’t really there back when I tried it and I slunk back to the comfort of Python 2.7. It turns out that all the dependencies for django-categories work in Python 3 and I found a few tools that make version portable code a snap to write. Maybe 2014 is the year of py3k.

Tools (or how Travis CI and tox make this possible)

Travis CI is a great idea. I was really confused and skeptical when I started to see these .travis.yml files show up in git repos. But after finally running it myself I can see what the fuss is about. Travis CI integrates seamlessly with github these days. You literally just have to click a button for Travis CI to start watching one of your github repos and running automated builds. This is great news since you now have the power to run your tests using a slew of different Pythons and dependent libraries. Here’s a .travis.yml file that tests all recent Python versions with all recent Django versions (except for Python 3 and Django 1.4…that’s not supported):

language: python
python:
  - "2.6"
  - "2.7"
  - "3.2"
  - "3.3"
env:
  - DJANGO_VERSION=1.4.10
  - DJANGO_VERSION=1.5.5
  - DJANGO_VERSION=1.6.2
matrix:
  exclude:
    # Django only started supporting Python 3 in 1.5+
    - python: "3.2"
      env: DJANGO_VERSION=1.4.10
    - python: "3.3"
      env: DJANGO_VERSION=1.4.10
install:
  - pip install Django==$DJANGO_VERSION
  - pip install -e .
script:
  - ./example/manage.py test categories

tox is a great idea. In a way tox is very similar to Travis CI. It will run your tests with a slew of different Pythons in virtualenvs on your computer. This is fantastic for tracking down version specific bugs while making sure you aren’t writing version incompatible code. It’s just a simple pip install tox away! Here’s the tox.ini I used:

[tox]
envlist = py26,py27,py32,py33

[testenv]
deps = Django
commands = python example/manage.py test categories

When a test fails in Python 2.6 I can make changes and run the tests again for Python 2.6 specifically with tox --develop -e py26. Once the test passes I run all environments with tox --develop.

Code (or what to watch out for)

Now you have the machinery to test your project in multiple environments and you need to start fixing the code. Here are a few things that stood out while I was doing this:

six is a good idea

six is a Python library that makes writing version compatible code easier. If you see a test failing because basestring no longer exists, you can swap in six.string_types. It also helps with tasks like correctly calling next on a generator or importing itertools.izip_longest (which in Python 3 has moved to zip_longest; thanks from six.moves import zip_longest!).

import all the __future__!

One way to proactively avoid writing violations is to include this set of imports:

from __future__ import (
    absolute_import,
    division,
    print_function,
    unicode_literals,
)

Python 2.6 gotchas

  • string.format needs numbers in the placeholders (e.g. "Hello, {}!".format("world") NO, "Hello, {0}!".format("world") YES).
  • assertRaises can’t be used as a context manager (boo).

Python 3.2 gotchas

Python 3.2 doesn’t believe in unicode string literals starting with a u. u"Hi!" NO, "Hi" YES (if you imported unicode_literals from __future__; which you did, so. yeah.).

Leave a Reply

Your email address will not be published. Required fields are marked *