1.. _compatible-idioms:
2
3Cheat Sheet: Writing Python 2-3 compatible code
4===============================================
5
6-  **Copyright (c):** 2013-2019 Python Charmers Pty Ltd, Australia.
7-  **Author:** Ed Schofield.
8-  **Licence:** Creative Commons Attribution.
9
10A PDF version is here: http://python-future.org/compatible\_idioms.pdf
11
12This notebook shows you idioms for writing future-proof code that is
13compatible with both versions of Python: 2 and 3. It accompanies Ed
14Schofield's talk at PyCon AU 2014, "Writing 2/3 compatible code". (The
15video is here: http://www.youtube.com/watch?v=KOqk8j11aAI&t=10m14s.)
16
17Minimum versions:
18
19-  Python 2: 2.7+
20-  Python 3: 3.4+
21
22Setup
23-----
24
25The imports below refer to these ``pip``-installable packages on PyPI:
26
27::
28
29    import future        # pip install future
30    import builtins      # pip install future
31    import past          # pip install future
32    import six           # pip install six
33
34The following scripts are also ``pip``-installable:
35
36::
37
38    futurize             # pip install future
39    pasteurize           # pip install future
40
41See http://python-future.org and https://pythonhosted.org/six/ for more
42information.
43
44Essential syntax differences
45----------------------------
46
47print
48~~~~~
49
50.. code:: python
51
52    # Python 2 only:
53    print 'Hello'
54.. code:: python
55
56    # Python 2 and 3:
57    print('Hello')
58To print multiple strings, import ``print_function`` to prevent Py2 from
59interpreting it as a tuple:
60
61.. code:: python
62
63    # Python 2 only:
64    print 'Hello', 'Guido'
65.. code:: python
66
67    # Python 2 and 3:
68    from __future__ import print_function    # (at top of module)
69
70    print('Hello', 'Guido')
71.. code:: python
72
73    # Python 2 only:
74    print >> sys.stderr, 'Hello'
75.. code:: python
76
77    # Python 2 and 3:
78    from __future__ import print_function
79
80    print('Hello', file=sys.stderr)
81.. code:: python
82
83    # Python 2 only:
84    print 'Hello',
85.. code:: python
86
87    # Python 2 and 3:
88    from __future__ import print_function
89
90    print('Hello', end='')
91Raising exceptions
92~~~~~~~~~~~~~~~~~~
93
94.. code:: python
95
96    # Python 2 only:
97    raise ValueError, "dodgy value"
98.. code:: python
99
100    # Python 2 and 3:
101    raise ValueError("dodgy value")
102Raising exceptions with a traceback:
103
104.. code:: python
105
106    # Python 2 only:
107    traceback = sys.exc_info()[2]
108    raise ValueError, "dodgy value", traceback
109.. code:: python
110
111    # Python 3 only:
112    raise ValueError("dodgy value").with_traceback()
113.. code:: python
114
115    # Python 2 and 3: option 1
116    from six import reraise as raise_
117    # or
118    from future.utils import raise_
119
120    traceback = sys.exc_info()[2]
121    raise_(ValueError, "dodgy value", traceback)
122.. code:: python
123
124    # Python 2 and 3: option 2
125    from future.utils import raise_with_traceback
126
127    raise_with_traceback(ValueError("dodgy value"))
128Exception chaining (PEP 3134):
129
130.. code:: python
131
132    # Setup:
133    class DatabaseError(Exception):
134        pass
135.. code:: python
136
137    # Python 3 only
138    class FileDatabase:
139        def __init__(self, filename):
140            try:
141                self.file = open(filename)
142            except IOError as exc:
143                raise DatabaseError('failed to open') from exc
144.. code:: python
145
146    # Python 2 and 3:
147    from future.utils import raise_from
148
149    class FileDatabase:
150        def __init__(self, filename):
151            try:
152                self.file = open(filename)
153            except IOError as exc:
154                raise_from(DatabaseError('failed to open'), exc)
155.. code:: python
156
157    # Testing the above:
158    try:
159        fd = FileDatabase('non_existent_file.txt')
160    except Exception as e:
161        assert isinstance(e.__cause__, IOError)    # FileNotFoundError on Py3.3+ inherits from IOError
162Catching exceptions
163~~~~~~~~~~~~~~~~~~~
164
165.. code:: python
166
167    # Python 2 only:
168    try:
169        ...
170    except ValueError, e:
171        ...
172.. code:: python
173
174    # Python 2 and 3:
175    try:
176        ...
177    except ValueError as e:
178        ...
179Division
180~~~~~~~~
181
182Integer division (rounding down):
183
184.. code:: python
185
186    # Python 2 only:
187    assert 2 / 3 == 0
188.. code:: python
189
190    # Python 2 and 3:
191    assert 2 // 3 == 0
192"True division" (float division):
193
194.. code:: python
195
196    # Python 3 only:
197    assert 3 / 2 == 1.5
198.. code:: python
199
200    # Python 2 and 3:
201    from __future__ import division    # (at top of module)
202
203    assert 3 / 2 == 1.5
204"Old division" (i.e. compatible with Py2 behaviour):
205
206.. code:: python
207
208    # Python 2 only:
209    a = b / c            # with any types
210.. code:: python
211
212    # Python 2 and 3:
213    from past.utils import old_div
214
215    a = old_div(b, c)    # always same as / on Py2
216Long integers
217~~~~~~~~~~~~~
218
219Short integers are gone in Python 3 and ``long`` has become ``int``
220(without the trailing ``L`` in the ``repr``).
221
222.. code:: python
223
224    # Python 2 only
225    k = 9223372036854775808L
226
227    # Python 2 and 3:
228    k = 9223372036854775808
229.. code:: python
230
231    # Python 2 only
232    bigint = 1L
233
234    # Python 2 and 3
235    from builtins import int
236    bigint = int(1)
237To test whether a value is an integer (of any kind):
238
239.. code:: python
240
241    # Python 2 only:
242    if isinstance(x, (int, long)):
243        ...
244
245    # Python 3 only:
246    if isinstance(x, int):
247        ...
248
249    # Python 2 and 3: option 1
250    from builtins import int    # subclass of long on Py2
251
252    if isinstance(x, int):             # matches both int and long on Py2
253        ...
254
255    # Python 2 and 3: option 2
256    from past.builtins import long
257
258    if isinstance(x, (int, long)):
259        ...
260Octal constants
261~~~~~~~~~~~~~~~
262
263.. code:: python
264
265    0644     # Python 2 only
266.. code:: python
267
268    0o644    # Python 2 and 3
269Backtick repr
270~~~~~~~~~~~~~
271
272.. code:: python
273
274    `x`      # Python 2 only
275.. code:: python
276
277    repr(x)  # Python 2 and 3
278Metaclasses
279~~~~~~~~~~~
280
281.. code:: python
282
283    class BaseForm(object):
284        pass
285
286    class FormType(type):
287        pass
288.. code:: python
289
290    # Python 2 only:
291    class Form(BaseForm):
292        __metaclass__ = FormType
293        pass
294.. code:: python
295
296    # Python 3 only:
297    class Form(BaseForm, metaclass=FormType):
298        pass
299.. code:: python
300
301    # Python 2 and 3:
302    from six import with_metaclass
303    # or
304    from future.utils import with_metaclass
305
306    class Form(with_metaclass(FormType, BaseForm)):
307        pass
308Strings and bytes
309-----------------
310
311Unicode (text) string literals
312~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
313
314If you are upgrading an existing Python 2 codebase, it may be preferable
315to mark up all string literals as unicode explicitly with ``u``
316prefixes:
317
318.. code:: python
319
320    # Python 2 only
321    s1 = 'The Zen of Python'
322    s2 = u'きたないのよりきれいな方がいい\n'
323
324    # Python 2 and 3
325    s1 = u'The Zen of Python'
326    s2 = u'きたないのよりきれいな方がいい\n'
327The ``futurize`` and ``python-modernize`` tools do not currently offer
328an option to do this automatically.
329
330If you are writing code for a new project or new codebase, you can use
331this idiom to make all string literals in a module unicode strings:
332
333.. code:: python
334
335    # Python 2 and 3
336    from __future__ import unicode_literals    # at top of module
337
338    s1 = 'The Zen of Python'
339    s2 = 'きたないのよりきれいな方がいい\n'
340See http://python-future.org/unicode\_literals.html for more discussion
341on which style to use.
342
343Byte-string literals
344~~~~~~~~~~~~~~~~~~~~
345
346.. code:: python
347
348    # Python 2 only
349    s = 'This must be a byte-string'
350
351    # Python 2 and 3
352    s = b'This must be a byte-string'
353To loop over a byte-string with possible high-bit characters, obtaining
354each character as a byte-string of length 1:
355
356.. code:: python
357
358    # Python 2 only:
359    for bytechar in 'byte-string with high-bit chars like \xf9':
360        ...
361
362    # Python 3 only:
363    for myint in b'byte-string with high-bit chars like \xf9':
364        bytechar = bytes([myint])
365
366    # Python 2 and 3:
367    from builtins import bytes
368    for myint in bytes(b'byte-string with high-bit chars like \xf9'):
369        bytechar = bytes([myint])
370As an alternative, ``chr()`` and ``.encode('latin-1')`` can be used to
371convert an int into a 1-char byte string:
372
373.. code:: python
374
375    # Python 3 only:
376    for myint in b'byte-string with high-bit chars like \xf9':
377        char = chr(myint)    # returns a unicode string
378        bytechar = char.encode('latin-1')
379
380    # Python 2 and 3:
381    from builtins import bytes, chr
382    for myint in bytes(b'byte-string with high-bit chars like \xf9'):
383        char = chr(myint)    # returns a unicode string
384        bytechar = char.encode('latin-1')    # forces returning a byte str
385basestring
386~~~~~~~~~~
387
388.. code:: python
389
390    # Python 2 only:
391    a = u'abc'
392    b = 'def'
393    assert (isinstance(a, basestring) and isinstance(b, basestring))
394
395    # Python 2 and 3: alternative 1
396    from past.builtins import basestring    # pip install future
397
398    a = u'abc'
399    b = b'def'
400    assert (isinstance(a, basestring) and isinstance(b, basestring))
401.. code:: python
402
403    # Python 2 and 3: alternative 2: refactor the code to avoid considering
404    # byte-strings as strings.
405
406    from builtins import str
407    a = u'abc'
408    b = b'def'
409    c = b.decode()
410    assert isinstance(a, str) and isinstance(c, str)
411    # ...
412unicode
413~~~~~~~
414
415.. code:: python
416
417    # Python 2 only:
418    templates = [u"blog/blog_post_detail_%s.html" % unicode(slug)]
419.. code:: python
420
421    # Python 2 and 3: alternative 1
422    from builtins import str
423    templates = [u"blog/blog_post_detail_%s.html" % str(slug)]
424.. code:: python
425
426    # Python 2 and 3: alternative 2
427    from builtins import str as text
428    templates = [u"blog/blog_post_detail_%s.html" % text(slug)]
429StringIO
430~~~~~~~~
431
432.. code:: python
433
434    # Python 2 only:
435    from StringIO import StringIO
436    # or:
437    from cStringIO import StringIO
438
439    # Python 2 and 3:
440    from io import BytesIO     # for handling byte strings
441    from io import StringIO    # for handling unicode strings
442Imports relative to a package
443-----------------------------
444
445Suppose the package is:
446
447::
448
449    mypackage/
450        __init__.py
451        submodule1.py
452        submodule2.py
453
454
455and the code below is in ``submodule1.py``:
456
457.. code:: python
458
459    # Python 2 only:
460    import submodule2
461.. code:: python
462
463    # Python 2 and 3:
464    from . import submodule2
465.. code:: python
466
467    # Python 2 and 3:
468    # To make Py2 code safer (more like Py3) by preventing
469    # implicit relative imports, you can also add this to the top:
470    from __future__ import absolute_import
471Dictionaries
472------------
473
474.. code:: python
475
476    heights = {'Fred': 175, 'Anne': 166, 'Joe': 192}
477Iterating through ``dict`` keys/values/items
478~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
479
480Iterable dict keys:
481
482.. code:: python
483
484    # Python 2 only:
485    for key in heights.iterkeys():
486        ...
487.. code:: python
488
489    # Python 2 and 3:
490    for key in heights:
491        ...
492Iterable dict values:
493
494.. code:: python
495
496    # Python 2 only:
497    for value in heights.itervalues():
498        ...
499.. code:: python
500
501    # Idiomatic Python 3
502    for value in heights.values():    # extra memory overhead on Py2
503        ...
504.. code:: python
505
506    # Python 2 and 3: option 1
507    from builtins import dict
508
509    heights = dict(Fred=175, Anne=166, Joe=192)
510    for key in heights.values():    # efficient on Py2 and Py3
511        ...
512.. code:: python
513
514    # Python 2 and 3: option 2
515    from future.utils import itervalues
516    # or
517    from six import itervalues
518
519    for key in itervalues(heights):
520        ...
521Iterable dict items:
522
523.. code:: python
524
525    # Python 2 only:
526    for (key, value) in heights.iteritems():
527        ...
528.. code:: python
529
530    # Python 2 and 3: option 1
531    for (key, value) in heights.items():    # inefficient on Py2
532        ...
533.. code:: python
534
535    # Python 2 and 3: option 2
536    from future.utils import viewitems
537
538    for (key, value) in viewitems(heights):   # also behaves like a set
539        ...
540.. code:: python
541
542    # Python 2 and 3: option 3
543    from future.utils import iteritems
544    # or
545    from six import iteritems
546
547    for (key, value) in iteritems(heights):
548        ...
549dict keys/values/items as a list
550~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
551
552dict keys as a list:
553
554.. code:: python
555
556    # Python 2 only:
557    keylist = heights.keys()
558    assert isinstance(keylist, list)
559.. code:: python
560
561    # Python 2 and 3:
562    keylist = list(heights)
563    assert isinstance(keylist, list)
564dict values as a list:
565
566.. code:: python
567
568    # Python 2 only:
569    heights = {'Fred': 175, 'Anne': 166, 'Joe': 192}
570    valuelist = heights.values()
571    assert isinstance(valuelist, list)
572.. code:: python
573
574    # Python 2 and 3: option 1
575    valuelist = list(heights.values())    # inefficient on Py2
576.. code:: python
577
578    # Python 2 and 3: option 2
579    from builtins import dict
580
581    heights = dict(Fred=175, Anne=166, Joe=192)
582    valuelist = list(heights.values())
583.. code:: python
584
585    # Python 2 and 3: option 3
586    from future.utils import listvalues
587
588    valuelist = listvalues(heights)
589.. code:: python
590
591    # Python 2 and 3: option 4
592    from future.utils import itervalues
593    # or
594    from six import itervalues
595
596    valuelist = list(itervalues(heights))
597dict items as a list:
598
599.. code:: python
600
601    # Python 2 and 3: option 1
602    itemlist = list(heights.items())    # inefficient on Py2
603.. code:: python
604
605    # Python 2 and 3: option 2
606    from future.utils import listitems
607
608    itemlist = listitems(heights)
609.. code:: python
610
611    # Python 2 and 3: option 3
612    from future.utils import iteritems
613    # or
614    from six import iteritems
615
616    itemlist = list(iteritems(heights))
617Custom class behaviour
618----------------------
619
620Custom iterators
621~~~~~~~~~~~~~~~~
622
623.. code:: python
624
625    # Python 2 only
626    class Upper(object):
627        def __init__(self, iterable):
628            self._iter = iter(iterable)
629        def next(self):          # Py2-style
630            return self._iter.next().upper()
631        def __iter__(self):
632            return self
633
634    itr = Upper('hello')
635    assert itr.next() == 'H'     # Py2-style
636    assert list(itr) == list('ELLO')
637.. code:: python
638
639    # Python 2 and 3: option 1
640    from builtins import object
641
642    class Upper(object):
643        def __init__(self, iterable):
644            self._iter = iter(iterable)
645        def __next__(self):      # Py3-style iterator interface
646            return next(self._iter).upper()  # builtin next() function calls
647        def __iter__(self):
648            return self
649
650    itr = Upper('hello')
651    assert next(itr) == 'H'      # compatible style
652    assert list(itr) == list('ELLO')
653.. code:: python
654
655    # Python 2 and 3: option 2
656    from future.utils import implements_iterator
657
658    @implements_iterator
659    class Upper(object):
660        def __init__(self, iterable):
661            self._iter = iter(iterable)
662        def __next__(self):                  # Py3-style iterator interface
663            return next(self._iter).upper()  # builtin next() function calls
664        def __iter__(self):
665            return self
666
667    itr = Upper('hello')
668    assert next(itr) == 'H'
669    assert list(itr) == list('ELLO')
670Custom ``__str__`` methods
671~~~~~~~~~~~~~~~~~~~~~~~~~~
672
673.. code:: python
674
675    # Python 2 only:
676    class MyClass(object):
677        def __unicode__(self):
678            return 'Unicode string: \u5b54\u5b50'
679        def __str__(self):
680            return unicode(self).encode('utf-8')
681
682    a = MyClass()
683    print(a)    # prints encoded string
684.. code:: python
685
686    # Python 2 and 3:
687    from future.utils import python_2_unicode_compatible
688
689    @python_2_unicode_compatible
690    class MyClass(object):
691        def __str__(self):
692            return u'Unicode string: \u5b54\u5b50'
693
694    a = MyClass()
695    print(a)    # prints string encoded as utf-8 on Py2
696
697.. parsed-literal::
698
699    Unicode string: 孔子
700
701
702Custom ``__nonzero__`` vs ``__bool__`` method:
703~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
704
705.. code:: python
706
707    # Python 2 only:
708    class AllOrNothing(object):
709        def __init__(self, l):
710            self.l = l
711        def __nonzero__(self):
712            return all(self.l)
713
714    container = AllOrNothing([0, 100, 200])
715    assert not bool(container)
716.. code:: python
717
718    # Python 2 and 3:
719    from builtins import object
720
721    class AllOrNothing(object):
722        def __init__(self, l):
723            self.l = l
724        def __bool__(self):
725            return all(self.l)
726
727    container = AllOrNothing([0, 100, 200])
728    assert not bool(container)
729Lists versus iterators
730----------------------
731
732xrange
733~~~~~~
734
735.. code:: python
736
737    # Python 2 only:
738    for i in xrange(10**8):
739        ...
740.. code:: python
741
742    # Python 2 and 3: forward-compatible
743    from builtins import range
744    for i in range(10**8):
745        ...
746.. code:: python
747
748    # Python 2 and 3: backward-compatible
749    from past.builtins import xrange
750    for i in xrange(10**8):
751        ...
752range
753~~~~~
754
755.. code:: python
756
757    # Python 2 only
758    mylist = range(5)
759    assert mylist == [0, 1, 2, 3, 4]
760.. code:: python
761
762    # Python 2 and 3: forward-compatible: option 1
763    mylist = list(range(5))            # copies memory on Py2
764    assert mylist == [0, 1, 2, 3, 4]
765.. code:: python
766
767    # Python 2 and 3: forward-compatible: option 2
768    from builtins import range
769
770    mylist = list(range(5))
771    assert mylist == [0, 1, 2, 3, 4]
772.. code:: python
773
774    # Python 2 and 3: option 3
775    from future.utils import lrange
776
777    mylist = lrange(5)
778    assert mylist == [0, 1, 2, 3, 4]
779.. code:: python
780
781    # Python 2 and 3: backward compatible
782    from past.builtins import range
783
784    mylist = range(5)
785    assert mylist == [0, 1, 2, 3, 4]
786map
787~~~
788
789.. code:: python
790
791    # Python 2 only:
792    mynewlist = map(f, myoldlist)
793    assert mynewlist == [f(x) for x in myoldlist]
794.. code:: python
795
796    # Python 2 and 3: option 1
797    # Idiomatic Py3, but inefficient on Py2
798    mynewlist = list(map(f, myoldlist))
799    assert mynewlist == [f(x) for x in myoldlist]
800.. code:: python
801
802    # Python 2 and 3: option 2
803    from builtins import map
804
805    mynewlist = list(map(f, myoldlist))
806    assert mynewlist == [f(x) for x in myoldlist]
807.. code:: python
808
809    # Python 2 and 3: option 3
810    try:
811        import itertools.imap as map
812    except ImportError:
813        pass
814
815    mynewlist = list(map(f, myoldlist))    # inefficient on Py2
816    assert mynewlist == [f(x) for x in myoldlist]
817.. code:: python
818
819    # Python 2 and 3: option 4
820    from future.utils import lmap
821
822    mynewlist = lmap(f, myoldlist)
823    assert mynewlist == [f(x) for x in myoldlist]
824.. code:: python
825
826    # Python 2 and 3: option 5
827    from past.builtins import map
828
829    mynewlist = map(f, myoldlist)
830    assert mynewlist == [f(x) for x in myoldlist]
831imap
832~~~~
833
834.. code:: python
835
836    # Python 2 only:
837    from itertools import imap
838
839    myiter = imap(func, myoldlist)
840    assert isinstance(myiter, iter)
841.. code:: python
842
843    # Python 3 only:
844    myiter = map(func, myoldlist)
845    assert isinstance(myiter, iter)
846.. code:: python
847
848    # Python 2 and 3: option 1
849    from builtins import map
850
851    myiter = map(func, myoldlist)
852    assert isinstance(myiter, iter)
853.. code:: python
854
855    # Python 2 and 3: option 2
856    try:
857        import itertools.imap as map
858    except ImportError:
859        pass
860
861    myiter = map(func, myoldlist)
862    assert isinstance(myiter, iter)
863.. code:: python
864
865    # Python 2 and 3: option 3
866    from six.moves import map
867
868    myiter = map(func, myoldlist)
869    assert isinstance(myiter, iter)
870
871zip, izip
872~~~~~~~~~
873
874As above with ``zip`` and ``itertools.izip``.
875
876filter, ifilter
877~~~~~~~~~~~~~~~
878
879As above with ``filter`` and ``itertools.ifilter`` too.
880
881Other builtins
882--------------
883
884File IO with open()
885~~~~~~~~~~~~~~~~~~~
886
887.. code:: python
888
889    # Python 2 only
890    f = open('myfile.txt')
891    data = f.read()              # as a byte string
892    text = data.decode('utf-8')
893
894    # Python 2 and 3: alternative 1
895    from io import open
896    f = open('myfile.txt', 'rb')
897    data = f.read()              # as bytes
898    text = data.decode('utf-8')  # unicode, not bytes
899
900    # Python 2 and 3: alternative 2
901    from io import open
902    f = open('myfile.txt', encoding='utf-8')
903    text = f.read()    # unicode, not bytes
904reduce()
905~~~~~~~~
906
907.. code:: python
908
909    # Python 2 only:
910    assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5
911.. code:: python
912
913    # Python 2 and 3:
914    from functools import reduce
915
916    assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5
917raw\_input()
918~~~~~~~~~~~~
919
920.. code:: python
921
922    # Python 2 only:
923    name = raw_input('What is your name? ')
924    assert isinstance(name, str)    # native str
925.. code:: python
926
927    # Python 2 and 3:
928    from builtins import input
929
930    name = input('What is your name? ')
931    assert isinstance(name, str)    # native str on Py2 and Py3
932input()
933~~~~~~~
934
935.. code:: python
936
937    # Python 2 only:
938    input("Type something safe please: ")
939.. code:: python
940
941    # Python 2 and 3
942    from builtins import input
943    eval(input("Type something safe please: "))
944Warning: using either of these is **unsafe** with untrusted input.
945
946file()
947~~~~~~
948
949.. code:: python
950
951    # Python 2 only:
952    f = file(pathname)
953.. code:: python
954
955    # Python 2 and 3:
956    f = open(pathname)
957
958    # But preferably, use this:
959    from io import open
960    f = open(pathname, 'rb')   # if f.read() should return bytes
961    # or
962    f = open(pathname, 'rt')   # if f.read() should return unicode text
963exec
964~~~~
965
966.. code:: python
967
968    # Python 2 only:
969    exec 'x = 10'
970
971    # Python 2 and 3:
972    exec('x = 10')
973.. code:: python
974
975    # Python 2 only:
976    g = globals()
977    exec 'x = 10' in g
978
979    # Python 2 and 3:
980    g = globals()
981    exec('x = 10', g)
982.. code:: python
983
984    # Python 2 only:
985    l = locals()
986    exec 'x = 10' in g, l
987
988    # Python 2 and 3:
989    exec('x = 10', g, l)
990execfile()
991~~~~~~~~~~
992
993.. code:: python
994
995    # Python 2 only:
996    execfile('myfile.py')
997.. code:: python
998
999    # Python 2 and 3: alternative 1
1000    from past.builtins import execfile
1001
1002    execfile('myfile.py')
1003.. code:: python
1004
1005    # Python 2 and 3: alternative 2
1006    exec(compile(open('myfile.py').read()))
1007
1008    # This can sometimes cause this:
1009    #     SyntaxError: function ... uses import * and bare exec ...
1010    # See https://github.com/PythonCharmers/python-future/issues/37
1011unichr()
1012~~~~~~~~
1013
1014.. code:: python
1015
1016    # Python 2 only:
1017    assert unichr(8364) == '€'
1018.. code:: python
1019
1020    # Python 3 only:
1021    assert chr(8364) == '€'
1022.. code:: python
1023
1024    # Python 2 and 3:
1025    from builtins import chr
1026    assert chr(8364) == '€'
1027intern()
1028~~~~~~~~
1029
1030.. code:: python
1031
1032    # Python 2 only:
1033    intern('mystring')
1034.. code:: python
1035
1036    # Python 3 only:
1037    from sys import intern
1038    intern('mystring')
1039.. code:: python
1040
1041    # Python 2 and 3: alternative 1
1042    from past.builtins import intern
1043    intern('mystring')
1044.. code:: python
1045
1046    # Python 2 and 3: alternative 2
1047    from six.moves import intern
1048    intern('mystring')
1049.. code:: python
1050
1051    # Python 2 and 3: alternative 3
1052    from future.standard_library import install_aliases
1053    install_aliases()
1054    from sys import intern
1055    intern('mystring')
1056.. code:: python
1057
1058    # Python 2 and 3: alternative 2
1059    try:
1060        from sys import intern
1061    except ImportError:
1062        pass
1063    intern('mystring')
1064apply()
1065~~~~~~~
1066
1067.. code:: python
1068
1069    args = ('a', 'b')
1070    kwargs = {'kwarg1': True}
1071.. code:: python
1072
1073    # Python 2 only:
1074    apply(f, args, kwargs)
1075.. code:: python
1076
1077    # Python 2 and 3: alternative 1
1078    f(*args, **kwargs)
1079.. code:: python
1080
1081    # Python 2 and 3: alternative 2
1082    from past.builtins import apply
1083    apply(f, args, kwargs)
1084chr()
1085~~~~~
1086
1087.. code:: python
1088
1089    # Python 2 only:
1090    assert chr(64) == b'@'
1091    assert chr(200) == b'\xc8'
1092.. code:: python
1093
1094    # Python 3 only: option 1
1095    assert chr(64).encode('latin-1') == b'@'
1096    assert chr(0xc8).encode('latin-1') == b'\xc8'
1097.. code:: python
1098
1099    # Python 2 and 3: option 1
1100    from builtins import chr
1101
1102    assert chr(64).encode('latin-1') == b'@'
1103    assert chr(0xc8).encode('latin-1') == b'\xc8'
1104.. code:: python
1105
1106    # Python 3 only: option 2
1107    assert bytes([64]) == b'@'
1108    assert bytes([0xc8]) == b'\xc8'
1109.. code:: python
1110
1111    # Python 2 and 3: option 2
1112    from builtins import bytes
1113
1114    assert bytes([64]) == b'@'
1115    assert bytes([0xc8]) == b'\xc8'
1116cmp()
1117~~~~~
1118
1119.. code:: python
1120
1121    # Python 2 only:
1122    assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0
1123.. code:: python
1124
1125    # Python 2 and 3: alternative 1
1126    from past.builtins import cmp
1127    assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0
1128.. code:: python
1129
1130    # Python 2 and 3: alternative 2
1131    cmp = lambda(x, y): (x > y) - (x < y)
1132    assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0
1133reload()
1134~~~~~~~~
1135
1136.. code:: python
1137
1138    # Python 2 only:
1139    reload(mymodule)
1140.. code:: python
1141
1142    # Python 2 and 3
1143    from imp import reload
1144    reload(mymodule)
1145Standard library
1146----------------
1147
1148dbm modules
1149~~~~~~~~~~~
1150
1151.. code:: python
1152
1153    # Python 2 only
1154    import anydbm
1155    import whichdb
1156    import dbm
1157    import dumbdbm
1158    import gdbm
1159
1160    # Python 2 and 3: alternative 1
1161    from future import standard_library
1162    standard_library.install_aliases()
1163
1164    import dbm
1165    import dbm.ndbm
1166    import dbm.dumb
1167    import dbm.gnu
1168
1169    # Python 2 and 3: alternative 2
1170    from future.moves import dbm
1171    from future.moves.dbm import dumb
1172    from future.moves.dbm import ndbm
1173    from future.moves.dbm import gnu
1174
1175    # Python 2 and 3: alternative 3
1176    from six.moves import dbm_gnu
1177    # (others not supported)
1178commands / subprocess modules
1179~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1180
1181.. code:: python
1182
1183    # Python 2 only
1184    from commands import getoutput, getstatusoutput
1185
1186    # Python 2 and 3
1187    from future import standard_library
1188    standard_library.install_aliases()
1189
1190    from subprocess import getoutput, getstatusoutput
1191StringIO module
1192~~~~~~~~~~~~~~~
1193
1194.. code:: python
1195
1196    # Python 2 only
1197    from StringIO import StringIO
1198    from cStringIO import StringIO
1199.. code:: python
1200
1201    # Python 2 and 3
1202    from io import BytesIO
1203    # and refactor StringIO() calls to BytesIO() if passing byte-strings
1204http module
1205~~~~~~~~~~~
1206
1207.. code:: python
1208
1209    # Python 2 only:
1210    import httplib
1211    import Cookie
1212    import cookielib
1213    import BaseHTTPServer
1214    import SimpleHTTPServer
1215    import CGIHttpServer
1216
1217    # Python 2 and 3 (after ``pip install future``):
1218    import http.client
1219    import http.cookies
1220    import http.cookiejar
1221    import http.server
1222xmlrpc module
1223~~~~~~~~~~~~~
1224
1225.. code:: python
1226
1227    # Python 2 only:
1228    import DocXMLRPCServer
1229    import SimpleXMLRPCServer
1230
1231    # Python 2 and 3 (after ``pip install future``):
1232    import xmlrpc.server
1233.. code:: python
1234
1235    # Python 2 only:
1236    import xmlrpclib
1237
1238    # Python 2 and 3 (after ``pip install future``):
1239    import xmlrpc.client
1240html escaping and entities
1241~~~~~~~~~~~~~~~~~~~~~~~~~~
1242
1243.. code:: python
1244
1245    # Python 2 and 3:
1246    from cgi import escape
1247
1248    # Safer (Python 2 and 3, after ``pip install future``):
1249    from html import escape
1250
1251    # Python 2 only:
1252    from htmlentitydefs import codepoint2name, entitydefs, name2codepoint
1253
1254    # Python 2 and 3 (after ``pip install future``):
1255    from html.entities import codepoint2name, entitydefs, name2codepoint
1256html parsing
1257~~~~~~~~~~~~
1258
1259.. code:: python
1260
1261    # Python 2 only:
1262    from HTMLParser import HTMLParser
1263
1264    # Python 2 and 3 (after ``pip install future``)
1265    from html.parser import HTMLParser
1266
1267    # Python 2 and 3 (alternative 2):
1268    from future.moves.html.parser import HTMLParser
1269urllib module
1270~~~~~~~~~~~~~
1271
1272``urllib`` is the hardest module to use from Python 2/3 compatible code.
1273You might want to switch to Requests (http://python-requests.org) instead.
1274
1275.. code:: python
1276
1277    # Python 2 only:
1278    from urlparse import urlparse
1279    from urllib import urlencode
1280    from urllib2 import urlopen, Request, HTTPError
1281.. code:: python
1282
1283    # Python 3 only:
1284    from urllib.parse import urlparse, urlencode
1285    from urllib.request import urlopen, Request
1286    from urllib.error import HTTPError
1287.. code:: python
1288
1289    # Python 2 and 3: easiest option
1290    from future.standard_library import install_aliases
1291    install_aliases()
1292
1293    from urllib.parse import urlparse, urlencode
1294    from urllib.request import urlopen, Request
1295    from urllib.error import HTTPError
1296.. code:: python
1297
1298    # Python 2 and 3: alternative 2
1299    from future.standard_library import hooks
1300
1301    with hooks():
1302        from urllib.parse import urlparse, urlencode
1303        from urllib.request import urlopen, Request
1304        from urllib.error import HTTPError
1305.. code:: python
1306
1307    # Python 2 and 3: alternative 3
1308    from future.moves.urllib.parse import urlparse, urlencode
1309    from future.moves.urllib.request import urlopen, Request
1310    from future.moves.urllib.error import HTTPError
1311    # or
1312    from six.moves.urllib.parse import urlparse, urlencode
1313    from six.moves.urllib.request import urlopen
1314    from six.moves.urllib.error import HTTPError
1315.. code:: python
1316
1317    # Python 2 and 3: alternative 4
1318    try:
1319        from urllib.parse import urlparse, urlencode
1320        from urllib.request import urlopen, Request
1321        from urllib.error import HTTPError
1322    except ImportError:
1323        from urlparse import urlparse
1324        from urllib import urlencode
1325        from urllib2 import urlopen, Request, HTTPError
1326Tkinter
1327~~~~~~~
1328
1329.. code:: python
1330
1331    # Python 2 only:
1332    import Tkinter
1333    import Dialog
1334    import FileDialog
1335    import ScrolledText
1336    import SimpleDialog
1337    import Tix
1338    import Tkconstants
1339    import Tkdnd
1340    import tkColorChooser
1341    import tkCommonDialog
1342    import tkFileDialog
1343    import tkFont
1344    import tkMessageBox
1345    import tkSimpleDialog
1346    import ttk
1347
1348    # Python 2 and 3 (after ``pip install future``):
1349    import tkinter
1350    import tkinter.dialog
1351    import tkinter.filedialog
1352    import tkinter.scrolledtext
1353    import tkinter.simpledialog
1354    import tkinter.tix
1355    import tkinter.constants
1356    import tkinter.dnd
1357    import tkinter.colorchooser
1358    import tkinter.commondialog
1359    import tkinter.filedialog
1360    import tkinter.font
1361    import tkinter.messagebox
1362    import tkinter.simpledialog
1363    import tkinter.ttk
1364socketserver
1365~~~~~~~~~~~~
1366
1367.. code:: python
1368
1369    # Python 2 only:
1370    import SocketServer
1371
1372    # Python 2 and 3 (after ``pip install future``):
1373    import socketserver
1374copy\_reg, copyreg
1375~~~~~~~~~~~~~~~~~~
1376
1377.. code:: python
1378
1379    # Python 2 only:
1380    import copy_reg
1381
1382    # Python 2 and 3 (after ``pip install future``):
1383    import copyreg
1384configparser
1385~~~~~~~~~~~~
1386
1387.. code:: python
1388
1389    # Python 2 only:
1390    from ConfigParser import ConfigParser
1391
1392    # Python 2 and 3 (after ``pip install configparser``):
1393    from configparser import ConfigParser
1394queue
1395~~~~~
1396
1397.. code:: python
1398
1399    # Python 2 only:
1400    from Queue import Queue, heapq, deque
1401
1402    # Python 2 and 3 (after ``pip install future``):
1403    from queue import Queue, heapq, deque
1404repr, reprlib
1405~~~~~~~~~~~~~
1406
1407.. code:: python
1408
1409    # Python 2 only:
1410    from repr import aRepr, repr
1411
1412    # Python 2 and 3 (after ``pip install future``):
1413    from reprlib import aRepr, repr
1414UserDict, UserList, UserString
1415~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1416
1417.. code:: python
1418
1419    # Python 2 only:
1420    from UserDict import UserDict
1421    from UserList import UserList
1422    from UserString import UserString
1423
1424    # Python 3 only:
1425    from collections import UserDict, UserList, UserString
1426
1427    # Python 2 and 3: alternative 1
1428    from future.moves.collections import UserDict, UserList, UserString
1429
1430    # Python 2 and 3: alternative 2
1431    from six.moves import UserDict, UserList, UserString
1432
1433    # Python 2 and 3: alternative 3
1434    from future.standard_library import install_aliases
1435    install_aliases()
1436    from collections import UserDict, UserList, UserString
1437itertools: filterfalse, zip\_longest
1438~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1439
1440.. code:: python
1441
1442    # Python 2 only:
1443    from itertools import ifilterfalse, izip_longest
1444
1445    # Python 3 only:
1446    from itertools import filterfalse, zip_longest
1447
1448    # Python 2 and 3: alternative 1
1449    from future.moves.itertools import filterfalse, zip_longest
1450
1451    # Python 2 and 3: alternative 2
1452    from six.moves import filterfalse, zip_longest
1453
1454    # Python 2 and 3: alternative 3
1455    from future.standard_library import install_aliases
1456    install_aliases()
1457    from itertools import filterfalse, zip_longest
1458