summaryrefslogtreecommitdiff
path: root/doc/python3.rst
diff options
context:
space:
mode:
authorxmo-odoo <xmo@odoo.com>2017-04-27 13:59:33 +0200
committerGitHub <noreply@github.com>2017-04-27 13:59:33 +0200
commit2e6a589f417af48e3322955ffff6e94b6d8a24e3 (patch)
treeaa613ecc1f74a9531a03de89aa2bdc7bb32eed3b /doc/python3.rst
parentde4a2216b953abb86094c9bfa5f45b1eaaa79d3d (diff)
[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
Diffstat (limited to 'doc/python3.rst')
-rw-r--r--doc/python3.rst149
1 files changed, 132 insertions, 17 deletions
diff --git a/doc/python3.rst b/doc/python3.rst
index cb60965eb6c..407d8e9ee56 100644
--- a/doc/python3.rst
+++ b/doc/python3.rst
@@ -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
-----------------------