Add PEP 606: Python Compatibility Version (#1209)
This commit is contained in:
parent
7498996064
commit
635c6914a2
|
@ -0,0 +1,625 @@
|
||||||
|
PEP: 606
|
||||||
|
Title: Python Compatibility Version
|
||||||
|
Author: Victor Stinner <vstinner@python.org>
|
||||||
|
Status: Draft
|
||||||
|
Type: Standards Track
|
||||||
|
Content-Type: text/x-rst
|
||||||
|
Created: 18-Oct-2019
|
||||||
|
Python-Version: 3.9
|
||||||
|
|
||||||
|
|
||||||
|
Abstract
|
||||||
|
========
|
||||||
|
|
||||||
|
Add ``sys.set_python_compat_version(version)`` to enable partial
|
||||||
|
compatibility with requested Python version. Add
|
||||||
|
``sys.get_python_compat_version()``.
|
||||||
|
|
||||||
|
Modify a few functions of the standard library to implement a partial
|
||||||
|
compatibility with Python 3.8.
|
||||||
|
|
||||||
|
Add ``sys.set_python_min_compat_version(version)`` to deny backward
|
||||||
|
compatibility with Python older than *version*.
|
||||||
|
|
||||||
|
Add ``-X compat_version=VERSION`` and ``-X min_compat_version=VERSION``
|
||||||
|
command line options. Add ``PYTHONCOMPATVERSION`` and
|
||||||
|
``PYTHONCOMPATMINVERSION`` environment variables.
|
||||||
|
|
||||||
|
|
||||||
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
|
The need to evolve frequently
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
To remain relevant and useful, Python has to evolve frequently. Some
|
||||||
|
enhancements require incompatible changes. Any incompatible change can
|
||||||
|
break an unknown number of Python projects. Developers can decide to
|
||||||
|
not implement a feature because of that.
|
||||||
|
|
||||||
|
Users want to get the latest Python version to get new features and
|
||||||
|
better performance. A few incompatible changes prevent them to use their
|
||||||
|
applications on the latest Python version.
|
||||||
|
|
||||||
|
This PEP proposes to add a partial compatibility with old Python
|
||||||
|
versions as a tradeoff to fit both use cases.
|
||||||
|
|
||||||
|
The main issue with the migration from Python 2 to Python 3 is not that
|
||||||
|
Python 3 is backward incompatible, but how incompatible changes were
|
||||||
|
introduced.
|
||||||
|
|
||||||
|
|
||||||
|
Partial compatibility to minimize the Python maintenance burden
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
While technically it would be possible to provide a full compatibility
|
||||||
|
with old Python versions, this PEP proposes to minimize the number of
|
||||||
|
functions handling backward compatibility to reduce the maintenance
|
||||||
|
burden of the Python project ("CPython").
|
||||||
|
|
||||||
|
Each change introducing backport compatibility to a function should be
|
||||||
|
properly discussed to estimate the maintenance cost in the long-term.
|
||||||
|
|
||||||
|
Backward compatibility code will be dropped at each Python release, on a
|
||||||
|
case by case basis. Each compatibility function can be supported for a
|
||||||
|
different number of Python releases depending on its maintenance cost
|
||||||
|
and the estimated risk (number of broken projects) if it's removed.
|
||||||
|
|
||||||
|
The maintenance cost does not only come from the code implementing the
|
||||||
|
backward compatibility, but come also from additional tests.
|
||||||
|
|
||||||
|
|
||||||
|
Cases excluded from backward compatibility
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
The performance overhead of a compatibility code must be low when
|
||||||
|
``sys.set_python_compat_version()`` is not called.
|
||||||
|
|
||||||
|
The C API is out of the scope of this PEP: ``Py_LIMITED_API`` macro and
|
||||||
|
the stable ABI are solving this problem differently, see the `PEP 384:
|
||||||
|
Defining a Stable ABI <https://www.python.org/dev/peps/pep-0384/>`_.
|
||||||
|
|
||||||
|
Security fixes which break the backward compatibility on purpose will
|
||||||
|
not get a compatibility layer. Security matters more than compatibility.
|
||||||
|
For example, ``http.client.HTTPSConnection`` was modified in Python
|
||||||
|
3.4.3 to performs all the necessary certificate and hostname checks by
|
||||||
|
default. It was a deliberate change motivated by the `PEP 476: Enabling
|
||||||
|
certificate verification by default for stdlib http clients
|
||||||
|
<https://www.python.org/dev/peps/pep-0476/>`_ (`bpo-22417
|
||||||
|
<https://bugs.python.org/issue22417>`_).
|
||||||
|
|
||||||
|
The Python language does not provide backward compatibility.
|
||||||
|
|
||||||
|
Changes which are not clearly incompatible are not covered by this PEP.
|
||||||
|
For example, Python 3.9 changed the default protocol in the ``pickle``
|
||||||
|
module to Protocol 4 which was first introduced in Python 3.4. This
|
||||||
|
change is backward compatible up to Python 3.4. There is no need to use
|
||||||
|
the Protocol 3 by default when compatibility with Python 3.8 is
|
||||||
|
requested.
|
||||||
|
|
||||||
|
New ``DeprecationWarning`` and ``PendingDeprecatingWarning`` warnings
|
||||||
|
of Python 3.9 will not be disabled in Python 3.8 compatibility mode.
|
||||||
|
If a project runs its test suite using ``-Werror`` (treat any warning as
|
||||||
|
an error), these warnings must be fixed, or specific deprecation
|
||||||
|
warnings must be ignored on a case by case basis.
|
||||||
|
|
||||||
|
|
||||||
|
Upgrade a project to a newer Python
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Without backward compatibility, all incompatible changes must be fixed
|
||||||
|
at once, which can be a blocker issue. It is even worse when a project
|
||||||
|
is upgraded to a newer Python which is separated by multiple releases
|
||||||
|
from the old Python.
|
||||||
|
|
||||||
|
Postponing an upgrade only makes things worse: each skipped release adds
|
||||||
|
more incompatible changes. The technical debt is only steadily
|
||||||
|
increasing.
|
||||||
|
|
||||||
|
With backward compatibility, it becomes possible to upgrade Python
|
||||||
|
increamentally in a project, without having to fix all issues at once.
|
||||||
|
|
||||||
|
The "all-or-nothing" is a showstopper to port large Python 2 code bases
|
||||||
|
to Python 3. The list of incompatible changes between Python 2 and
|
||||||
|
Python 3 is long, and it's getting longer at each Python 3.x release.
|
||||||
|
|
||||||
|
|
||||||
|
Cleaning up Python and DeprecationWarning
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
One of the `Zen of Python (PEP 20)
|
||||||
|
<https://www.python.org/dev/peps/pep-0020/>`_ motto is:
|
||||||
|
|
||||||
|
There should be one-- and preferably only one --obvious way to do
|
||||||
|
it.
|
||||||
|
|
||||||
|
When Python evolves, new ways emerge inevitably. ``DeprecationWarning``
|
||||||
|
are emitted to suggest to use the new way, but many developers ignore
|
||||||
|
these warnings, which are silent by default (except in the ``__main__``
|
||||||
|
module: see the `PEP 565 <https://www.python.org/dev/peps/pep-0565/>_`).
|
||||||
|
Some developers simply ignore all warnings since they are too many
|
||||||
|
warnings, and so only bother with exceptions when deprecated code is
|
||||||
|
removed.
|
||||||
|
|
||||||
|
Sometimes, supporting both ways has a minor maintenance cost, but
|
||||||
|
developers prefer to drop the old way to clean up the code. Such kind of
|
||||||
|
change is backward incompatible.
|
||||||
|
|
||||||
|
Some developers can take the end of the Python 2 support as an
|
||||||
|
opportunity to push even more incompatible changes than usual.
|
||||||
|
|
||||||
|
Adding backward compatibility as an opt-in prevents to break
|
||||||
|
applications and allows developers to continue to do such cleanup.
|
||||||
|
|
||||||
|
|
||||||
|
Redistribute the maintenance burden
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
The backward compatibility involves authors of backward incompatible
|
||||||
|
changes more in the upgrade path.
|
||||||
|
|
||||||
|
|
||||||
|
Examples of backward compatibility
|
||||||
|
==================================
|
||||||
|
|
||||||
|
collections ABC aliases
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
``collections.abc`` aliases to ABC classes have been removed from the
|
||||||
|
``collections`` module in Python 3.9, after being deprecated since
|
||||||
|
Python 3.3. For example, ``collections.Mapping`` no longer exists.
|
||||||
|
|
||||||
|
In Python 3.6, aliases were created in ``collections/__init__.py`` by
|
||||||
|
``from _collections_abc import *``.
|
||||||
|
|
||||||
|
In Python 3.7, a ``__getattr__()`` has been added to the ``collections``
|
||||||
|
module to emit a DeprecationWarning at the first access to an
|
||||||
|
attribute::
|
||||||
|
|
||||||
|
def __getattr__(name):
|
||||||
|
# For backwards compatibility, continue to make the collections ABCs
|
||||||
|
# through Python 3.6 available through the collections module.
|
||||||
|
# Note, no new collections ABCs were added in Python 3.7
|
||||||
|
if name in _collections_abc.__all__:
|
||||||
|
obj = getattr(_collections_abc, name)
|
||||||
|
import warnings
|
||||||
|
warnings.warn("Using or importing the ABCs from 'collections' instead "
|
||||||
|
"of from 'collections.abc' is deprecated since Python 3.3, "
|
||||||
|
"and in 3.9 it will stop working",
|
||||||
|
DeprecationWarning, stacklevel=2)
|
||||||
|
globals()[name] = obj
|
||||||
|
return obj
|
||||||
|
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|
||||||
|
|
||||||
|
Compatibility with Python 3.8 can be restored in Python 3.9 by adding
|
||||||
|
back the ``__getattr__()`` function, but only when backward
|
||||||
|
compatibility is requested::
|
||||||
|
|
||||||
|
def __getattr__(name):
|
||||||
|
if (sys.get_python_compat_version() < (3, 9)
|
||||||
|
and name in _collections_abc.__all__):
|
||||||
|
...
|
||||||
|
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|
||||||
|
|
||||||
|
|
||||||
|
Deprecated open() "U" mode
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
The "U" mode of ``open()`` is deprecated since Python 3.4 and emits a
|
||||||
|
``DeprecationWarning``. The `bpo-37330
|
||||||
|
<https://bugs.python.org/issue37330>`_ proposes to drop this mode:
|
||||||
|
``open()`` would raise an exception if ``U`` mode is used.
|
||||||
|
|
||||||
|
This change falls into the "cleanup" category: it is not required to
|
||||||
|
implement a feature.
|
||||||
|
|
||||||
|
A backward compatibility mode would be trivial to implement and would be
|
||||||
|
welcomed here by users.
|
||||||
|
|
||||||
|
|
||||||
|
Specification
|
||||||
|
=============
|
||||||
|
|
||||||
|
sys functions
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Add 3 functions to the ``sys`` module:
|
||||||
|
|
||||||
|
* ``sys.set_python_compat_version(version)``: set the Python
|
||||||
|
compatibility version. If it has been called previously, use the
|
||||||
|
minimum of requested versions. Raise an exception if
|
||||||
|
``sys.set_python_min_compat_version(min_version)`` has been called and
|
||||||
|
``version < min_version``.
|
||||||
|
*version* must be greater than or equal to ``(3, 0)``.
|
||||||
|
|
||||||
|
* ``sys.set_python_min_compat_version(min_version)``: set the
|
||||||
|
**minimum** compatibility version. Raise an exception if
|
||||||
|
``sys.set_python_compat_version(old_version)`` has been called
|
||||||
|
previously and ``old_version < min_version``.
|
||||||
|
*min_version* must be greater than or equal to ``(3, 0)``.
|
||||||
|
|
||||||
|
* ``sys.get_python_compat_version()``: get the Python compatibility
|
||||||
|
version. Return a ``tuple`` of 3 integers.
|
||||||
|
|
||||||
|
A *version* must a tuple of 2 or 3 integers. ``(major, minor)`` version
|
||||||
|
is equivalent to ``(major, minor, 0)``.
|
||||||
|
|
||||||
|
By default, ``sys.get_python_compat_version()`` returns the current
|
||||||
|
Python version.
|
||||||
|
|
||||||
|
Example to request compatibility with Python 3.8.0::
|
||||||
|
|
||||||
|
import collections
|
||||||
|
|
||||||
|
sys.set_python_compat_version((3, 8))
|
||||||
|
|
||||||
|
# collections.Mapping alias, removed from Python 3.9, is available
|
||||||
|
# again, even if collections has been imported before calling
|
||||||
|
# set_python_compat_version().
|
||||||
|
parent = collections.Mapping
|
||||||
|
|
||||||
|
Obviously, calling ``sys.set_python_compat_version(version)`` has no
|
||||||
|
effect on code executed before the call. Use ``-X
|
||||||
|
compat_version=VERSION`` command line option or
|
||||||
|
``PYTHONCOMPATVERSIONVERSION=VERSION`` environment variable to set the
|
||||||
|
compatibility version at Python startup.
|
||||||
|
|
||||||
|
Command line
|
||||||
|
------------
|
||||||
|
|
||||||
|
Add ``-X compat_version=VERSION`` and ``-X min_compat_version=VERSION``
|
||||||
|
command line options: call respectivelly
|
||||||
|
``sys.set_python_compat_version()`` and
|
||||||
|
``sys.set_python_min_compat_version()``. ``VERSION`` is a version string
|
||||||
|
with 2 or 3 numbers (``major.minor.micro`` or ``major.minor``). For
|
||||||
|
example, ``-X compat_version=3.8`` calls
|
||||||
|
``sys.set_python_compat_version((3, 8))``.
|
||||||
|
|
||||||
|
Add ``PYTHONCOMPATVERSIONVERSION=VERSION`` and
|
||||||
|
``PYTHONCOMPATMINVERSION=VERSION=VERSION`` environment variables: call
|
||||||
|
respectivelly ``sys.set_python_compat_version()`` and
|
||||||
|
``sys.set_python_min_compat_version()``. ``VERSION`` is a version
|
||||||
|
string with the same format that the command line options.
|
||||||
|
|
||||||
|
|
||||||
|
Backwards Compatibility
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Introducing ``sys.set_python_compat_version()`` function means that an
|
||||||
|
application will behave differently depending on the compatibility
|
||||||
|
version. Moreover, since the version can be decreased multiple times,
|
||||||
|
the application can behave differently depending on the import order.
|
||||||
|
|
||||||
|
Python 3.9 with ``sys.set_python_compat_version((3, 8))`` is not fully
|
||||||
|
compatible with Python 3.8: the compatibility is only partial.
|
||||||
|
|
||||||
|
|
||||||
|
Security Implications
|
||||||
|
=====================
|
||||||
|
|
||||||
|
``sys.set_python_compat_version()`` must not disable security fixes.
|
||||||
|
|
||||||
|
|
||||||
|
Alternatives
|
||||||
|
============
|
||||||
|
|
||||||
|
Provide a workaround for each incompatible change
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
An application can works around most of the incompatible changes which
|
||||||
|
impacts it.
|
||||||
|
|
||||||
|
For example, ``collections`` aliases can be added again using::
|
||||||
|
|
||||||
|
import collections.abc
|
||||||
|
collections.Mapping = collections.abc.Mapping
|
||||||
|
collections.Sequence = collections.abc.Sequence
|
||||||
|
|
||||||
|
Handle backward compatibility in the parser
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
The parser is modified to support multiple versions of the Python
|
||||||
|
language (grammar).
|
||||||
|
|
||||||
|
The current Python parser cannot be easily modified for that. AST and
|
||||||
|
grammar are hardcoded to a single Python version.
|
||||||
|
|
||||||
|
In Python 3.8, ``compile()`` has an undocumented
|
||||||
|
``_feature_version`` to not consider ``async`` and ``await`` as
|
||||||
|
keywords.
|
||||||
|
|
||||||
|
The latest major language backward incompatible change was Python 3.7
|
||||||
|
which made ``async`` and ``await`` real keywords. It seems like Twisted
|
||||||
|
was the only affected project, and Twisted had a single affected
|
||||||
|
function (it used a parameter called ``async``).
|
||||||
|
|
||||||
|
Handling backward compatibility in the parser seems quite complex, not
|
||||||
|
only to modify the parser, but also for developers who have to check
|
||||||
|
which version of the Python language is used.
|
||||||
|
|
||||||
|
from __future__ import python38_syntax
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Add ``pythonXY_syntax`` to the ``__future__`` module. It would enable
|
||||||
|
backward compatibility with Python X.Y syntax, but only for the current
|
||||||
|
file.
|
||||||
|
|
||||||
|
With this option, there is no need to change
|
||||||
|
``sys.implementation.cache_tag`` to use a different ``.pyc`` filename,
|
||||||
|
since the parser would always produce the same output for the same input
|
||||||
|
(except of the optimization level).
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
from __future__ import python35_syntax
|
||||||
|
|
||||||
|
async = 1
|
||||||
|
await = 2
|
||||||
|
|
||||||
|
Update cache_tag
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Modify the parser to use ``sys.get_python_compat_version()`` to choose
|
||||||
|
the version of the Python language.
|
||||||
|
|
||||||
|
``sys.set_python_compat_version()`` updates
|
||||||
|
``sys.implementation.cache_tag`` to include the compatibility version
|
||||||
|
without the micro version as a suffix. For example, Python 3.9 uses
|
||||||
|
``'cpython-39'`` by default, but
|
||||||
|
``sys.set_python_compat_version((3, 7, 2))`` sets ``cache_tag`` to
|
||||||
|
``'cpython-39-37'``. Changes of the Python language are now allowed
|
||||||
|
in micro releases.
|
||||||
|
|
||||||
|
One problem is that ``import asyncio`` is likely to fail if
|
||||||
|
``sys.set_python_compat_version((3, 6))`` has been called previously.
|
||||||
|
The code of the ``asyncio`` module requires ``async`` and ``await`` to
|
||||||
|
be real keywords (change done in Python 3.7).
|
||||||
|
|
||||||
|
Another problem is that regular users cannot write ``.pyc`` files into
|
||||||
|
system directories, and so cannot create them on demand. It means that
|
||||||
|
``.pyc`` optimization cannot be used in the backward compatibility mode.
|
||||||
|
|
||||||
|
One solution for that is to modify the Python installer and Python
|
||||||
|
package installers to precompile ``.pyc`` files not only for the current
|
||||||
|
Python version, but also for multiple older Python versions (up to
|
||||||
|
Python 3.0?).
|
||||||
|
|
||||||
|
Each ``.py`` file would have 3n ``.pyc`` files (3 optimization levels),
|
||||||
|
where ``n`` is the number of supported Python versions. For example, it
|
||||||
|
means 6 ``.pyc`` files, instead of 3, to support Python 3.8 and Python
|
||||||
|
3.9.
|
||||||
|
|
||||||
|
|
||||||
|
Temporary moratorium on incompatible changes
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
In 2009, the PEP 3003 "Python Language Moratorium" proposed to a
|
||||||
|
temporary moratorium (suspension) of all changes to the Python language
|
||||||
|
syntax, semantics, and built-ins for Python 3.1 and Python 3.2.
|
||||||
|
|
||||||
|
In May 2018, during PEP 572 discussions, it was also proposed to slow
|
||||||
|
down Python changes: see the python-dev thread `Slow down...
|
||||||
|
<https://mail.python.org/archives/list/python-dev@python.org/thread/HHKRXOMRJQH75VNM3JMSQIOOU6MIUB24/#PHA35EAPNONZMTOYBINGFR6XXNMCDPFQ>`_
|
||||||
|
|
||||||
|
`Barry Warsaw's call on this
|
||||||
|
<https://mail.python.org/archives/list/python-dev@python.org/message/XR7IF2OB3S72KBP3PEQ3IKBOERE4FV2I/>`_:
|
||||||
|
|
||||||
|
I don’t believe that the way for Python to remain relevant and
|
||||||
|
useful for the next 10 years is to cease all language evolution.
|
||||||
|
Who knows what the computing landscape will look like in 5 years,
|
||||||
|
let alone 10? Something as arbitrary as a 10 year moratorium is
|
||||||
|
(again, IMHO) a death sentence for the language.
|
||||||
|
|
||||||
|
PEP 387
|
||||||
|
-------
|
||||||
|
|
||||||
|
`PEP 387 -- Backwards Compatibility Policy
|
||||||
|
<https://www.python.org/dev/peps/pep-0387/>`_ proposes a process to make
|
||||||
|
incompatible changes. The main point is the 4th step of the process:
|
||||||
|
|
||||||
|
See if there's any feedback. Users not involved in the original
|
||||||
|
discussions may comment now after seeing the warning. Perhaps
|
||||||
|
reconsider.
|
||||||
|
|
||||||
|
PEP 497
|
||||||
|
-------
|
||||||
|
|
||||||
|
`PEP 497 -- A standard mechanism for backward compatibility
|
||||||
|
<https://www.python.org/dev/peps/pep-0497/>`_ proposes different
|
||||||
|
solutions to provide backward compatibility.
|
||||||
|
|
||||||
|
Except of the ``__past__`` mechanism idea, the PEP 497 does not propose
|
||||||
|
concrete solutions:
|
||||||
|
|
||||||
|
When an incompatible change to core language syntax or semantics is
|
||||||
|
being made, Python-dev's policy is to prefer and expect that,
|
||||||
|
wherever possible, a mechanism for backward compatibility be
|
||||||
|
considered and provided for future Python versions after the
|
||||||
|
breaking change is adopted by default, in addition to any mechanisms
|
||||||
|
proposed for forward compatibility such as new future_statements.
|
||||||
|
|
||||||
|
|
||||||
|
Examples of incompatible changes
|
||||||
|
================================
|
||||||
|
|
||||||
|
Python 3.8
|
||||||
|
----------
|
||||||
|
|
||||||
|
Examples of Python 3.8 incompatible changes:
|
||||||
|
|
||||||
|
* (During beta phase) ``PyCode_New()`` required a new parameter: it
|
||||||
|
broke all Cython extensions (all projects distributing precompiled
|
||||||
|
Cython code). This change has been reverted during the 3.8 beta phase
|
||||||
|
and a new ``PyCode_NewWithPosOnlyArgs()`` function was added instead.
|
||||||
|
|
||||||
|
* ``types.CodeType`` requires an additional mandatory parameter.
|
||||||
|
The ``CodeType.replace()`` function was added to help projects to no
|
||||||
|
longer depend on the exact signature of the ``CodeType`` constructor.
|
||||||
|
|
||||||
|
* C extensions are no longer linked to libpython.
|
||||||
|
|
||||||
|
* ``sys.abiflags`` changed from ``'m'`` to an empty string.
|
||||||
|
For example, ``python3.8m`` program is gone.
|
||||||
|
|
||||||
|
* The C structure ``PyInterpreterState`` was made opaque.
|
||||||
|
|
||||||
|
* Blender:
|
||||||
|
|
||||||
|
* https://bugzilla.redhat.com/show_bug.cgi?id=1734980#c6
|
||||||
|
* https://developer.blender.org/D6038
|
||||||
|
|
||||||
|
* XML attribute order: `bpo-34160
|
||||||
|
<https://bugs.python.org/issue34160>`_. Broken projects:
|
||||||
|
|
||||||
|
* `coverage <https://bugs.python.org/issue34160#msg329612>`_
|
||||||
|
* `docutils <https://sourceforge.net/p/docutils/bugs/359/>`_
|
||||||
|
* `pcs <https://bugzilla.redhat.com/show_bug.cgi?id=1705475>`_
|
||||||
|
* `python-glyphsLib
|
||||||
|
<https://bugzilla.redhat.com/show_bug.cgi?id=1705391>`_
|
||||||
|
|
||||||
|
Backward compatibility cannot be added for all these changes. For
|
||||||
|
example, changes in the C API and in the build system are out of the
|
||||||
|
scope of this PEP.
|
||||||
|
|
||||||
|
See `What’s New In Python 3.8: API and Feature Removals
|
||||||
|
<https://docs.python.org/dev/whatsnew/3.8.html#api-and-feature-removals>`_
|
||||||
|
for all changes.
|
||||||
|
|
||||||
|
See also the `Porting to Python 3.8
|
||||||
|
<https://docs.python.org/dev/whatsnew/3.8.html#porting-to-python-3-8>`_
|
||||||
|
section of What’s New In Python 3.8.
|
||||||
|
|
||||||
|
|
||||||
|
Python 3.7
|
||||||
|
----------
|
||||||
|
|
||||||
|
Examples of Python 3.7 incompatible changes:
|
||||||
|
|
||||||
|
* ``async`` and ``await`` are now reserved keywords.
|
||||||
|
* Several undocumented internal imports were removed. One example is
|
||||||
|
that ``os.errno`` is no longer available; use ``import errno``
|
||||||
|
directly instead. Note that such undocumented internal imports may be
|
||||||
|
removed any time without notice, even in micro version releases.
|
||||||
|
* Unknown escapes consisting of ``'\'`` and an ASCII letter in
|
||||||
|
replacement templates for ``re.sub()`` were deprecated in Python 3.5,
|
||||||
|
and will now cause an error.
|
||||||
|
* The ``asyncio.windows_utils.socketpair()`` function has been removed:
|
||||||
|
it was an alias to ``socket.socketpair()``.
|
||||||
|
* ``asyncio`` no longer exports the ``selectors`` and ``_overlapped``
|
||||||
|
modules as ``asyncio.selectors`` and ``asyncio._overlapped``. Replace
|
||||||
|
``from asyncio import selectors`` with ``import selectors``.
|
||||||
|
* PEP 479 is enabled for all code in Python 3.7, meaning that
|
||||||
|
``StopIteration`` exceptions raised directly or indirectly in
|
||||||
|
coroutines and generators are transformed into ``RuntimeError``
|
||||||
|
exceptions.
|
||||||
|
* ``socketserver.ThreadingMixIn.server_close()`` now waits until all
|
||||||
|
non-daemon threads complete. Set the new ``block_on_close`` class
|
||||||
|
attribute to ``False`` to get the pre-3.7 behaviour.
|
||||||
|
* The ``struct.Struct.format`` type is now ``str`` instead of
|
||||||
|
``bytes``.
|
||||||
|
* ``repr`` for ``datetime.timedelta`` has changed to include the keyword
|
||||||
|
arguments in the output.
|
||||||
|
* ``tracemalloc.Traceback`` frames are now sorted from oldest to most
|
||||||
|
recent to be more consistent with ``traceback``.
|
||||||
|
|
||||||
|
Adding backward compatibility for most of these changes would be easy.
|
||||||
|
|
||||||
|
See also the `Porting to Python 3.7
|
||||||
|
<https://docs.python.org/dev/whatsnew/3.7.html#porting-to-python-3-7>`_
|
||||||
|
section of What’s New In Python 3.7.
|
||||||
|
|
||||||
|
|
||||||
|
Micro releases
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Sometimes, incompatible changes are introduced in micro releases
|
||||||
|
(``micro`` in ``major.minor.micro``) to fix bugs or security
|
||||||
|
vulnerabilities. Examples:
|
||||||
|
|
||||||
|
* Python 3.7.2, ``compileall`` and ``py_compile`` module: the
|
||||||
|
*invalidation_mode* parameter's default value is updated to ``None``;
|
||||||
|
the ``SOURCE_DATE_EPOCH`` environment variable no longer
|
||||||
|
overrides the value of the *invalidation_mode* argument, and
|
||||||
|
determines its default value instead.
|
||||||
|
|
||||||
|
* Python 3.7.1, ``xml`` modules: the SAX parser no longer processes
|
||||||
|
general external entities by default to increase security by default.
|
||||||
|
|
||||||
|
* Python 3.5.2, ``os.urandom()``: on Linux, if the ``getrandom()``
|
||||||
|
syscall blocks (the urandom entropy pool is not initialized yet), fall
|
||||||
|
back on reading ``/dev/urandom``.
|
||||||
|
|
||||||
|
* Python 3.5.1, ``sys.setrecursionlimit()``: a ``RecursionError``
|
||||||
|
exception is now raised if the new limit is too low at the current
|
||||||
|
recursion depth.
|
||||||
|
|
||||||
|
* Python 3.4.4, ``ssl.create_default_context()``: RC4 was dropped from
|
||||||
|
the default cipher string.
|
||||||
|
|
||||||
|
* Python 3.4.3, ``http.client``: ``HTTPSConnection`` now performs all
|
||||||
|
the necessary certificate and hostname checks by default.
|
||||||
|
|
||||||
|
* Python 3.4.2, ``email.message``: ``EmailMessage.is_attachment()`` is
|
||||||
|
now a method instead of a property, for consistency with
|
||||||
|
``Message.is_multipart()``.
|
||||||
|
|
||||||
|
* Python 3.4.1, ``os.makedirs(name, mode=0o777, exist_ok=False)``:
|
||||||
|
Before Python 3.4.1, if *exist_ok* was ``True`` and the directory
|
||||||
|
existed, ``makedirs()`` would still raise an error if *mode* did not
|
||||||
|
match the mode of the existing directory. Since this behavior was
|
||||||
|
impossible to implement safely, it was removed in Python 3.4.1
|
||||||
|
(`bpo-21082 <https://bugs.python.org/issue21082>`_).
|
||||||
|
|
||||||
|
Examples of changes made in micro releases which are not backward
|
||||||
|
incompatible:
|
||||||
|
|
||||||
|
* ``ssl.OP_NO_TLSv1_3`` constant was added to 2.7.15, 3.6.3 and 3.7.0
|
||||||
|
for backwards compatibility with OpenSSL 1.0.2.
|
||||||
|
* ``typing.AsyncContextManager`` was added to Python 3.6.2.
|
||||||
|
* The ``zipfile`` module accepts a path-like object since Python 3.6.2.
|
||||||
|
* ``loop.create_future()`` was added to Python 3.5.2 in the ``asyncio``
|
||||||
|
module.
|
||||||
|
|
||||||
|
No backward compatibility code is needed for such kind of changes.
|
||||||
|
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
Accepted PEPs:
|
||||||
|
|
||||||
|
* `PEP 5 -- Guidelines for Language Evolution
|
||||||
|
<https://www.python.org/dev/peps/pep-0005/>`_
|
||||||
|
* `PEP 236 -- Back to the __future__
|
||||||
|
<https://www.python.org/dev/peps/pep-0236/>`_
|
||||||
|
* `PEP 411 -- Provisional packages in the Python standard library
|
||||||
|
<https://www.python.org/dev/peps/pep-0411/>`_
|
||||||
|
* `PEP 3002 -- Procedure for Backwards-Incompatible Changes
|
||||||
|
<https://www.python.org/dev/peps/pep-3002/>`_
|
||||||
|
|
||||||
|
Draft PEPs:
|
||||||
|
|
||||||
|
* `PEP 602 -- Annual Release Cycle for Python
|
||||||
|
<https://www.python.org/dev/peps/pep-0602/>`_
|
||||||
|
* `PEP 605 -- A rolling feature release stream for CPython
|
||||||
|
<https://www.python.org/dev/peps/pep-0605/>`_
|
||||||
|
* See also withdrawn `PEP 598 -- Introducing incremental feature
|
||||||
|
releases <https://www.python.org/dev/peps/pep-0598/>`_
|
||||||
|
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
|
This document is placed in the public domain or under the
|
||||||
|
CC0-1.0-Universal license, whichever is more permissive.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
..
|
||||||
|
Local Variables:
|
||||||
|
mode: indented-text
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
sentence-end-double-space: t
|
||||||
|
fill-column: 70
|
||||||
|
coding: utf-8
|
||||||
|
End:
|
Loading…
Reference in New Issue