Writing portable python code

Portable python

When writing python code I try to write code which will run both on python2 and python3. Below is a list of items I regularly use.

I know there is a module named ‘six’ which probably also handles some of these cases, I still need to look into that.

Detecting version

There are several ways of detecting the python version:

platform.python_version() < '3.0'

sys.version_info[0] == 2

sys.version_info < (3, 0)

try:
   import mod1
except:
   import mod2

try:
   name
except NameError:
   name = something

__future__

from __future__ import division, print_function

StringIO

if sys.version_info[0] == 2:
    from StringIO import StringIO
else:
    from io import StringIO
    from io import BytesIO

long

if sys.version_info[0] == 3:
    long = int

stdin

if sys.version_info[0] == 2:
    stdin = sys.stdin
else:
    stdin = sys.stdin.buffer

xrange

if sys.version_info[0] == 3:
    xrange = range

reload

if sys.version_info[0] == 3:
    import imp
    reload = imp.reload

builtins

if sys.version_info[0] == 2:
    import __builtin__
else:
    import builtins as __builtin__

utf8

if sys.version_info[0] == 2:
    reload(sys)
    sys.setdefaultencoding('utf-8')

bytes

if sys.version_info[0] == 2:
    bytes = bytearray

unicode

if sys.version_info[0] == 3:
    unicode = str

single byte

bytes((a,))

or

struct.pack("B", a)

join bytearrays

in python3 this is no problem, in python2 it does not work.

characters

Use slices instead of a single index to access single bytes:

if data[1:2] == b'a':
    print("the 2nd byte is an 'a'")

unittest2

if sys.version_info < (2, 7):
    import unittest2 as unittest
else:
    import unittest

ConfigParser

if sys.version_info[0] == 2:
    from ConfigParser import ConfigParser
else:
    from configparser import ConfigParser

urlopen

if sys.version_info[0] == 2:
    from urllib2 import urlopen
else:
    from urllib.request import urlopen

Request

if sys.version_info[0] == 3:
    import urllib.request
    from urllib.request import Request
    urllib2 = urllib.request
else:
    import urllib2
    from urllib2 import Request

start_new_thread

if sys.version_info[0] == 2:
    from thread import start_new_thread
else:
    from _thread import start_new_thread

scandir

import os
if sys.version_info[0] == 2:
    import scandir
    os.scandir= scandir.scandir

iterators

def next(self): return self.__next__()

print

In python2 print will eval and print arguments in order, while in python3 all arguments are evaluated first, and then printed. Even with __future__.print_function

datetime.timezone.utc

if sys.version_info[0] == 2:
    stdin = sys.stdin
    class DummyTimezone:
        class UTC(datetime.tzinfo):
            def utcoffset(self, dt): return timedelta(minutes=-399)
        utc = UTC()
    datetime.timezone = DummyTimezone