3.3. Python3 compatibility

A good place to start looking for advice to ensure that any code is compatible with both Python-3.x and Python2.6/2.7 is too look at the python-future cheat sheet . Buildbot uses the python-future library to ensure compatibility with both Python2.6/2.7 and Python3.x.

3.3.1. Imports

All __future__ import have to happen at the top of the module, anything else is seen as a syntax error. All imports from the python-future package should happen below __future__ imports, but before any other.

Yes:

from __future__ import print_function
from twisted.application import internet
from twisted.spread import pb

No:

from twisted.application import internet
from twisted.spread import pb
from __future__ import print_function

3.3.2. Dictionaries

In python3, dict.iteritems is no longer available. While dict.items() does exist, it can be memory intensive in python2. For this reason, please use the python.future function iteritems().

Example:

d = {"cheese": 4, "bread": 5, "milk": 1}
for item, num in d.iteritems():
    print("We have {} {}".format(num, item))

should be written as:

from future.utils import iteritems
d = {"cheese": 4, "bread": 5, "milk": 1}
for item, num in iteritems(d):
    print("We have {} {}".format(num, item))

This also applies to the similar methods dict.itervalues() and dict.values(), which have an equivalent itervalues().

If a list is required, please use list(iteritems(dict)). This is for compatibility with the six library.

For iterating over dictionary keys, please use for key in dict:. For example:

d = {"cheese": 4, "bread": 5, "milk": 1}
for item in d:
    print("We have {}".format(item))

Similarly when you want a list of keys:

keys = list(d)

3.3.3. New-style classes

All classes in Python3 are newstyle, so any classes added to the code base must therefore be new-style. This is done by inheriting object

Old-style:

class Foo:
    def __init__(self, bar)
        self.bar = bar

new-style:

class Foo(object):
    def __init__(self, bar)
        self.bar = bar

When creating new-style classes, it is advised to import object from the builtins module. The reasoning for this can be read in the python-future documentation

3.3.4. Strings

Note

This has not yet been implemented in the current code base, and will not be strictly adhered to yet. But it is important to keep in mind when writing code, that there is a strict distinction between bytestrings and unicode in Python3’

In python2, there is only one type of string. It can be both unicode and bytestring. In python3, this is no longer the case. For this reasons all string must be marked with either u'' or b'' to signify if the string is a unicode string or a bytestring respectively

Example:

u'this is a unicode string, a string for humans to read'
b'This is a bytestring, a string for computers to read'

3.3.5. Exceptions

All exceptions should be written with the as statement. Before:

try:
    number = 5 / 0
except ZeroDivisionError, err:
    print(err.msg)

After:

try:
    number = 5/0
except ZeroDivisionError as err:
    print(err.msg)

3.3.6. Basestring

In Python2 there is a basestring type, which both str and unicode inherit. In Python3, only unicode should be of this type, while bytestrings are type(byte).

For this reason, we use an import from python future. Before:

s = "this is a string"
if(isinstance(s, basestring)):
    print "This line will run"

After:

from future.utils import text_type
unicode_s = u"this is a unicode string"
byte_s = b"this is a bytestring"

if(isinstance(unicode_s, text_type)):
    print("This line will print")
if(isinstance(unicode_s, bytes)):
    print("this line will not print")
if(isinstance(unicode_s, (text_type, bytes))):
    print("This line will print")
if(isinstance(byte_s, text_type):
    print("this line will not print")
if(isinstance(byte_s, bytes):
    print("This line will print")
if(isinstance(byte_s, (text_type, bytes)):
    print("This line will print")

3.3.8. Division

Integer division is slightly different in Python3. // is integer division and / is floating point division. For this reason, we use division from the future module. Before:

2 / 3 = 0

After:

from __future__ import division

2 / 3 = 1.5
2 // 3 = 0

3.3.9. Types

The types standard library has changed in Python3. Please make sure to read the official documentation for the library and adapt accordingly