Skip to content

PythonCharmers/python-future

Repository files navigation

Overview: Easy, clean, reliable Python 2/3 compatibility

https://github.com/PythonCharmers/python-future/actions/workflows/ci.yml/badge.svg?branch=master

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.

The python-future project has been downloaded over 1.7 billion times.

Status

The python-future project was created in 2013 to attempt to save Python from the schism of version incompatibility that was threatening to tear apart the language (as Perl 6 contributed to the death of Perl).

That time is now past. Thanks to a huge porting effort across the Python community, Python 3 eventually thrived. Python 2 reached its end of life in 2020 and the python-future package should no longer be necessary. Use it to help with porting legacy code to Python 3 but don't depend on it for new code.

Features

  • future.builtins package (also available as builtins 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 and future.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 and pasteurize scripts based on 2to3 and parts of 3to2 and python-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 like six, IPython, Jinja2, Django, and Pandas.
  • support for the surrogateescape error handler when encoding and decoding the backported str and bytes objects. [This feature is currently in alpha.]
  • support for pre-commit hooks

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+:

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() functi