626 lines
23 KiB
ReStructuredText
626 lines
23 KiB
ReStructuredText
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:
|