The
recently released Chameleon template compiler was written as a
single source for all Python platforms > 2.5, including Python 3.x (and PyPy).
I'd like to share my experience in taking this approach instead of using the
2to3 tool or a similar technique (read
this article by Armin Ronacher to compare).
I started out requiring Python 2.7. This is actually my recommendation if you're contemplating writing a cross-platform compatible library. This release of Python 2 supports most of the features of Python 3 and has syntax-compatibility. And most applications that run on 2.5 will also run without modification on 2.7.
However, in my case, Python 2.5 was a priority. It's somewhat tedious to support this version because the exception handler syntax is incompatible with Python 3. You have to call
sys.exc_info() to get the exception instance in every handler. To remedy this, you can try and minimize the use of exception handlers; most of the standard library code offer interfaces that don't raise exceptions. The unit test module is also somewhat outdated and I ended up with a dependency on
unittest2.
It's hard to avoid conditional imports and use of various aliases such as:
try: fast_string = str str = unicode bytes = fast_string except NameError: long = int basestring = str fast_string = str
Most libraries won't have to care about string encoding to the point where this is necessary, but in the case of a template engine, this stuff matters.
In terms of packaging, I decided to require
distribute. I don't know what the support for Python 3 is with
setuptools, but my attempts to make it work failed miserably. After adding trove classifiers for all supported versions, my package showed up in the Python 3
compatibility list.
Why not use the conversion tool? Truth is that I didn't care to try this approach because it seemed error prone and complex. I'd rather "dumb down" my library code than have to automatically translated. With any sort of code generation there's going to be questions such as "where is the generated code?" and "how to step-debug it?". With the single source approach, everything's business as usual. There's always a downside in supporting old Python releases in that you can't use all the new standard library code. But the conversion tool can't help there.