Python-Future
The missing compatibility layer between Python 2 and Python 3.
python-future is the missing compatibility layer between Python 2 and Python 3. It allows you to use a single, clean Python 3.x-compatible codebase to support both Python 2 and Python 3 with minimal overhead.
It provides future and past packages with backports and forward ports of features from Python 3 and 2. It also comes with futurize and pasteurize, customized 2to3-based scripts that helps you to convert either Py2 or Py3 code easily to support both Python 2 and 3 in a single clean Py3-style codebase, module by module.
Notable projects that use python-future for Python 2/3 compatibility are Mezzanine and ObsPy.
Features
-
future.builtins
package (also available asbuiltins
on Py2) provides
backports and remappings for 20 builtins with different semantics on Py3
versus Py2 -
support for directly importing 30 standard library modules under
their Python 3 names on Py2 -
support for importing the other 14 refactored standard library modules
under their Py3 names relatively cleanly via
future.standard_library
andfuture.moves
-
past.builtins
package provides forward-ports of 19 Python 2 types and
builtin functions. These can aid with per-module code migrations. -
past.translation
package supports transparent translation of Python 2
modules to Python 3 upon import. [This feature is currently in alpha.] -
1000+ unit tests, including many from the Py3.3 source tree.
-
futurize
andpasteurize
scripts based on2to3
and parts of
3to2
andpython-modernize
, for automatic conversion from either Py2
or Py3 to a clean single-source codebase compatible with Python 2.6+ and
Python 3.3+. -
a curated set of utility functions and decorators in
future.utils
and
past.utils
selected from Py2/3 compatibility interfaces from projects
likesix
,IPython
,Jinja2
,Django
, andPandas
. -
support for the
surrogateescape
error handler when encoding and
decoding the backportedstr
andbytes
objects. [This feature is
currently in alpha.]
Code examples
Replacements for Py2's built-in functions and types are designed to be imported
at the top of each Python module together with Python's built-in __future__
statements. For example, this code behaves identically on Python 2.6/2.7 after
these imports as it does on Python 3.3+:
.. code-block:: python
from __future__ import absolute_import, division, print_function
from builtins import (bytes, str, open, super, range,
zip, round, input, int, pow, object)
# Backported Py3 bytes object
b = bytes(b'ABCD')
assert list(b) == [65, 66, 67, 68]
assert repr(b) == "b'ABCD'"
# These raise TypeErrors:
# b + u'EFGH'
# bytes(b',').join([u'Fred', u'Bill'])
# Backported Py3 str object
s = str(u'ABCD')
assert s != bytes(b'ABCD')
assert isinstance(s.encode('utf-8'), bytes)
assert isinstance(b.decode('utf-8'), str)
assert repr(s) == "'ABCD'" # consistent repr with Py3 (no u prefix)
# These raise TypeErrors:
# bytes(b'B') in s
# s.find(bytes(b'A'))
# Extra arguments for the open() function
f = open('japanese.txt', encoding='utf-8', errors='replace')
# New zero-argument super() function:
class VerboseList(list):
def append(self, item):
print('Adding an item')
super().append(item)
# New iterable range object with slicing support
for i in range(10**15)[:10]:
pass
# Other iterators: map, zip, filter
my_iter = zip(range(3), ['a', 'b', 'c'])
assert my_iter != list(my_iter)
# The round() function behaves as it does in Python 3, using
# "Banker's Rounding" to the nearest even last digit:
assert round(0.1250, 2) == 0.12
# input() replaces Py2's raw_input() (with no eval()):
name = input('What is your name? ')
print('Hello ' + name)
# pow() supports fractional exponents of negative numbers like in Py3:
z = pow(-1, 0.5)
# Compatible output from isinstance() across Py2/3:
assert isinstance(2**64, int) # long integers
assert isinstance(u'blah', str)
assert isinstance('blah', str) # only if unicode_literals is in effect
# Py3-style iterators written as new-style classes (subclasses of
# future.types.newobject) are automatically backward compatible with Py2:
class Upper(object):
def __init__(self, iterable):
self._iter = iter(iterable)
def __next__(self): # note the Py3 interface
return next(self._iter).upper()
def __iter__(self):
return self
assert list(Upper('hello')) == list('HELLO')
There is also support for renamed standard library modules. The recommended
interface works like this:
.. code-block:: python
# Many Py3 module names are supported directly on both Py2.x and 3.x:
from http.client import HttpConnection
import html.parser
import queue
import xmlrpc.client
# Refactored modules with clashing names on Py2 and Py3 are supported
# as follows:
from future import standard_library
standard_library.install_aliases()
# Then, for example:
from itertools import filterfalse, zip_longest
from urllib.request import urlopen
from collections import ChainMap
from collections import UserDict, UserList, UserString
from subprocess import getoutput, getstatusoutput
from collections import Counter, OrderedDict # backported to Py2.6