Porting to Python 3 by updating to modern Python 2
For quixotic reasons I decided to take a shot at porting DWiki to Python 3 just to see how difficult and annoying it would be and how far I could get. One of the surprising things about the process has been that a great deal of porting to Python 3 has been less about porting the code and more about modernizing it to current Python 2 standards.
DWiki is what is now a pretty old codebase (as you might guess) and even when it was new it wasn't written with the latest Python idioms for various reasons, including that I started with Python back in the Python 1.5 era. As a result it contained a number of long obsolete idioms that are very much not supported in Python 3 and had to be changed. Once the dust settled it turned out that modernizing these idioms was most (although not all) of what was needed to make DWiki at least start up under Python 3.
At this point you might be wondering just what ancient idioms I was still using. I'm glad you asked. DWiki was doing all of these:
raise EXCEPTION, STR' instead of '
raise E(STR)'. I have no real excuse here; I'm sure this was considered obsolete even when I started writing DWiki.
except CLS, VAR:' instead of '
except CLS as VAR:', which I think is at least less ancient than my
- using comparison functions in
reverse=True. Switching made things clearer.
- dividing two integers with '
/' and expecting the result to be an integer. In Python 3 this is an exact float instead, which caused an interesting bug when I used the result as an (integer) counter. Using '
//' explicitly is better and is needed in Python 3.
I consider this modernization of the Python 2 codebase to be a good thing. Even if I never do anything with a Python 3 version of DWiki, updating to the current best practice idioms is an improvement of the code (especially since it's public and I'd like it to not be too embarrassing). I'm glad that trying out a Python 3 port has pushed me into doing this; it really has been overdue.
(Another gotcha that Python 3 exposed is that in at least one place
I was assuming that '
None > 0' was a valid comparison to make and
False. This works in Python 2 but it's not exactly a
good idea and fixing the code to explicitly check for
None is a
good cleanup. Since this sort of stuff can only really be checked
dynamically there may be other spots that do this.)