summaryrefslogtreecommitdiffstats
path: root/FOSS/Python/Dependencies/future-0.18.2/docs/compatible_idioms.rst
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2023-01-01 21:05:27 -0800
committeryum <yum.food.vr@gmail.com>2023-01-01 21:44:45 -0800
commite25bdba3a3a53b09be5269d8b065c13b73ab55c3 (patch)
tree1d1dc1d94cde92c2f4f8ce86017395054787515d /FOSS/Python/Dependencies/future-0.18.2/docs/compatible_idioms.rst
parent0d408cc812a094a708edbe4baf536e928731cfc3 (diff)
Embed git in package
package.ps1 fetches PortableGit and embeds it in the package. This eliminates all but one runtime dependency (MSVC++ Redistributable). * Move Python into a new FOSS folder.
Diffstat (limited to 'FOSS/Python/Dependencies/future-0.18.2/docs/compatible_idioms.rst')
-rw-r--r--FOSS/Python/Dependencies/future-0.18.2/docs/compatible_idioms.rst1457
1 files changed, 1457 insertions, 0 deletions
diff --git a/FOSS/Python/Dependencies/future-0.18.2/docs/compatible_idioms.rst b/FOSS/Python/Dependencies/future-0.18.2/docs/compatible_idioms.rst
new file mode 100644
index 0000000..b0cb05a
--- /dev/null
+++ b/FOSS/Python/Dependencies/future-0.18.2/docs/compatible_idioms.rst
@@ -0,0 +1,1457 @@
+.. _compatible-idioms:
+
+Cheat Sheet: Writing Python 2-3 compatible code
+===============================================
+
+- **Copyright (c):** 2013-2019 Python Charmers Pty Ltd, Australia.
+- **Author:** Ed Schofield.
+- **Licence:** Creative Commons Attribution.
+
+A PDF version is here: http://python-future.org/compatible\_idioms.pdf
+
+This notebook shows you idioms for writing future-proof code that is
+compatible with both versions of Python: 2 and 3. It accompanies Ed
+Schofield's talk at PyCon AU 2014, "Writing 2/3 compatible code". (The
+video is here: http://www.youtube.com/watch?v=KOqk8j11aAI&t=10m14s.)
+
+Minimum versions:
+
+- Python 2: 2.7+
+- Python 3: 3.4+
+
+Setup
+-----
+
+The imports below refer to these ``pip``-installable packages on PyPI:
+
+::
+
+ import future # pip install future
+ import builtins # pip install future
+ import past # pip install future
+ import six # pip install six
+
+The following scripts are also ``pip``-installable:
+
+::
+
+ futurize # pip install future
+ pasteurize # pip install future
+
+See http://python-future.org and https://pythonhosted.org/six/ for more
+information.
+
+Essential syntax differences
+----------------------------
+
+print
+~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ print 'Hello'
+.. code:: python
+
+ # Python 2 and 3:
+ print('Hello')
+To print multiple strings, import ``print_function`` to prevent Py2 from
+interpreting it as a tuple:
+
+.. code:: python
+
+ # Python 2 only:
+ print 'Hello', 'Guido'
+.. code:: python
+
+ # Python 2 and 3:
+ from __future__ import print_function # (at top of module)
+
+ print('Hello', 'Guido')
+.. code:: python
+
+ # Python 2 only:
+ print >> sys.stderr, 'Hello'
+.. code:: python
+
+ # Python 2 and 3:
+ from __future__ import print_function
+
+ print('Hello', file=sys.stderr)
+.. code:: python
+
+ # Python 2 only:
+ print 'Hello',
+.. code:: python
+
+ # Python 2 and 3:
+ from __future__ import print_function
+
+ print('Hello', end='')
+Raising exceptions
+~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ raise ValueError, "dodgy value"
+.. code:: python
+
+ # Python 2 and 3:
+ raise ValueError("dodgy value")
+Raising exceptions with a traceback:
+
+.. code:: python
+
+ # Python 2 only:
+ traceback = sys.exc_info()[2]
+ raise ValueError, "dodgy value", traceback
+.. code:: python
+
+ # Python 3 only:
+ raise ValueError("dodgy value").with_traceback()
+.. code:: python
+
+ # Python 2 and 3: option 1
+ from six import reraise as raise_
+ # or
+ from future.utils import raise_
+
+ traceback = sys.exc_info()[2]
+ raise_(ValueError, "dodgy value", traceback)
+.. code:: python
+
+ # Python 2 and 3: option 2
+ from future.utils import raise_with_traceback
+
+ raise_with_traceback(ValueError("dodgy value"))
+Exception chaining (PEP 3134):
+
+.. code:: python
+
+ # Setup:
+ class DatabaseError(Exception):
+ pass
+.. code:: python
+
+ # Python 3 only
+ class FileDatabase:
+ def __init__(self, filename):
+ try:
+ self.file = open(filename)
+ except IOError as exc:
+ raise DatabaseError('failed to open') from exc
+.. code:: python
+
+ # Python 2 and 3:
+ from future.utils import raise_from
+
+ class FileDatabase:
+ def __init__(self, filename):
+ try:
+ self.file = open(filename)
+ except IOError as exc:
+ raise_from(DatabaseError('failed to open'), exc)
+.. code:: python
+
+ # Testing the above:
+ try:
+ fd = FileDatabase('non_existent_file.txt')
+ except Exception as e:
+ assert isinstance(e.__cause__, IOError) # FileNotFoundError on Py3.3+ inherits from IOError
+Catching exceptions
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ try:
+ ...
+ except ValueError, e:
+ ...
+.. code:: python
+
+ # Python 2 and 3:
+ try:
+ ...
+ except ValueError as e:
+ ...
+Division
+~~~~~~~~
+
+Integer division (rounding down):
+
+.. code:: python
+
+ # Python 2 only:
+ assert 2 / 3 == 0
+.. code:: python
+
+ # Python 2 and 3:
+ assert 2 // 3 == 0
+"True division" (float division):
+
+.. code:: python
+
+ # Python 3 only:
+ assert 3 / 2 == 1.5
+.. code:: python
+
+ # Python 2 and 3:
+ from __future__ import division # (at top of module)
+
+ assert 3 / 2 == 1.5
+"Old division" (i.e. compatible with Py2 behaviour):
+
+.. code:: python
+
+ # Python 2 only:
+ a = b / c # with any types
+.. code:: python
+
+ # Python 2 and 3:
+ from past.utils import old_div
+
+ a = old_div(b, c) # always same as / on Py2
+Long integers
+~~~~~~~~~~~~~
+
+Short integers are gone in Python 3 and ``long`` has become ``int``
+(without the trailing ``L`` in the ``repr``).
+
+.. code:: python
+
+ # Python 2 only
+ k = 9223372036854775808L
+
+ # Python 2 and 3:
+ k = 9223372036854775808
+.. code:: python
+
+ # Python 2 only
+ bigint = 1L
+
+ # Python 2 and 3
+ from builtins import int
+ bigint = int(1)
+To test whether a value is an integer (of any kind):
+
+.. code:: python
+
+ # Python 2 only:
+ if isinstance(x, (int, long)):
+ ...
+
+ # Python 3 only:
+ if isinstance(x, int):
+ ...
+
+ # Python 2 and 3: option 1
+ from builtins import int # subclass of long on Py2
+
+ if isinstance(x, int): # matches both int and long on Py2
+ ...
+
+ # Python 2 and 3: option 2
+ from past.builtins import long
+
+ if isinstance(x, (int, long)):
+ ...
+Octal constants
+~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ 0644 # Python 2 only
+.. code:: python
+
+ 0o644 # Python 2 and 3
+Backtick repr
+~~~~~~~~~~~~~
+
+.. code:: python
+
+ `x` # Python 2 only
+.. code:: python
+
+ repr(x) # Python 2 and 3
+Metaclasses
+~~~~~~~~~~~
+
+.. code:: python
+
+ class BaseForm(object):
+ pass
+
+ class FormType(type):
+ pass
+.. code:: python
+
+ # Python 2 only:
+ class Form(BaseForm):
+ __metaclass__ = FormType
+ pass
+.. code:: python
+
+ # Python 3 only:
+ class Form(BaseForm, metaclass=FormType):
+ pass
+.. code:: python
+
+ # Python 2 and 3:
+ from six import with_metaclass
+ # or
+ from future.utils import with_metaclass
+
+ class Form(with_metaclass(FormType, BaseForm)):
+ pass
+Strings and bytes
+-----------------
+
+Unicode (text) string literals
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you are upgrading an existing Python 2 codebase, it may be preferable
+to mark up all string literals as unicode explicitly with ``u``
+prefixes:
+
+.. code:: python
+
+ # Python 2 only
+ s1 = 'The Zen of Python'
+ s2 = u'きたないのよりきれいな方がいい\n'
+
+ # Python 2 and 3
+ s1 = u'The Zen of Python'
+ s2 = u'きたないのよりきれいな方がいい\n'
+The ``futurize`` and ``python-modernize`` tools do not currently offer
+an option to do this automatically.
+
+If you are writing code for a new project or new codebase, you can use
+this idiom to make all string literals in a module unicode strings:
+
+.. code:: python
+
+ # Python 2 and 3
+ from __future__ import unicode_literals # at top of module
+
+ s1 = 'The Zen of Python'
+ s2 = 'きたないのよりきれいな方がいい\n'
+See http://python-future.org/unicode\_literals.html for more discussion
+on which style to use.
+
+Byte-string literals
+~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only
+ s = 'This must be a byte-string'
+
+ # Python 2 and 3
+ s = b'This must be a byte-string'
+To loop over a byte-string with possible high-bit characters, obtaining
+each character as a byte-string of length 1:
+
+.. code:: python
+
+ # Python 2 only:
+ for bytechar in 'byte-string with high-bit chars like \xf9':
+ ...
+
+ # Python 3 only:
+ for myint in b'byte-string with high-bit chars like \xf9':
+ bytechar = bytes([myint])
+
+ # Python 2 and 3:
+ from builtins import bytes
+ for myint in bytes(b'byte-string with high-bit chars like \xf9'):
+ bytechar = bytes([myint])
+As an alternative, ``chr()`` and ``.encode('latin-1')`` can be used to
+convert an int into a 1-char byte string:
+
+.. code:: python
+
+ # Python 3 only:
+ for myint in b'byte-string with high-bit chars like \xf9':
+ char = chr(myint) # returns a unicode string
+ bytechar = char.encode('latin-1')
+
+ # Python 2 and 3:
+ from builtins import bytes, chr
+ for myint in bytes(b'byte-string with high-bit chars like \xf9'):
+ char = chr(myint) # returns a unicode string
+ bytechar = char.encode('latin-1') # forces returning a byte str
+basestring
+~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ a = u'abc'
+ b = 'def'
+ assert (isinstance(a, basestring) and isinstance(b, basestring))
+
+ # Python 2 and 3: alternative 1
+ from past.builtins import basestring # pip install future
+
+ a = u'abc'
+ b = b'def'
+ assert (isinstance(a, basestring) and isinstance(b, basestring))
+.. code:: python
+
+ # Python 2 and 3: alternative 2: refactor the code to avoid considering
+ # byte-strings as strings.
+
+ from builtins import str
+ a = u'abc'
+ b = b'def'
+ c = b.decode()
+ assert isinstance(a, str) and isinstance(c, str)
+ # ...
+unicode
+~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ templates = [u"blog/blog_post_detail_%s.html" % unicode(slug)]
+.. code:: python
+
+ # Python 2 and 3: alternative 1
+ from builtins import str
+ templates = [u"blog/blog_post_detail_%s.html" % str(slug)]
+.. code:: python
+
+ # Python 2 and 3: alternative 2
+ from builtins import str as text
+ templates = [u"blog/blog_post_detail_%s.html" % text(slug)]
+StringIO
+~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ from StringIO import StringIO
+ # or:
+ from cStringIO import StringIO
+
+ # Python 2 and 3:
+ from io import BytesIO # for handling byte strings
+ from io import StringIO # for handling unicode strings
+Imports relative to a package
+-----------------------------
+
+Suppose the package is:
+
+::
+
+ mypackage/
+ __init__.py
+ submodule1.py
+ submodule2.py
+
+
+and the code below is in ``submodule1.py``:
+
+.. code:: python
+
+ # Python 2 only:
+ import submodule2
+.. code:: python
+
+ # Python 2 and 3:
+ from . import submodule2
+.. code:: python
+
+ # Python 2 and 3:
+ # To make Py2 code safer (more like Py3) by preventing
+ # implicit relative imports, you can also add this to the top:
+ from __future__ import absolute_import
+Dictionaries
+------------
+
+.. code:: python
+
+ heights = {'Fred': 175, 'Anne': 166, 'Joe': 192}
+Iterating through ``dict`` keys/values/items
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Iterable dict keys:
+
+.. code:: python
+
+ # Python 2 only:
+ for key in heights.iterkeys():
+ ...
+.. code:: python
+
+ # Python 2 and 3:
+ for key in heights:
+ ...
+Iterable dict values:
+
+.. code:: python
+
+ # Python 2 only:
+ for value in heights.itervalues():
+ ...
+.. code:: python
+
+ # Idiomatic Python 3
+ for value in heights.values(): # extra memory overhead on Py2
+ ...
+.. code:: python
+
+ # Python 2 and 3: option 1
+ from builtins import dict
+
+ heights = dict(Fred=175, Anne=166, Joe=192)
+ for key in heights.values(): # efficient on Py2 and Py3
+ ...
+.. code:: python
+
+ # Python 2 and 3: option 2
+ from future.utils import itervalues
+ # or
+ from six import itervalues
+
+ for key in itervalues(heights):
+ ...
+Iterable dict items:
+
+.. code:: python
+
+ # Python 2 only:
+ for (key, value) in heights.iteritems():
+ ...
+.. code:: python
+
+ # Python 2 and 3: option 1
+ for (key, value) in heights.items(): # inefficient on Py2
+ ...
+.. code:: python
+
+ # Python 2 and 3: option 2
+ from future.utils import viewitems
+
+ for (key, value) in viewitems(heights): # also behaves like a set
+ ...
+.. code:: python
+
+ # Python 2 and 3: option 3
+ from future.utils import iteritems
+ # or
+ from six import iteritems
+
+ for (key, value) in iteritems(heights):
+ ...
+dict keys/values/items as a list
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+dict keys as a list:
+
+.. code:: python
+
+ # Python 2 only:
+ keylist = heights.keys()
+ assert isinstance(keylist, list)
+.. code:: python
+
+ # Python 2 and 3:
+ keylist = list(heights)
+ assert isinstance(keylist, list)
+dict values as a list:
+
+.. code:: python
+
+ # Python 2 only:
+ heights = {'Fred': 175, 'Anne': 166, 'Joe': 192}
+ valuelist = heights.values()
+ assert isinstance(valuelist, list)
+.. code:: python
+
+ # Python 2 and 3: option 1
+ valuelist = list(heights.values()) # inefficient on Py2
+.. code:: python
+
+ # Python 2 and 3: option 2
+ from builtins import dict
+
+ heights = dict(Fred=175, Anne=166, Joe=192)
+ valuelist = list(heights.values())
+.. code:: python
+
+ # Python 2 and 3: option 3
+ from future.utils import listvalues
+
+ valuelist = listvalues(heights)
+.. code:: python
+
+ # Python 2 and 3: option 4
+ from future.utils import itervalues
+ # or
+ from six import itervalues
+
+ valuelist = list(itervalues(heights))
+dict items as a list:
+
+.. code:: python
+
+ # Python 2 and 3: option 1
+ itemlist = list(heights.items()) # inefficient on Py2
+.. code:: python
+
+ # Python 2 and 3: option 2
+ from future.utils import listitems
+
+ itemlist = listitems(heights)
+.. code:: python
+
+ # Python 2 and 3: option 3
+ from future.utils import iteritems
+ # or
+ from six import iteritems
+
+ itemlist = list(iteritems(heights))
+Custom class behaviour
+----------------------
+
+Custom iterators
+~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only
+ class Upper(object):
+ def __init__(self, iterable):
+ self._iter = iter(iterable)
+ def next(self): # Py2-style
+ return self._iter.next().upper()
+ def __iter__(self):
+ return self
+
+ itr = Upper('hello')
+ assert itr.next() == 'H' # Py2-style
+ assert list(itr) == list('ELLO')
+.. code:: python
+
+ # Python 2 and 3: option 1
+ from builtins import object
+
+ class Upper(object):
+ def __init__(self, iterable):
+ self._iter = iter(iterable)
+ def __next__(self): # Py3-style iterator interface
+ return next(self._iter).upper() # builtin next() function calls
+ def __iter__(self):
+ return self
+
+ itr = Upper('hello')
+ assert next(itr) == 'H' # compatible style
+ assert list(itr) == list('ELLO')
+.. code:: python
+
+ # Python 2 and 3: option 2
+ from future.utils import implements_iterator
+
+ @implements_iterator
+ class Upper(object):
+ def __init__(self, iterable):
+ self._iter = iter(iterable)
+ def __next__(self): # Py3-style iterator interface
+ return next(self._iter).upper() # builtin next() function calls
+ def __iter__(self):
+ return self
+
+ itr = Upper('hello')
+ assert next(itr) == 'H'
+ assert list(itr) == list('ELLO')
+Custom ``__str__`` methods
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ class MyClass(object):
+ def __unicode__(self):
+ return 'Unicode string: \u5b54\u5b50'
+ def __str__(self):
+ return unicode(self).encode('utf-8')
+
+ a = MyClass()
+ print(a) # prints encoded string
+.. code:: python
+
+ # Python 2 and 3:
+ from future.utils import python_2_unicode_compatible
+
+ @python_2_unicode_compatible
+ class MyClass(object):
+ def __str__(self):
+ return u'Unicode string: \u5b54\u5b50'
+
+ a = MyClass()
+ print(a) # prints string encoded as utf-8 on Py2
+
+.. parsed-literal::
+
+ Unicode string: 孔子
+
+
+Custom ``__nonzero__`` vs ``__bool__`` method:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ class AllOrNothing(object):
+ def __init__(self, l):
+ self.l = l
+ def __nonzero__(self):
+ return all(self.l)
+
+ container = AllOrNothing([0, 100, 200])
+ assert not bool(container)
+.. code:: python
+
+ # Python 2 and 3:
+ from builtins import object
+
+ class AllOrNothing(object):
+ def __init__(self, l):
+ self.l = l
+ def __bool__(self):
+ return all(self.l)
+
+ container = AllOrNothing([0, 100, 200])
+ assert not bool(container)
+Lists versus iterators
+----------------------
+
+xrange
+~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ for i in xrange(10**8):
+ ...
+.. code:: python
+
+ # Python 2 and 3: forward-compatible
+ from builtins import range
+ for i in range(10**8):
+ ...
+.. code:: python
+
+ # Python 2 and 3: backward-compatible
+ from past.builtins import xrange
+ for i in xrange(10**8):
+ ...
+range
+~~~~~
+
+.. code:: python
+
+ # Python 2 only
+ mylist = range(5)
+ assert mylist == [0, 1, 2, 3, 4]
+.. code:: python
+
+ # Python 2 and 3: forward-compatible: option 1
+ mylist = list(range(5)) # copies memory on Py2
+ assert mylist == [0, 1, 2, 3, 4]
+.. code:: python
+
+ # Python 2 and 3: forward-compatible: option 2
+ from builtins import range
+
+ mylist = list(range(5))
+ assert mylist == [0, 1, 2, 3, 4]
+.. code:: python
+
+ # Python 2 and 3: option 3
+ from future.utils import lrange
+
+ mylist = lrange(5)
+ assert mylist == [0, 1, 2, 3, 4]
+.. code:: python
+
+ # Python 2 and 3: backward compatible
+ from past.builtins import range
+
+ mylist = range(5)
+ assert mylist == [0, 1, 2, 3, 4]
+map
+~~~
+
+.. code:: python
+
+ # Python 2 only:
+ mynewlist = map(f, myoldlist)
+ assert mynewlist == [f(x) for x in myoldlist]
+.. code:: python
+
+ # Python 2 and 3: option 1
+ # Idiomatic Py3, but inefficient on Py2
+ mynewlist = list(map(f, myoldlist))
+ assert mynewlist == [f(x) for x in myoldlist]
+.. code:: python
+
+ # Python 2 and 3: option 2
+ from builtins import map
+
+ mynewlist = list(map(f, myoldlist))
+ assert mynewlist == [f(x) for x in myoldlist]
+.. code:: python
+
+ # Python 2 and 3: option 3
+ try:
+ import itertools.imap as map
+ except ImportError:
+ pass
+
+ mynewlist = list(map(f, myoldlist)) # inefficient on Py2
+ assert mynewlist == [f(x) for x in myoldlist]
+.. code:: python
+
+ # Python 2 and 3: option 4
+ from future.utils import lmap
+
+ mynewlist = lmap(f, myoldlist)
+ assert mynewlist == [f(x) for x in myoldlist]
+.. code:: python
+
+ # Python 2 and 3: option 5
+ from past.builtins import map
+
+ mynewlist = map(f, myoldlist)
+ assert mynewlist == [f(x) for x in myoldlist]
+imap
+~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ from itertools import imap
+
+ myiter = imap(func, myoldlist)
+ assert isinstance(myiter, iter)
+.. code:: python
+
+ # Python 3 only:
+ myiter = map(func, myoldlist)
+ assert isinstance(myiter, iter)
+.. code:: python
+
+ # Python 2 and 3: option 1
+ from builtins import map
+
+ myiter = map(func, myoldlist)
+ assert isinstance(myiter, iter)
+.. code:: python
+
+ # Python 2 and 3: option 2
+ try:
+ import itertools.imap as map
+ except ImportError:
+ pass
+
+ myiter = map(func, myoldlist)
+ assert isinstance(myiter, iter)
+.. code:: python
+
+ # Python 2 and 3: option 3
+ from six.moves import map
+
+ myiter = map(func, myoldlist)
+ assert isinstance(myiter, iter)
+
+zip, izip
+~~~~~~~~~
+
+As above with ``zip`` and ``itertools.izip``.
+
+filter, ifilter
+~~~~~~~~~~~~~~~
+
+As above with ``filter`` and ``itertools.ifilter`` too.
+
+Other builtins
+--------------
+
+File IO with open()
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only
+ f = open('myfile.txt')
+ data = f.read() # as a byte string
+ text = data.decode('utf-8')
+
+ # Python 2 and 3: alternative 1
+ from io import open
+ f = open('myfile.txt', 'rb')
+ data = f.read() # as bytes
+ text = data.decode('utf-8') # unicode, not bytes
+
+ # Python 2 and 3: alternative 2
+ from io import open
+ f = open('myfile.txt', encoding='utf-8')
+ text = f.read() # unicode, not bytes
+reduce()
+~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5
+.. code:: python
+
+ # Python 2 and 3:
+ from functools import reduce
+
+ assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5
+raw\_input()
+~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ name = raw_input('What is your name? ')
+ assert isinstance(name, str) # native str
+.. code:: python
+
+ # Python 2 and 3:
+ from builtins import input
+
+ name = input('What is your name? ')
+ assert isinstance(name, str) # native str on Py2 and Py3
+input()
+~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ input("Type something safe please: ")
+.. code:: python
+
+ # Python 2 and 3
+ from builtins import input
+ eval(input("Type something safe please: "))
+Warning: using either of these is **unsafe** with untrusted input.
+
+file()
+~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ f = file(pathname)
+.. code:: python
+
+ # Python 2 and 3:
+ f = open(pathname)
+
+ # But preferably, use this:
+ from io import open
+ f = open(pathname, 'rb') # if f.read() should return bytes
+ # or
+ f = open(pathname, 'rt') # if f.read() should return unicode text
+exec
+~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ exec 'x = 10'
+
+ # Python 2 and 3:
+ exec('x = 10')
+.. code:: python
+
+ # Python 2 only:
+ g = globals()
+ exec 'x = 10' in g
+
+ # Python 2 and 3:
+ g = globals()
+ exec('x = 10', g)
+.. code:: python
+
+ # Python 2 only:
+ l = locals()
+ exec 'x = 10' in g, l
+
+ # Python 2 and 3:
+ exec('x = 10', g, l)
+execfile()
+~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ execfile('myfile.py')
+.. code:: python
+
+ # Python 2 and 3: alternative 1
+ from past.builtins import execfile
+
+ execfile('myfile.py')
+.. code:: python
+
+ # Python 2 and 3: alternative 2
+ exec(compile(open('myfile.py').read()))
+
+ # This can sometimes cause this:
+ # SyntaxError: function ... uses import * and bare exec ...
+ # See https://github.com/PythonCharmers/python-future/issues/37
+unichr()
+~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ assert unichr(8364) == '€'
+.. code:: python
+
+ # Python 3 only:
+ assert chr(8364) == '€'
+.. code:: python
+
+ # Python 2 and 3:
+ from builtins import chr
+ assert chr(8364) == '€'
+intern()
+~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ intern('mystring')
+.. code:: python
+
+ # Python 3 only:
+ from sys import intern
+ intern('mystring')
+.. code:: python
+
+ # Python 2 and 3: alternative 1
+ from past.builtins import intern
+ intern('mystring')
+.. code:: python
+
+ # Python 2 and 3: alternative 2
+ from six.moves import intern
+ intern('mystring')
+.. code:: python
+
+ # Python 2 and 3: alternative 3
+ from future.standard_library import install_aliases
+ install_aliases()
+ from sys import intern
+ intern('mystring')
+.. code:: python
+
+ # Python 2 and 3: alternative 2
+ try:
+ from sys import intern
+ except ImportError:
+ pass
+ intern('mystring')
+apply()
+~~~~~~~
+
+.. code:: python
+
+ args = ('a', 'b')
+ kwargs = {'kwarg1': True}
+.. code:: python
+
+ # Python 2 only:
+ apply(f, args, kwargs)
+.. code:: python
+
+ # Python 2 and 3: alternative 1
+ f(*args, **kwargs)
+.. code:: python
+
+ # Python 2 and 3: alternative 2
+ from past.builtins import apply
+ apply(f, args, kwargs)
+chr()
+~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ assert chr(64) == b'@'
+ assert chr(200) == b'\xc8'
+.. code:: python
+
+ # Python 3 only: option 1
+ assert chr(64).encode('latin-1') == b'@'
+ assert chr(0xc8).encode('latin-1') == b'\xc8'
+.. code:: python
+
+ # Python 2 and 3: option 1
+ from builtins import chr
+
+ assert chr(64).encode('latin-1') == b'@'
+ assert chr(0xc8).encode('latin-1') == b'\xc8'
+.. code:: python
+
+ # Python 3 only: option 2
+ assert bytes([64]) == b'@'
+ assert bytes([0xc8]) == b'\xc8'
+.. code:: python
+
+ # Python 2 and 3: option 2
+ from builtins import bytes
+
+ assert bytes([64]) == b'@'
+ assert bytes([0xc8]) == b'\xc8'
+cmp()
+~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0
+.. code:: python
+
+ # Python 2 and 3: alternative 1
+ from past.builtins import cmp
+ assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0
+.. code:: python
+
+ # Python 2 and 3: alternative 2
+ cmp = lambda(x, y): (x > y) - (x < y)
+ assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0
+reload()
+~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ reload(mymodule)
+.. code:: python
+
+ # Python 2 and 3
+ from imp import reload
+ reload(mymodule)
+Standard library
+----------------
+
+dbm modules
+~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only
+ import anydbm
+ import whichdb
+ import dbm
+ import dumbdbm
+ import gdbm
+
+ # Python 2 and 3: alternative 1
+ from future import standard_library
+ standard_library.install_aliases()
+
+ import dbm
+ import dbm.ndbm
+ import dbm.dumb
+ import dbm.gnu
+
+ # Python 2 and 3: alternative 2
+ from future.moves import dbm
+ from future.moves.dbm import dumb
+ from future.moves.dbm import ndbm
+ from future.moves.dbm import gnu
+
+ # Python 2 and 3: alternative 3
+ from six.moves import dbm_gnu
+ # (others not supported)
+commands / subprocess modules
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only
+ from commands import getoutput, getstatusoutput
+
+ # Python 2 and 3
+ from future import standard_library
+ standard_library.install_aliases()
+
+ from subprocess import getoutput, getstatusoutput
+StringIO module
+~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only
+ from StringIO import StringIO
+ from cStringIO import StringIO
+.. code:: python
+
+ # Python 2 and 3
+ from io import BytesIO
+ # and refactor StringIO() calls to BytesIO() if passing byte-strings
+http module
+~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ import httplib
+ import Cookie
+ import cookielib
+ import BaseHTTPServer
+ import SimpleHTTPServer
+ import CGIHttpServer
+
+ # Python 2 and 3 (after ``pip install future``):
+ import http.client
+ import http.cookies
+ import http.cookiejar
+ import http.server
+xmlrpc module
+~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ import DocXMLRPCServer
+ import SimpleXMLRPCServer
+
+ # Python 2 and 3 (after ``pip install future``):
+ import xmlrpc.server
+.. code:: python
+
+ # Python 2 only:
+ import xmlrpclib
+
+ # Python 2 and 3 (after ``pip install future``):
+ import xmlrpc.client
+html escaping and entities
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 and 3:
+ from cgi import escape
+
+ # Safer (Python 2 and 3, after ``pip install future``):
+ from html import escape
+
+ # Python 2 only:
+ from htmlentitydefs import codepoint2name, entitydefs, name2codepoint
+
+ # Python 2 and 3 (after ``pip install future``):
+ from html.entities import codepoint2name, entitydefs, name2codepoint
+html parsing
+~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ from HTMLParser import HTMLParser
+
+ # Python 2 and 3 (after ``pip install future``)
+ from html.parser import HTMLParser
+
+ # Python 2 and 3 (alternative 2):
+ from future.moves.html.parser import HTMLParser
+urllib module
+~~~~~~~~~~~~~
+
+``urllib`` is the hardest module to use from Python 2/3 compatible code.
+You might want to switch to Requests (http://python-requests.org) instead.
+
+.. code:: python
+
+ # Python 2 only:
+ from urlparse import urlparse
+ from urllib import urlencode
+ from urllib2 import urlopen, Request, HTTPError
+.. code:: python
+
+ # Python 3 only:
+ from urllib.parse import urlparse, urlencode
+ from urllib.request import urlopen, Request
+ from urllib.error import HTTPError
+.. code:: python
+
+ # Python 2 and 3: easiest option
+ from future.standard_library import install_aliases
+ install_aliases()
+
+ from urllib.parse import urlparse, urlencode
+ from urllib.request import urlopen, Request
+ from urllib.error import HTTPError
+.. code:: python
+
+ # Python 2 and 3: alternative 2
+ from future.standard_library import hooks
+
+ with hooks():
+ from urllib.parse import urlparse, urlencode
+ from urllib.request import urlopen, Request
+ from urllib.error import HTTPError
+.. code:: python
+
+ # Python 2 and 3: alternative 3
+ from future.moves.urllib.parse import urlparse, urlencode
+ from future.moves.urllib.request import urlopen, Request
+ from future.moves.urllib.error import HTTPError
+ # or
+ from six.moves.urllib.parse import urlparse, urlencode
+ from six.moves.urllib.request import urlopen
+ from six.moves.urllib.error import HTTPError
+.. code:: python
+
+ # Python 2 and 3: alternative 4
+ try:
+ from urllib.parse import urlparse, urlencode
+ from urllib.request import urlopen, Request
+ from urllib.error import HTTPError
+ except ImportError:
+ from urlparse import urlparse
+ from urllib import urlencode
+ from urllib2 import urlopen, Request, HTTPError
+Tkinter
+~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ import Tkinter
+ import Dialog
+ import FileDialog
+ import ScrolledText
+ import SimpleDialog
+ import Tix
+ import Tkconstants
+ import Tkdnd
+ import tkColorChooser
+ import tkCommonDialog
+ import tkFileDialog
+ import tkFont
+ import tkMessageBox
+ import tkSimpleDialog
+ import ttk
+
+ # Python 2 and 3 (after ``pip install future``):
+ import tkinter
+ import tkinter.dialog
+ import tkinter.filedialog
+ import tkinter.scrolledtext
+ import tkinter.simpledialog
+ import tkinter.tix
+ import tkinter.constants
+ import tkinter.dnd
+ import tkinter.colorchooser
+ import tkinter.commondialog
+ import tkinter.filedialog
+ import tkinter.font
+ import tkinter.messagebox
+ import tkinter.simpledialog
+ import tkinter.ttk
+socketserver
+~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ import SocketServer
+
+ # Python 2 and 3 (after ``pip install future``):
+ import socketserver
+copy\_reg, copyreg
+~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ import copy_reg
+
+ # Python 2 and 3 (after ``pip install future``):
+ import copyreg
+configparser
+~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ from ConfigParser import ConfigParser
+
+ # Python 2 and 3 (after ``pip install configparser``):
+ from configparser import ConfigParser
+queue
+~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ from Queue import Queue, heapq, deque
+
+ # Python 2 and 3 (after ``pip install future``):
+ from queue import Queue, heapq, deque
+repr, reprlib
+~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ from repr import aRepr, repr
+
+ # Python 2 and 3 (after ``pip install future``):
+ from reprlib import aRepr, repr
+UserDict, UserList, UserString
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ from UserDict import UserDict
+ from UserList import UserList
+ from UserString import UserString
+
+ # Python 3 only:
+ from collections import UserDict, UserList, UserString
+
+ # Python 2 and 3: alternative 1
+ from future.moves.collections import UserDict, UserList, UserString
+
+ # Python 2 and 3: alternative 2
+ from six.moves import UserDict, UserList, UserString
+
+ # Python 2 and 3: alternative 3
+ from future.standard_library import install_aliases
+ install_aliases()
+ from collections import UserDict, UserList, UserString
+itertools: filterfalse, zip\_longest
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ # Python 2 only:
+ from itertools import ifilterfalse, izip_longest
+
+ # Python 3 only:
+ from itertools import filterfalse, zip_longest
+
+ # Python 2 and 3: alternative 1
+ from future.moves.itertools import filterfalse, zip_longest
+
+ # Python 2 and 3: alternative 2
+ from six.moves import filterfalse, zip_longest
+
+ # Python 2 and 3: alternative 3
+ from future.standard_library import install_aliases
+ install_aliases()
+ from itertools import filterfalse, zip_longest