-
Notifications
You must be signed in to change notification settings - Fork 140
Write py2py3 compatible code
#Write py2py3 compatible code on pyDAL
pyDAL aims to be compatible with several python versions, from python 2.6.x to python 3.x
In order to guarantee an easy development for the contributors, pyDAL integrates the _compat module, and the main development team has wrote down these guidelines that should be followed in contributing to the project.
When you need to check the python version, or separate some code blocks from python 2 to python 3, you should use the PY2
boolean variable, as follows:
from ._compat import PY2
if PY2:
# some python 2 code
else:
# some python 3 code
As you may know, with python 3 the dict
methods iterkeys
, itervalues
and iteritems
are no longer available, since now keys
, values
and items
return dynamic objects instead of lists.
When you need to use an iterator, you should use the provided functions of _compat:
from ._compat import iterkeys, itervalues, iteritems
d = dict()
for k in iterkeys(d):
# some code
for v in itervalues(d):
# some code
for k, v in iteritems(d):
# some code
Also, when you need to work with copied lists from a dictionary, and want the behavior to be the same both on python 2 and python 3, you should write:
d = dict()
keys = list(d)
values = list(d.values())
items = list(d.items())
In python3 there's no type for python 2 long
. So, when you need to work with longs in python2 and get the same code working on python 3, you should import integer_types
from _compat and define long
:
from ._compat import integer_types
long = integer_types[-1]
In python 3 you don't have range
and xrange
anymore. You only have range
that behaves as the python 2 xrange
. So, when you work with xrange in python 2, ensure to import it from _compat:
from ._compat import xrange
In python 2 you can implements an iterator and a boolean with next
and __nonzero__
methods.
In python 3 you have the better named methods __next__
and __bool__
.
When you need to implements these methods in classes inside pydal, you should use the python 3 notation and import the implements_iterator
and implements_bool
decorators from _compat:
from ._compat import implements_iterator, implements_bool
@implements_iterator
@implements_bool
class MyClass(object):
def __next__(self):
# iterator code
def __bool__(self):
# boolean code
In python 2 you can implement a type on a class using the __metaclass__
attribute. This is no longer an option in python 3.
When you need to implement a metaclass in pyDAL, you should use the with_metaclass
method of _compat:
from ._compat import with_metaclass
class MyMetaclass(type):
# code
class MyClass(with_metaclass(MyMetaclass)):
# code
You can also do sub-classing using with_metaclass
:
class A(object):
# code
class B(object):
# code
class C(with_metaclass(MyMetaclass, A)):
# code
class D(with_metaclass(MyMetaclass, A, B)):
# code
Since in python 3 everything changed regarding bytes/unicode, pyDAL has some helpers in _compat module to help you writing compatible code on both sides:
-
string_types
is a tuple containing the proper string types -
basestring
gives you the same behavior of python 2 in python 3 -
to_unicode(obj)
method helps you convert objects to unicode in both language versions
Also, you may need to compute md5 hashes, and you will find the hashlib_md5
method in _compat which converts objects to the right format in both versions.
With python3 these libraries have changed in names, or are available in different packages from python 2. Due to this, when you need them, you can import them from the _compat module and use them as normal:
from ._compat import pickle
from ._compat import StringIO
from ._compat import copyreg