Recently, the DMOJ judge codebase has been migrated to Python 3, thanks to the combined efforts of me, Xyene, and kiritofeng. Many issues, such as unicode handling were exposed in the process.

Since Python 2 is still in heavy use, at least in the deployment of the DMOJ judge, compatibility with it must be maintained. This necessitated writing code in such a fashion as to be compatible with both Python 2 and Python 3. The six library has proved tremendously helpful in abstracting away the differences, some of which highly non-trivial.

For example, six.with_metaclass hides away the difference in metaclass use. In Python 2, the __metaclass__ class member defines the metaclass used for the class, while in Python 3, one would specify it as class Class(metaclass=MetaClass). The latter would be a syntax error in Python 2, and the former has no effect in Python 3. six provides a solution that is highly non-obvious and yet works perfectly.

The most frustrating part is unicode-handling. The DMOJ judge was written somewhat sloppily in regards to unicode handling, dealing mostly with bytestrings and raw bytes. With the separation of bytes and str in Python 3, strings in the judge must be turned into either bytes or str on a case-by-case basis. It is decided that source code and program output will be treated as raw bytes, and textual data that are derived from these will be handled as UTF-8.