dnanexus/dx-toolkit — pull request #57 by kislyuk (2014-01-03 20:19:49+00:00)
Title: Python 3.3 compatibility

This PR is a heads up to @psung and @kjlai on style changes necessary to engineer a unified codebase that supports both Python 2.7 and 3.3 simultaneously (we will not support Python 3.0-3.2). I will use this readme to collect notes that we'll later put into the Python style section at https://github.com/dnanexus/dx-toolkit/blob/master/src/python/Readme.md. The changes in this PR don't introduce full compatibility, but allow installation of dxpy in Python 3.3 and some basic commands; the main objective is to keep the changeset small and shake out any bugs this may introduce in 2.7 (the most critical potential for bugs is in the handling of unicode/byte strings and their conversions).

I'll add a test suite to Jenkins shortly that will alert on Python 3.3 compatibility breakage.

Notes:
- A new module, `dxpy.compat`, has some simple shims that mirror Python 3.3 builtins and redirect them to Python 2.7 equivalents when on 2.7. Most critically, `from dxpy.compat import str` will import the `unicode` builtin on 2.7 and the `str` builtin on 3.3. To convert unicode strings to bytes, use `.encode('utf-8')`.
- Use `from __future__ import print_function` and use print as a function. Instead of `print >>sys.stderr`, write `print(..., file=sys.stderr)`.
- The next most troublesome gotcha after the bytes/unicode conversions is that many iterables operators return generators in Python 3. For example, `map()` returns a generator. This breaks places that expect a list, and requires either explicit casting with `list()`, or the use of list comprehensions (usually preferred).
- Instead of `raw_input`, use `from dxpy.compat import input`.
- Instead of `.iteritems()`, use `.items()`. If this is a performance concern on 2.7, introduce a shim in compat.py.
- Instead of `StringIO.StringIO`, use `from dxpy.compat import BytesIO` (which is StringIO on 2.7).
- Instead of `.next()`, use `from dxpy.compat import next` and `next()`.
- Instead of `x.has_key(y)`, use `y in x`.
- Instead of `sort(x, cmp=lambda x, y: ...), use x=sorted(x, key=lambda x: ...)`.

Please let me know if you see any issues.