[FIX] builtins removed from Python 3

* Reverse wrapper courtesy of @rco-odoo's original P3 branch
* thin compat module stripped down from werkzeug (to augment as needed)

issue 8530
This commit is contained in:
xmo-odoo
2017-04-27 13:59:33 +02:00
committed by GitHub
parent de4a2216b9
commit 2e6a589f41
73 changed files with 464 additions and 199 deletions
+132 -17
View File
@@ -16,13 +16,28 @@ with both.
Here are a few useful steps or reminders to make Python 2 code compatible
with Python 3.
.. important::
This is not a general-purpose guide for porting Python 2 to Python 3, it's
a guide to write 2/3-compatible Odoo code. It does not go through all the
changes in Python but rather through issues which have been found in the
standard Odoo distribution in order to show how to evolve such code such
that it works on both Python 2 and Python 3.
References/useful documents:
* `What's new in Python 3? <https://docs.python.org/3.0/whatsnew/3.0.html>`_
covers many of the changes between Python 2 and Python 3, though it is
missing a number of changes which `were backported to Python 2.7 <https://docs.python.org/2.7/whatsnew/2.7.html#python-3-1-features>`_
as well as :ref:`some feature reintroductions <p3support>` of later Python 3
revisions
* `How do I port to Python 3? <https://eev.ee/blog/2016/07/31/python-faq-how-do-i-port-to-python-3/>`_
* `Python-Future <http://python-future.org/index.html>`_
* `Porting Python 2 code to Python 3 <https://docs.python.org/3/howto/pyporting.html>`_
* `Porting to Python 3: A Guide <http://lucumr.pocoo.org/2010/2/11/porting-to-python-3-a-guide/>`_ (a bit outdated but useful for the extensive comments on strings and IO)
.. _p3support:
Versions Support
================
@@ -37,16 +52,17 @@ features whereas:
* Python 3.4 has no specific compatibility improvement but is the lowest P3
version for PyLint
* Python 3.3 reintroduced the "u" prefix for proper (unicode) strings
* Python 3.2 made ``range`` views more list-like and reintroduced ``callable``
* Python 3.2 made ``range`` views more list-like (backported to 2.7)and
reintroduced ``callable``
.. warning::
Python 3 adds plenty of great features (keyword-only parameters,
generator delegation, pathlib, ...), do not use them until Python 2
support is dropped
While Python 3 adds plenty of great features (keyword-only parameters,
generator delegation, pathlib, ...), you must *not *use them in Odoo
until Python 2 support is dropped
Fixes
=====
Moved and removed
=================
Exception Handlers
------------------
@@ -87,33 +103,132 @@ or::
This form was implemented in Python 2.5 and is thus compatible across the
board.
Removed Operators
-----------------
Operators & keywords
--------------------
.. important::
.. important:: The backtick operator ```foo``` must be converted to an
explicit call to the ``repr()`` builtin
* The backtick operator ``\`foo\``` must be converted to an explicit call
to the ``repr()`` builtin
* The ``<>`` operator must be replaced by ``!=``
.. important:: The ``<>`` operator must be replaced by ``!=``
These two operators were long recommended against/deprecated in Python 2,
Python 3 removed them from the language.
Removed/renamed builtins
------------------------
.. _changed-exec:
.. important:: ``exec`` is now a builtin
In Python 2, ``exec`` is a statement/keyword. Much like ``print``, it's been
converted to a builtin function in Python 3. However because the Python 2
version can take a tuple parameter it is easy to convert the odd ``exec``
statement to the following cross-language forms::
exec(source)
exec(source, globals)
exec(source, globals, locals)
builtins
--------
``cmp``
#######
The ``cmp`` builtin function has been removed from Python 3.
* Most of its uses are in ``cmp=`` parameters to sort functions where it can
usually be replaced by a key function.
* Other uses found were obtaining the sign of an item (``cmp(item, 0)``), this
can be replicated using the standard library's ``math.copysign`` e.g.
``math.copysign(1, item)`` will return ``1.0`` if ``item`` is positive and
``-1.0`` if ``item`` is negative.
``execfile``
############
``execfile(path)`` has been removed completely from Python 3 but it is
trivially replaceable in all cases by::
exec(open(path, 'rb').open())
of a variant thereof (see :ref:`exec changes <changed-exec>` for details)
``file``
########
The ``file`` builtin has been removed in Python 3. Generally, it can just
be replaced by the ``open`` builtin, although you may want to use ``io.open``
which is more flexible and better handles the binary/text dichotomy,
:ref:`a big issue in cross-version Python <changed-strings>`.
.. note::
In Python 3, the ``open`` builtin is actually an alias for ``io.open``.
``long``
########
In Python 2, integers can be either ``int`` or ``long``. Python 3 unifies this
under the single ``int`` type.
.. important::
* the ``L`` suffix for integer literals must be removed
* calls to ``long`` must be replaced by calls to ``int``
* ``(int, long)`` for type-checking purposes must be replaced by
:py:data:`odoo.tools.pycompat.integer_types`
* the ``L`` suffix on numbers is unsupported in Python 3, and unnecessary in
Python 2 as "overflowing" integer literals will implicitly instantiate long.
* in Python 2, a call to ``int()`` will implicitly create a ``long`` object if
necessary.
* type-testing is the last and bigger issue as in Python 2 ``long`` is not a
subtype of ``int`` (nor the reverse), and ``isinstance(value, (int, long))``
is thus generally necessary to catch all integrals.
For that case, Odoo 11 now provides a compatibility module with an
:py:data:`~odoo.tools.pycompat.integer_types` definition which can be used
for type-testing.
It is a tuple of types so when used with ``isinstance`` it can be provided
directly or inside an other tuple alongside other types e.g.
``isinstance(value, (BaseModel, integer_types))``.
However when used with ``type`` directly (which should be avoided) you
should use the ``in`` operator, and if you need other types you need to
concatenate ``integer_types`` to an other tuple.
``reduce``
##########
In Python 3, ``reduce`` has been demoted from builtin to ``functools.reduce``.
However this is because many (if not most) uses of ``reduce`` can be replaced
by ``sum``, ``all``, ``any`` or a list comprehension for a more readable and
faster result.
However this is because *most uses of ``reduce`` can be replaced by ``sum``,
``all``, ``any``* or a list comprehension for a more readable and faster
result.
It is easy enough to just add ``from functools import reduce`` to the file
and compatible with Python 2.6 and later, but consider whether you get better
code by replacing it with some other method altogether.
``xrange``
##########
In Python 3, ``range()`` behaves the same as Python 3's ``xrange``. For
cross-versions code you can:
* just use ``range()`` everywhere and ignore the allocation cost of a list in
Python 2 (often not an issue)
* conditionally alias ``xrange`` to ``range`` in Python 3 and use that
* use a combination of ``itertools.count`` and ``takewhile`` for a
cross-compatible lazy increasing sequence of numbers
.. warning::
In the *rare* cases where you need conditional code (code which applies
for one version of python and not the other), use ``sys.version_info``
e.g. ``sys.version_info() >= (3,)`` for Python3+ code or
``sys.version_info() < (3,)`` for Python 2 code.
Removed/renamed methods
-----------------------