|Ned Batchelder : Blog | Code | Text | Site|
Coverage.py on Python 3.x
» Home : Blog : July 2009
Last week I went through the exercise of making coverage.py compatible with Python 3.1. I learned a few things along the way.
At first, I wanted to create code that would work on both 2.x and 3.x, but while that is possible to an extent, there are syntactic differences that make it impossible. Then I toyed with the idea of a preprocessor-like tool that would let me have 2.x lines and 3.x lines together in one file, but it seemed like more trouble than it was worth.
In the end I went back to the standard 2to3 tool. I had thought that this tool was meant to be a starting point for creating a 3.x codebase, and I started using it that way. But a recommendation I read somewhere suggested using it not once at the start of the project, but as a build step to create your 3.x kit from your 2.x sources. This is what I ended up doing.
2to3 is impressive: it runs over your source files, changing code to work under 3.x. It doesn't always do the best thing, but I never saw it do the wrong thing.
My process is to copy my whole source tree into a "three" directory, then run 2to3, then run the unit tests. After fixing a problem, repeat the process. This seems like an odd way to run with an interpreted language, but works really well, and lets me keep one code base. It doesn't run as-is on 2.x and 3.x, but it's one set of files that produces code that runs on both.
The bulk of the changes I had to make were in the tests rather than in the coverage.py code itself. Coverage.py's tests consists of many small snippets of code, often in strings, so 2to3 wasn't able to fix it all up for me. In these snippets, I had often used print statements where any statement would do, so I ended up converting a lot of these to assignments. Where I really did want printing I added parentheses to make them compatible between 2.x and 3.x.
Here are some other differences I had to accommodate:
After all of these changes, now I have code that passes all its unit tests on 3.x. I still haven't tackled packaging kits for 3.x, but that's next.