Migrating to Python 3
This post is partially related to my previous blog post about Rewind.
I initially started the implementation of Rewind in Python 2.7. I constantly kept test coverage to 100%, and I tried to stick to TDD as much as possible. The Python testing tool Nose proved to be very valuable, as did Travis CI.
After some time I thought "Hey, why work in Python 2 when Python 3 seems around corner?". I installed Python 3.2 on my laptop and started executing those tests. Travis CI helped a lot here to always make sure that Rewind was backward compatible with Python 2.7. Ever nervous about a test failing? Make pull request on Github and Travis CI will tell you whether the pull request broke something or not. Highly convenient. Migration to Python 3 can be summarized in three paragraphs:
Migrate from lists to iterators. In many ways I like the changes to the built-in functions map and reduce. Working with iterators are in many ways a higher abstraction. I did have some code that expected these functions to return lists. The flip side was that I sometimes had to wrap in list:
variable = list(map(func, someiter))
In hindsight, I probably should have used list comprehensions for many of those cases as they are more readable...
Use the 'bytes' type instead of 'string' where appropriate. bytes was introduced as a new type in Python 3. In the Rewind case, this mostly involved ZeroMQ message frames handling, that takes bytes. This also involved some conversion to and/or from bytes and string. I tried to stick to UTF-8 for this.
Use 'string.format(...)' instead of 'string % ...' pattern. Nuff said.
In general, Python 3 is very backwards compatible (but Python 2 is not forward compatible). As far as I can recollect, the only conditionals I needed to make Python3 were aliasing of imports:
try: # Python < 3 import ConfigParser as configparser except ImportError: # Python >= 3 import configparser