diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst
index 0c0dca9..06bdd0d 100644
--- a/Doc/tutorial/classes.rst
+++ b/Doc/tutorial/classes.rst
@@ -143,10 +143,10 @@ language definition is evolving towards static name resolution, at "compile"
time, so don't rely on dynamic name resolution! (In fact, local variables are
already determined statically.)
-A special quirk of Python is that -- if no :keyword:`global` statement is in
-effect -- assignments to names always go into the innermost scope. Assignments
-do not copy data --- they just bind names to objects. The same is true for
-deletions: the statement ``del x`` removes the binding of ``x`` from the
+A special quirk of Python is that -- if no :keyword:`global` or :keyword:`nonlocal`
+statement is in effect -- assignments to names always go into the innermost scope.
+Assignments do not copy data --- they just bind names to objects. The same is true
+for deletions: the statement ``del x`` removes the binding of ``x`` from the
namespace referenced by the local scope. In fact, all operations that introduce
new names use the local scope: in particular, :keyword:`import` statements and
function definitions bind the module or function name in the local scope.
@@ -323,7 +323,7 @@ Instance Objects
Now what can we do with instance objects? The only operations understood by
instance objects are attribute references. There are two kinds of valid
-attribute names, data attributes and methods.
+attribute names: data attributes and methods.
*data attributes* correspond to "instance variables" in Smalltalk, and to "data
members" in C++. Data attributes need not be declared; like local variables,
diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst
index 7dfd33a..f05f5ed 100644
--- a/Doc/tutorial/controlflow.rst
+++ b/Doc/tutorial/controlflow.rst
@@ -142,7 +142,7 @@ the list, thus saving space.
We say such an object is :term:`iterable`, that is, suitable as a target for
functions and constructs that expect something from which they can
obtain successive items until the supply is exhausted. We have seen that
-the :keyword:`for` statement is such a construct, while an example of function
+the :keyword:`for` statement is such a construct, while an example of a function
that takes an iterable is :func:`sum`::
>>> sum(range(4)) # 0 + 1 + 2 + 3
diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst
index 2f7afb0..0edb73a 100644
--- a/Doc/tutorial/datastructures.rst
+++ b/Doc/tutorial/datastructures.rst
@@ -676,9 +676,10 @@ to a variable. For example, ::
'Trondheim'
Note that in Python, unlike C, assignment inside expressions must be done
-explicitly with the walrus operator ``:=``. This avoids a common class of
-problems encountered in C programs: typing ``=`` in an expression when ``==``
-was intended.
+explicitly with the
+:ref:`walrus operator ` ``:=``.
+This avoids a common class of problems encountered in C programs: typing ``=``
+in an expression when ``==`` was intended.
.. _tut-comparing:
diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst
index 4bc7184..27c67c6 100644
--- a/Doc/tutorial/errors.rst
+++ b/Doc/tutorial/errors.rst
@@ -341,15 +341,33 @@ example::
File "", line 2, in
KeyboardInterrupt
-If a :keyword:`finally` clause is present, the :keyword:`finally` clause will execute as the last task before the :keyword:`try` statement completes. The :keyword:`finally` clause runs whether or not the :keyword:`try` statement produces an exception. The following points discuss more complex cases when an exception occurs:
-
-* If an exception occurs during execution of the :keyword:`!try` clause, the exception may be handled by an :keyword:`except` clause. If the exception is not handled by an :keyword:`except` clause, the exception is re-raised after the :keyword:`!finally` clause has been executed.
-
-* An exception could occur during execution of an :keyword:`!except` or :keyword:`!else` clause. Again, the exception is re-raised after the :keyword:`!finally` clause has been executed.
-
-* If the :keyword:`!try` statement reaches a :keyword:`break`, :keyword:`continue` or :keyword:`return` statement, the :keyword:`finally` clause will execute just prior to the :keyword:`break`, :keyword:`continue` or :keyword:`return` statement's execution.
-
-* If a :keyword:`finally` clause includes a :keyword:`return` statement, the :keyword:`finally` clause's :keyword:`return` statement will execute before, and instead of, the :keyword:`return` statement in a :keyword:`try` clause.
+If a :keyword:`finally` clause is present, the :keyword:`!finally`
+clause will execute as the last task before the :keyword:`try`
+statement completes. The :keyword:`!finally` clause runs whether or
+not the :keyword:`!try` statement produces an exception. The following
+points discuss more complex cases when an exception occurs:
+
+* If an exception occurs during execution of the :keyword:`!try`
+ clause, the exception may be handled by an :keyword:`except`
+ clause. If the exception is not handled by an :keyword:`!except`
+ clause, the exception is re-raised after the :keyword:`!finally`
+ clause has been executed.
+
+* An exception could occur during execution of an :keyword:`!except`
+ or :keyword:`!else` clause. Again, the exception is re-raised after
+ the :keyword:`!finally` clause has been executed.
+
+* If the :keyword:`!try` statement reaches a :keyword:`break`,
+ :keyword:`continue` or :keyword:`return` statement, the
+ :keyword:`!finally` clause will execute just prior to the
+ :keyword:`!break`, :keyword:`!continue` or :keyword:`!return`
+ statement's execution.
+
+* If a :keyword:`!finally` clause includes a :keyword:`!return`
+ statement, the returned value will be the one from the
+ :keyword:`!finally` clause's :keyword:`!return` statement, not the
+ value from the :keyword:`!try` clause's :keyword:`!return`
+ statement.
For example::
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index c30f6fc..d3f0400 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -109,8 +109,8 @@ source.
Many standard library modules contain code that is invoked on their execution
as a script. An example is the :mod:`timeit` module::
- python -mtimeit -s 'setup here' 'benchmarked code here'
- python -mtimeit -h # for details
+ python -m timeit -s 'setup here' 'benchmarked code here'
+ python -m timeit -h # for details
.. audit-event:: cpython.run_module module-name cmdoption-m
@@ -936,8 +936,6 @@ conflict.
Also available as the :option:`-X` ``utf8`` option.
- .. availability:: \*nix.
-
.. versionadded:: 3.7
See :pep:`540` for more details.
diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc
index 1b24721..99b2a19 100644
--- a/Doc/using/venv-create.inc
+++ b/Doc/using/venv-create.inc
@@ -78,6 +78,17 @@ The command, if run with ``-h``, will show the available options::
particular note is that double-clicking ``python.exe`` in File Explorer
will resolve the symlink eagerly and ignore the virtual environment.
+.. note::
+ On Microsoft Windows, it may be required to enable the ``Activate.ps1``
+ script by setting the execution policy for the user. You can do this by
+ issuing the following PowerShell command:
+
+ PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
+
+ See `About Execution Policies
+ `_
+ for more information.
+
The created ``pyvenv.cfg`` file also includes the
``include-system-site-packages`` key, set to ``true`` if ``venv`` is
run with the ``--system-site-packages`` option, ``false`` otherwise.
diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst
index 9dc3e79..636f48d 100644
--- a/Doc/using/windows.rst
+++ b/Doc/using/windows.rst
@@ -602,6 +602,50 @@ existed)::
C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files\Python 3.8
+.. _win-utf8-mode:
+
+UTF-8 mode
+==========
+
+.. versionadded:: 3.7
+
+Windows still uses legacy encodings for the system encoding (the ANSI Code
+Page). Python uses it for the default encoding of text files (e.g.
+:func:`locale.getpreferredencoding`).
+
+This may cause issues because UTF-8 is widely used on the internet
+and most Unix systems, including WSL (Windows Subsystem for Linux).
+
+You can use UTF-8 mode to change the default text encoding to UTF-8.
+You can enable UTF-8 mode via the ``-X utf8`` command line option, or
+the ``PYTHONUTF8=1`` environment variable. See :envvar:`PYTHONUTF8` for
+enabling UTF-8 mode, and :ref:`setting-envvars` for how to modify
+environment variables.
+
+When UTF-8 mode is enabled:
+
+* :func:`locale.getpreferredencoding` returns ``'UTF-8'`` instead of
+ the system encoding. This function is used for the default text
+ encoding in many places, including :func:`open`, :class:`Popen`,
+ :meth:`Path.read_text`, etc.
+* :data:`sys.stdin`, :data:`sys.stdout`, and :data:`sys.stderr`
+ all use UTF-8 as their text encoding.
+* You can still use the system encoding via the "mbcs" codec.
+
+Note that adding ``PYTHONUTF8=1`` to the default environment variables
+will affect all Python 3.7+ applications on your system.
+If you have any Python 3.7+ applications which rely on the legacy
+system encoding, it is recommended to set the environment variable
+temporarily or use the ``-X utf8`` command line option.
+
+.. note::
+ Even when UTF-8 mode is disabled, Python uses UTF-8 by default
+ on Windows for:
+
+ * Console I/O including standard I/O (see :pep:`528` for details).
+ * The filesystem encoding (see :pep:`529` for details).
+
+
.. _launcher:
Python Launcher for Windows
diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst
index 880958d..6b8bd88 100644
--- a/Doc/whatsnew/3.0.rst
+++ b/Doc/whatsnew/3.0.rst
@@ -2,6 +2,8 @@
What's New In Python 3.0
****************************
+TEST CHANGE TO BE UNDONE
+
.. XXX Add trademark info for Apple, Microsoft.
:Author: Guido van Rossum
diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
index 8a70fe2..b9b5021 100644
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -493,6 +493,11 @@ of this mode.
Other Language Changes
======================
+* An :keyword:`await` expression and comprehensions containing an
+ :keyword:`async for` clause were illegal in the expressions in
+ :ref:`formatted string literals ` due to a problem with the
+ implementation. In Python 3.7 this restriction was lifted.
+
* More than 255 arguments can now be passed to a function, and a function can
now have more than 255 parameters. (Contributed by Serhiy Storchaka in
:issue:`12844` and :issue:`18896`.)
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 546fa2d..d2db5bf 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -144,12 +144,11 @@ However, these are invalid calls::
One use case for this notation is that it allows pure Python functions
to fully emulate behaviors of existing C coded functions. For example,
-the built-in :func:`pow` function does not accept keyword arguments::
+the built-in :func:`divmod` function does not accept keyword arguments::
- def pow(x, y, z=None, /):
- "Emulate the built in pow() function"
- r = x ** y
- return r if z is None else r%z
+ def divmod(a, b, /):
+ "Emulate the built in divmod() function"
+ return (a // b, a % b)
Another use case is to preclude keyword arguments when the parameter
name is not helpful. For example, the builtin :func:`len` function has
@@ -727,7 +726,7 @@ csv
The :class:`csv.DictReader` now returns instances of :class:`dict` instead of
a :class:`collections.OrderedDict`. The tool is now faster and uses less
memory while still preserving the field order.
-(Contributed by Michael Seek in :issue:`34003`.)
+(Contributed by Michael Selik in :issue:`34003`.)
curses
@@ -1942,6 +1941,12 @@ Changes in the Python API
:exc:`dbm.gnu.error` or :exc:`dbm.ndbm.error`) instead of :exc:`KeyError`.
(Contributed by Xiang Zhang in :issue:`33106`.)
+* Simplified AST for literals. All constants will be represented as
+ :class:`ast.Constant` instances. Instantiating old classes ``Num``,
+ ``Str``, ``Bytes``, ``NameConstant`` and ``Ellipsis`` will return
+ an instance of ``Constant``.
+ (Contributed by Serhiy Storchaka in :issue:`32892`.)
+
* :func:`~os.path.expanduser` on Windows now prefers the :envvar:`USERPROFILE`
environment variable and does not use :envvar:`HOME`, which is not normally
set for regular user accounts.
@@ -2111,7 +2116,7 @@ Changes in the C API
.. code-block:: shell
- gendef python38.dll > tmp.def
+ gendef - python38.dll > tmp.def
dlltool --dllname python38.dll --def tmp.def --output-lib libpython38.a
The location of an installed :file:`pythonXY.dll` will depend on the
@@ -2205,7 +2210,13 @@ Here's a summary of performance improvements since Python 3.3:
Timing loop:
loop_overhead 0.3 0.5 0.6 0.4 0.3 0.3
- (Measured from the macOS 64-bit builds found at python.org)
+The benchmarks were measured on an
+`Intel® Core⢠i7-4960HQ processor
+`_
+running the macOS 64-bit builds found at
+`python.org `_.
+The benchmark script displays timings in nanoseconds.
+
Notable changes in Python 3.8.1
===============================
@@ -2216,3 +2227,18 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more
details, see the documentation for ``loop.create_datagram_endpoint()``.
(Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in
:issue:`37228`.)
+
+Notable changes in Python 3.8.2
+===============================
+
+Fixed a regression with the ``ignore`` callback of :func:`shutil.copytree`.
+The argument types are now str and List[str] again.
+(Contributed by Manuel Barkhau and Giampaolo Rodola in :issue:`39390`.)
+
+Notable changes in Python 3.8.3
+===============================
+
+The constant values of future flags in the :mod:`__future__` module
+are updated in order to prevent collision with compiler flags. Previously
+``PyCF_ALLOW_TOP_LEVEL_AWAIT`` was clashing with ``CO_FUTURE_DIVISION``.
+(Contributed by Batuhan Taskaya in :issue:`39562`)
diff --git a/Include/code.h b/Include/code.h
index 3afddd2..a1cd58f 100644
--- a/Include/code.h
+++ b/Include/code.h
@@ -88,19 +88,19 @@ typedef struct {
#define CO_ITERABLE_COROUTINE 0x0100
#define CO_ASYNC_GENERATOR 0x0200
-/* These are no longer used. */
-#if 0
-#define CO_GENERATOR_ALLOWED 0x1000
-#endif
-#define CO_FUTURE_DIVISION 0x2000
-#define CO_FUTURE_ABSOLUTE_IMPORT 0x4000 /* do absolute imports by default */
-#define CO_FUTURE_WITH_STATEMENT 0x8000
-#define CO_FUTURE_PRINT_FUNCTION 0x10000
-#define CO_FUTURE_UNICODE_LITERALS 0x20000
-
-#define CO_FUTURE_BARRY_AS_BDFL 0x40000
-#define CO_FUTURE_GENERATOR_STOP 0x80000
-#define CO_FUTURE_ANNOTATIONS 0x100000
+/* bpo-39562: These constant values are changed in Python 3.9
+ to prevent collision with compiler flags. CO_FUTURE_ and PyCF_
+ constants must be kept unique. PyCF_ constants can use bits from
+ 0x0100 to 0x10000. CO_FUTURE_ constants use bits starting at 0x20000. */
+#define CO_FUTURE_DIVISION 0x20000
+#define CO_FUTURE_ABSOLUTE_IMPORT 0x40000 /* do absolute imports by default */
+#define CO_FUTURE_WITH_STATEMENT 0x80000
+#define CO_FUTURE_PRINT_FUNCTION 0x100000
+#define CO_FUTURE_UNICODE_LITERALS 0x200000
+
+#define CO_FUTURE_BARRY_AS_BDFL 0x400000
+#define CO_FUTURE_GENERATOR_STOP 0x800000
+#define CO_FUTURE_ANNOTATIONS 0x1000000
/* This value is found in the co_cell2arg array when the associated cell
variable does not correspond to an argument. */
diff --git a/Include/compile.h b/Include/compile.h
index 1cda955..015584d 100644
--- a/Include/compile.h
+++ b/Include/compile.h
@@ -18,12 +18,18 @@ PyAPI_FUNC(PyCodeObject *) PyNode_Compile(struct _node *, const char *);
CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | \
CO_FUTURE_GENERATOR_STOP | CO_FUTURE_ANNOTATIONS)
#define PyCF_MASK_OBSOLETE (CO_NESTED)
+
+/* bpo-39562: CO_FUTURE_ and PyCF_ constants must be kept unique.
+ PyCF_ constants can use bits from 0x0100 to 0x10000.
+ CO_FUTURE_ constants use bits starting at 0x20000. */
#define PyCF_SOURCE_IS_UTF8 0x0100
#define PyCF_DONT_IMPLY_DEDENT 0x0200
#define PyCF_ONLY_AST 0x0400
#define PyCF_IGNORE_COOKIE 0x0800
#define PyCF_TYPE_COMMENTS 0x1000
#define PyCF_ALLOW_TOP_LEVEL_AWAIT 0x2000
+#define PyCF_COMPILE_MASK (PyCF_ONLY_AST | PyCF_ALLOW_TOP_LEVEL_AWAIT | \
+ PyCF_TYPE_COMMENTS | PyCF_DONT_IMPLY_DEDENT)
#ifndef Py_LIMITED_API
typedef struct {
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index 94b0809..e22b053 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -55,6 +55,7 @@ struct _ts {
struct _ts *next;
PyInterpreterState *interp;
+ /* Borrowed reference to the current frame (it can be NULL) */
struct _frame *frame;
int recursion_depth;
char overflowed; /* The stack has overflowed. Allow 50 more calls
diff --git a/Include/object.h b/Include/object.h
index cc98d8a..5558f65 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -29,7 +29,7 @@ of data it contains. An object's type is fixed when it is created.
Types themselves are represented as objects; an object contains a
pointer to the corresponding type object. The type itself has a type
pointer pointing to the object representing the type 'type', which
-contains a pointer to itself!).
+contains a pointer to itself!.
Objects do not float around in memory; once allocated an object keeps
the same size and address. Objects that must hold variable-size data
diff --git a/Include/patchlevel.h b/Include/patchlevel.h
index 6936a3f..2f6a68f 100644
--- a/Include/patchlevel.h
+++ b/Include/patchlevel.h
@@ -18,12 +18,12 @@
/*--start constants--*/
#define PY_MAJOR_VERSION 3
#define PY_MINOR_VERSION 8
-#define PY_MICRO_VERSION 1
+#define PY_MICRO_VERSION 3
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL
#define PY_RELEASE_SERIAL 0
/* Version as a string */
-#define PY_VERSION "3.8.1"
+#define PY_VERSION "3.8.3"
/*--end constants--*/
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
diff --git a/LICENSE b/LICENSE
index 9dc010d..66a3ac8 100644
--- a/LICENSE
+++ b/LICENSE
@@ -73,7 +73,7 @@ analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Python Software Foundation;
+2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
All Rights Reserved" are retained in Python alone or in any derivative version
prepared by Licensee.
diff --git a/Lib/__future__.py b/Lib/__future__.py
index e113568..d7cb8ac 100644
--- a/Lib/__future__.py
+++ b/Lib/__future__.py
@@ -68,14 +68,14 @@ __all__ = ["all_feature_names"] + all_feature_names
# this module.
CO_NESTED = 0x0010 # nested_scopes
CO_GENERATOR_ALLOWED = 0 # generators (obsolete, was 0x1000)
-CO_FUTURE_DIVISION = 0x2000 # division
-CO_FUTURE_ABSOLUTE_IMPORT = 0x4000 # perform absolute imports by default
-CO_FUTURE_WITH_STATEMENT = 0x8000 # with statement
-CO_FUTURE_PRINT_FUNCTION = 0x10000 # print function
-CO_FUTURE_UNICODE_LITERALS = 0x20000 # unicode string literals
-CO_FUTURE_BARRY_AS_BDFL = 0x40000
-CO_FUTURE_GENERATOR_STOP = 0x80000 # StopIteration becomes RuntimeError in generators
-CO_FUTURE_ANNOTATIONS = 0x100000 # annotations become strings at runtime
+CO_FUTURE_DIVISION = 0x20000 # division
+CO_FUTURE_ABSOLUTE_IMPORT = 0x40000 # perform absolute imports by default
+CO_FUTURE_WITH_STATEMENT = 0x80000 # with statement
+CO_FUTURE_PRINT_FUNCTION = 0x100000 # print function
+CO_FUTURE_UNICODE_LITERALS = 0x200000 # unicode string literals
+CO_FUTURE_BARRY_AS_BDFL = 0x400000
+CO_FUTURE_GENERATOR_STOP = 0x800000 # StopIteration becomes RuntimeError in generators
+CO_FUTURE_ANNOTATIONS = 0x1000000 # annotations become strings at runtime
class _Feature:
def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py
index db6674e..e9efce7 100644
--- a/Lib/_osx_support.py
+++ b/Lib/_osx_support.py
@@ -211,7 +211,7 @@ def _remove_universal_flags(_config_vars):
if cv in _config_vars and cv not in os.environ:
flags = _config_vars[cv]
flags = re.sub(r'-arch\s+\w+\s', ' ', flags, flags=re.ASCII)
- flags = re.sub('-isysroot [^ \t]*', ' ', flags)
+ flags = re.sub(r'-isysroot\s*\S+', ' ', flags)
_save_modified_value(_config_vars, cv, flags)
return _config_vars
@@ -287,7 +287,7 @@ def _check_for_unavailable_sdk(_config_vars):
# to /usr and /System/Library by either a standalone CLT
# package or the CLT component within Xcode.
cflags = _config_vars.get('CFLAGS', '')
- m = re.search(r'-isysroot\s+(\S+)', cflags)
+ m = re.search(r'-isysroot\s*(\S+)', cflags)
if m is not None:
sdk = m.group(1)
if not os.path.exists(sdk):
@@ -295,7 +295,7 @@ def _check_for_unavailable_sdk(_config_vars):
# Do not alter a config var explicitly overridden by env var
if cv in _config_vars and cv not in os.environ:
flags = _config_vars[cv]
- flags = re.sub(r'-isysroot\s+\S+(?:\s|$)', ' ', flags)
+ flags = re.sub(r'-isysroot\s*\S+(?:\s|$)', ' ', flags)
_save_modified_value(_config_vars, cv, flags)
return _config_vars
@@ -320,7 +320,7 @@ def compiler_fixup(compiler_so, cc_args):
stripArch = stripSysroot = True
else:
stripArch = '-arch' in cc_args
- stripSysroot = '-isysroot' in cc_args
+ stripSysroot = any(arg for arg in cc_args if arg.startswith('-isysroot'))
if stripArch or 'ARCHFLAGS' in os.environ:
while True:
@@ -338,23 +338,34 @@ def compiler_fixup(compiler_so, cc_args):
if stripSysroot:
while True:
- try:
- index = compiler_so.index('-isysroot')
+ indices = [i for i,x in enumerate(compiler_so) if x.startswith('-isysroot')]
+ if not indices:
+ break
+ index = indices[0]
+ if compiler_so[index] == '-isysroot':
# Strip this argument and the next one:
del compiler_so[index:index+2]
- except ValueError:
- break
+ else:
+ # It's '-isysroot/some/path' in one arg
+ del compiler_so[index:index+1]
# Check if the SDK that is used during compilation actually exists,
# the universal build requires the usage of a universal SDK and not all
# users have that installed by default.
sysroot = None
- if '-isysroot' in cc_args:
- idx = cc_args.index('-isysroot')
- sysroot = cc_args[idx+1]
- elif '-isysroot' in compiler_so:
- idx = compiler_so.index('-isysroot')
- sysroot = compiler_so[idx+1]
+ argvar = cc_args
+ indices = [i for i,x in enumerate(cc_args) if x.startswith('-isysroot')]
+ if not indices:
+ argvar = compiler_so
+ indices = [i for i,x in enumerate(compiler_so) if x.startswith('-isysroot')]
+
+ for idx in indices:
+ if argvar[idx] == '-isysroot':
+ sysroot = argvar[idx+1]
+ break
+ else:
+ sysroot = argvar[idx][len('-isysroot'):]
+ break
if sysroot and not os.path.isdir(sysroot):
from distutils import log
diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py
index c14d8ca..ab989e5 100644
--- a/Lib/_pydecimal.py
+++ b/Lib/_pydecimal.py
@@ -140,8 +140,11 @@ __all__ = [
# Limits for the C version for compatibility
'MAX_PREC', 'MAX_EMAX', 'MIN_EMIN', 'MIN_ETINY',
- # C version: compile time choice that enables the thread local context
- 'HAVE_THREADS'
+ # C version: compile time choice that enables the thread local context (deprecated, now always true)
+ 'HAVE_THREADS',
+
+ # C version: compile time choice that enables the coroutine local context
+ 'HAVE_CONTEXTVAR'
]
__xname__ = __name__ # sys.modules lookup (--without-threads)
@@ -172,6 +175,7 @@ ROUND_05UP = 'ROUND_05UP'
# Compatibility with the C version
HAVE_THREADS = True
+HAVE_CONTEXTVAR = True
if sys.maxsize == 2**63-1:
MAX_PREC = 999999999999999999
MAX_EMAX = 999999999999999999
diff --git a/Lib/argparse.py b/Lib/argparse.py
index fd61bc7..2dad5f1 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -2144,24 +2144,23 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
action = self._option_string_actions[option_string]
return action, option_string, explicit_arg
- if self.allow_abbrev or not arg_string.startswith('--'):
- # search through all possible prefixes of the option string
- # and all actions in the parser for possible interpretations
- option_tuples = self._get_option_tuples(arg_string)
-
- # if multiple actions match, the option string was ambiguous
- if len(option_tuples) > 1:
- options = ', '.join([option_string
- for action, option_string, explicit_arg in option_tuples])
- args = {'option': arg_string, 'matches': options}
- msg = _('ambiguous option: %(option)s could match %(matches)s')
- self.error(msg % args)
-
- # if exactly one action matched, this segmentation is good,
- # so return the parsed action
- elif len(option_tuples) == 1:
- option_tuple, = option_tuples
- return option_tuple
+ # search through all possible prefixes of the option string
+ # and all actions in the parser for possible interpretations
+ option_tuples = self._get_option_tuples(arg_string)
+
+ # if multiple actions match, the option string was ambiguous
+ if len(option_tuples) > 1:
+ options = ', '.join([option_string
+ for action, option_string, explicit_arg in option_tuples])
+ args = {'option': arg_string, 'matches': options}
+ msg = _('ambiguous option: %(option)s could match %(matches)s')
+ self.error(msg % args)
+
+ # if exactly one action matched, this segmentation is good,
+ # so return the parsed action
+ elif len(option_tuples) == 1:
+ option_tuple, = option_tuples
+ return option_tuple
# if it was not found as an option, but it looks like a negative
# number, it was meant to be positional
@@ -2185,16 +2184,17 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
# split at the '='
chars = self.prefix_chars
if option_string[0] in chars and option_string[1] in chars:
- if '=' in option_string:
- option_prefix, explicit_arg = option_string.split('=', 1)
- else:
- option_prefix = option_string
- explicit_arg = None
- for option_string in self._option_string_actions:
- if option_string.startswith(option_prefix):
- action = self._option_string_actions[option_string]
- tup = action, option_string, explicit_arg
- result.append(tup)
+ if self.allow_abbrev:
+ if '=' in option_string:
+ option_prefix, explicit_arg = option_string.split('=', 1)
+ else:
+ option_prefix = option_string
+ explicit_arg = None
+ for option_string in self._option_string_actions:
+ if option_string.startswith(option_prefix):
+ action = self._option_string_actions[option_string]
+ tup = action, option_string, explicit_arg
+ result.append(tup)
# single character options can be concatenated with their arguments
# but multiple character options always have to have their argument
diff --git a/Lib/ast.py b/Lib/ast.py
index b45f1e4..0c88bcf 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -59,11 +59,12 @@ def literal_eval(node_or_string):
node_or_string = parse(node_or_string, mode='eval')
if isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
+ def _raise_malformed_node(node):
+ raise ValueError(f'malformed node or string: {node!r}')
def _convert_num(node):
- if isinstance(node, Constant):
- if type(node.value) in (int, float, complex):
- return node.value
- raise ValueError('malformed node or string: ' + repr(node))
+ if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):
+ _raise_malformed_node(node)
+ return node.value
def _convert_signed_num(node):
if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
operand = _convert_num(node.operand)
@@ -82,6 +83,8 @@ def literal_eval(node_or_string):
elif isinstance(node, Set):
return set(map(_convert, node.elts))
elif isinstance(node, Dict):
+ if len(node.keys) != len(node.values):
+ _raise_malformed_node(node)
return dict(zip(map(_convert, node.keys),
map(_convert, node.values)))
elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):
@@ -408,11 +411,11 @@ class NodeTransformer(NodeVisitor):
class RewriteName(NodeTransformer):
def visit_Name(self, node):
- return copy_location(Subscript(
+ return Subscript(
value=Name(id='data', ctx=Load()),
slice=Index(value=Str(s=node.id)),
ctx=node.ctx
- ), node)
+ )
Keep in mind that if the node you're operating on has child nodes you must
either transform the child nodes yourself or call the :meth:`generic_visit`
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index bfd4011..799013d 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -547,14 +547,17 @@ class BaseEventLoop(events.AbstractEventLoop):
'asyncgen': agen
})
- def run_forever(self):
- """Run until stop() is called."""
- self._check_closed()
+ def _check_running(self):
if self.is_running():
raise RuntimeError('This event loop is already running')
if events._get_running_loop() is not None:
raise RuntimeError(
'Cannot run the event loop while another loop is running')
+
+ def run_forever(self):
+ """Run until stop() is called."""
+ self._check_closed()
+ self._check_running()
self._set_coroutine_origin_tracking(self._debug)
self._thread_id = threading.get_ident()
@@ -586,6 +589,7 @@ class BaseEventLoop(events.AbstractEventLoop):
Return the Future's result, or raise its exception.
"""
self._check_closed()
+ self._check_running()
new_task = not futures.isfuture(future)
future = tasks.ensure_future(future, loop=self)
diff --git a/Lib/asyncio/base_tasks.py b/Lib/asyncio/base_tasks.py
index e2da462..09bb171 100644
--- a/Lib/asyncio/base_tasks.py
+++ b/Lib/asyncio/base_tasks.py
@@ -24,11 +24,18 @@ def _task_repr_info(task):
def _task_get_stack(task, limit):
frames = []
- try:
- # 'async def' coroutines
+ if hasattr(task._coro, 'cr_frame'):
+ # case 1: 'async def' coroutines
f = task._coro.cr_frame
- except AttributeError:
+ elif hasattr(task._coro, 'gi_frame'):
+ # case 2: legacy coroutines
f = task._coro.gi_frame
+ elif hasattr(task._coro, 'ag_frame'):
+ # case 3: async generators
+ f = task._coro.ag_frame
+ else:
+ # case 4: unknown objects
+ f = None
if f is not None:
while f is not None:
if limit is not None:
diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py
index 27c665a..451a53a 100644
--- a/Lib/asyncio/staggered.py
+++ b/Lib/asyncio/staggered.py
@@ -6,7 +6,7 @@ import contextlib
import typing
from . import events
-from . import futures
+from . import exceptions as exceptions_mod
from . import locks
from . import tasks
@@ -83,7 +83,7 @@ async def staggered_race(
previous_failed: typing.Optional[locks.Event]) -> None:
# Wait for the previous task to finish, or for delay seconds
if previous_failed is not None:
- with contextlib.suppress(futures.TimeoutError):
+ with contextlib.suppress(exceptions_mod.TimeoutError):
# Use asyncio.wait_for() instead of asyncio.wait() here, so
# that if we get cancelled at this point, Event.wait() is also
# cancelled, otherwise there will be a "Task destroyed but it is
diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py
index d8f6530..8c0a574 100644
--- a/Lib/asyncio/unix_events.py
+++ b/Lib/asyncio/unix_events.py
@@ -1266,7 +1266,14 @@ class ThreadedChildWatcher(AbstractChildWatcher):
return True
def close(self):
- pass
+ self._join_threads()
+
+ def _join_threads(self):
+ """Internal: Join all non-daemon threads"""
+ threads = [thread for thread in list(self._threads.values())
+ if thread.is_alive() and not thread.daemon]
+ for thread in threads:
+ thread.join()
def __enter__(self):
return self
diff --git a/Lib/base64.py b/Lib/base64.py
index 2be9c39..2e70223 100755
--- a/Lib/base64.py
+++ b/Lib/base64.py
@@ -82,7 +82,7 @@ def b64decode(s, altchars=None, validate=False):
altchars = _bytes_from_decode_data(altchars)
assert len(altchars) == 2, repr(altchars)
s = s.translate(bytes.maketrans(altchars, b'+/'))
- if validate and not re.match(b'^[A-Za-z0-9+/]*={0,2}$', s):
+ if validate and not re.fullmatch(b'[A-Za-z0-9+/]*={0,2}', s):
raise binascii.Error('Non-base64 digit found')
return binascii.a2b_base64(s)
diff --git a/Lib/bdb.py b/Lib/bdb.py
index 50d9eec..18491da 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -548,14 +548,7 @@ class Bdb:
s += frame.f_code.co_name
else:
s += ""
- if '__args__' in frame.f_locals:
- args = frame.f_locals['__args__']
- else:
- args = None
- if args:
- s += reprlib.repr(args)
- else:
- s += '()'
+ s += '()'
if '__return__' in frame.f_locals:
rv = frame.f_locals['__return__']
s += '->'
diff --git a/Lib/code.py b/Lib/code.py
index d8106ae..76000f8 100644
--- a/Lib/code.py
+++ b/Lib/code.py
@@ -40,7 +40,7 @@ class InteractiveInterpreter:
Arguments are as for compile_command().
- One several things can happen:
+ One of several things can happen:
1) The input is incorrect; compile_command() raised an
exception (SyntaxError or OverflowError). A syntax traceback
diff --git a/Lib/codecs.py b/Lib/codecs.py
index 21c45a7..7f23e97 100644
--- a/Lib/codecs.py
+++ b/Lib/codecs.py
@@ -905,11 +905,16 @@ def open(filename, mode='r', encoding=None, errors='strict', buffering=-1):
file = builtins.open(filename, mode, buffering)
if encoding is None:
return file
- info = lookup(encoding)
- srw = StreamReaderWriter(file, info.streamreader, info.streamwriter, errors)
- # Add attributes to simplify introspection
- srw.encoding = encoding
- return srw
+
+ try:
+ info = lookup(encoding)
+ srw = StreamReaderWriter(file, info.streamreader, info.streamwriter, errors)
+ # Add attributes to simplify introspection
+ srw.encoding = encoding
+ return srw
+ except:
+ file.close()
+ raise
def EncodedFile(file, data_encoding, file_encoding=None, errors='strict'):
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index cadf1c7..a78a47c 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -695,6 +695,13 @@ class Counter(dict):
#
# To strip negative and zero counts, add-in an empty counter:
# c += Counter()
+ #
+ # Rich comparison operators for multiset subset and superset tests
+ # are deliberately omitted due to semantic conflicts with the
+ # existing inherited dict equality method. Subset and superset
+ # semantics ignore zero counts and require that pâ¤q ⧠pâ¥q â p=q;
+ # however, that would not be the case for p=Counter(a=1, b=0)
+ # and q=Counter(a=1) where the dictionaries are not equal.
def __add__(self, other):
'''Add counts from two counters.
diff --git a/Lib/compileall.py b/Lib/compileall.py
index 49306d9..bfac8ef 100644
--- a/Lib/compileall.py
+++ b/Lib/compileall.py
@@ -41,7 +41,7 @@ def _walk_dir(dir, ddir=None, maxlevels=10, quiet=0):
else:
dfile = None
if not os.path.isdir(fullname):
- yield fullname
+ yield fullname, ddir
elif (maxlevels > 0 and name != os.curdir and name != os.pardir and
os.path.isdir(fullname) and not os.path.islink(fullname)):
yield from _walk_dir(fullname, ddir=dfile,
@@ -76,28 +76,33 @@ def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
from concurrent.futures import ProcessPoolExecutor
except ImportError:
workers = 1
- files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels,
- ddir=ddir)
+ files_and_ddirs = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels,
+ ddir=ddir)
success = True
if workers != 1 and ProcessPoolExecutor is not None:
# If workers == 0, let ProcessPoolExecutor choose
workers = workers or None
with ProcessPoolExecutor(max_workers=workers) as executor:
- results = executor.map(partial(compile_file,
- ddir=ddir, force=force,
- rx=rx, quiet=quiet,
- legacy=legacy,
- optimize=optimize,
- invalidation_mode=invalidation_mode),
- files)
+ results = executor.map(
+ partial(_compile_file_tuple,
+ force=force, rx=rx, quiet=quiet,
+ legacy=legacy, optimize=optimize,
+ invalidation_mode=invalidation_mode,
+ ),
+ files_and_ddirs)
success = min(results, default=True)
else:
- for file in files:
- if not compile_file(file, ddir, force, rx, quiet,
+ for file, dfile in files_and_ddirs:
+ if not compile_file(file, dfile, force, rx, quiet,
legacy, optimize, invalidation_mode):
success = False
return success
+def _compile_file_tuple(file_and_dfile, **kwargs):
+ """Needs to be toplevel for ProcessPoolExecutor."""
+ file, dfile = file_and_dfile
+ return compile_file(file, dfile, **kwargs)
+
def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
legacy=False, optimize=-1,
invalidation_mode=None):
diff --git a/Lib/copy.py b/Lib/copy.py
index f53cd8c..41873f2 100644
--- a/Lib/copy.py
+++ b/Lib/copy.py
@@ -107,7 +107,7 @@ _copy_dispatch = d = {}
def _copy_immutable(x):
return x
for t in (type(None), int, float, bool, complex, str, tuple,
- bytes, frozenset, type, range, slice,
+ bytes, frozenset, type, range, slice, property,
types.BuiltinFunctionType, type(Ellipsis), type(NotImplemented),
types.FunctionType, weakref.ref):
d[t] = _copy_immutable
@@ -195,6 +195,7 @@ d[type] = _deepcopy_atomic
d[types.BuiltinFunctionType] = _deepcopy_atomic
d[types.FunctionType] = _deepcopy_atomic
d[weakref.ref] = _deepcopy_atomic
+d[property] = _deepcopy_atomic
def _deepcopy_list(x, memo, deepcopy=deepcopy):
y = []
diff --git a/Lib/ctypes/test/test_loading.py b/Lib/ctypes/test/test_loading.py
index 9b97d80..a62044e 100644
--- a/Lib/ctypes/test/test_loading.py
+++ b/Lib/ctypes/test/test_loading.py
@@ -158,8 +158,11 @@ class LoaderTest(unittest.TestCase):
# Relative path (but not just filename) should succeed
should_pass("WinDLL('./_sqlite3.dll')")
- # Insecure load flags should succeed
- should_pass("WinDLL('_sqlite3.dll', winmode=0)")
+ # XXX: This test has started failing on Azure Pipelines CI. See
+ # bpo-40214 for more information.
+ if 0:
+ # Insecure load flags should succeed
+ should_pass("WinDLL('_sqlite3.dll', winmode=0)")
# Full path load without DLL_LOAD_DIR shouldn't find dependency
should_fail("WinDLL(nt._getfullpathname('_sqlite3.dll'), " +
diff --git a/Lib/ctypes/test/test_structures.py b/Lib/ctypes/test/test_structures.py
index 19c4430..cdbaa7f 100644
--- a/Lib/ctypes/test/test_structures.py
+++ b/Lib/ctypes/test/test_structures.py
@@ -571,6 +571,7 @@ class StructureTestCase(unittest.TestCase):
self.assertEqual(f2, [0x4567, 0x0123, 0xcdef, 0x89ab,
0x3210, 0x7654, 0xba98, 0xfedc])
+ @unittest.skipIf(True, 'Test disabled for now - see bpo-16575/bpo-16576')
def test_union_by_value(self):
# See bpo-16575
@@ -651,7 +652,7 @@ class StructureTestCase(unittest.TestCase):
self.assertEqual(test5.nested.an_int, 0)
self.assertEqual(test5.another_int, 0)
- #@unittest.skipIf('s390' in MACHINE, 'Test causes segfault on S390')
+ @unittest.skipIf(True, 'Test disabled for now - see bpo-16575/bpo-16576')
def test_bitfield_by_value(self):
# See bpo-16576
diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py
index e8e4b71..03a5986 100644
--- a/Lib/distutils/_msvccompiler.py
+++ b/Lib/distutils/_msvccompiler.py
@@ -97,28 +97,11 @@ PLAT_SPEC_TO_RUNTIME = {
}
def _find_vcvarsall(plat_spec):
+ # bpo-38597: Removed vcruntime return value
_, best_dir = _find_vc2017()
- vcruntime = None
-
- if plat_spec in PLAT_SPEC_TO_RUNTIME:
- vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec]
- else:
- vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
-
- if best_dir:
- vcredist = os.path.join(best_dir, "..", "..", "redist", "MSVC", "**",
- vcruntime_plat, "Microsoft.VC14*.CRT", "vcruntime140.dll")
- try:
- import glob
- vcruntime = glob.glob(vcredist, recursive=True)[-1]
- except (ImportError, OSError, LookupError):
- vcruntime = None
if not best_dir:
best_version, best_dir = _find_vc2015()
- if best_version:
- vcruntime = os.path.join(best_dir, 'redist', vcruntime_plat,
- "Microsoft.VC140.CRT", "vcruntime140.dll")
if not best_dir:
log.debug("No suitable Visual C++ version found")
@@ -129,11 +112,7 @@ def _find_vcvarsall(plat_spec):
log.debug("%s cannot be found", vcvarsall)
return None, None
- if not vcruntime or not os.path.isfile(vcruntime):
- log.debug("%s cannot be found", vcruntime)
- vcruntime = None
-
- return vcvarsall, vcruntime
+ return vcvarsall, None
def _get_vc_env(plat_spec):
if os.getenv("DISTUTILS_USE_SDK"):
@@ -142,7 +121,7 @@ def _get_vc_env(plat_spec):
for key, value in os.environ.items()
}
- vcvarsall, vcruntime = _find_vcvarsall(plat_spec)
+ vcvarsall, _ = _find_vcvarsall(plat_spec)
if not vcvarsall:
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
@@ -163,8 +142,6 @@ def _get_vc_env(plat_spec):
if key and value
}
- if vcruntime:
- env['py_vcruntime_redist'] = vcruntime
return env
def _find_exe(exe, paths=None):
@@ -194,12 +171,6 @@ PLAT_TO_VCVARS = {
'win-arm64' : 'x86_arm64'
}
-# A set containing the DLLs that are guaranteed to be available for
-# all micro versions of this Python version. Known extension
-# dependencies that are not in this set will be copied to the output
-# path.
-_BUNDLED_DLLS = frozenset(['vcruntime140.dll'])
-
class MSVCCompiler(CCompiler) :
"""Concrete class that implements an interface to Microsoft Visual C++,
as defined by the CCompiler abstract class."""
@@ -263,7 +234,6 @@ class MSVCCompiler(CCompiler) :
self.rc = _find_exe("rc.exe", paths) # resource compiler
self.mc = _find_exe("mc.exe", paths) # message compiler
self.mt = _find_exe("mt.exe", paths) # message compiler
- self._vcruntime_redist = vc_env.get('py_vcruntime_redist', '')
for dir in vc_env.get('include', '').split(os.pathsep):
if dir:
@@ -274,13 +244,12 @@ class MSVCCompiler(CCompiler) :
self.add_library_dir(dir.rstrip(os.sep))
self.preprocess_options = None
- # If vcruntime_redist is available, link against it dynamically. Otherwise,
- # use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib
- # later to dynamically link to ucrtbase but not vcruntime.
+ # bpo-38597: Always compile with dynamic linking
+ # Future releases of Python 3.x will include all past
+ # versions of vcruntime*.dll for compatibility.
self.compile_options = [
- '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG'
+ '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG', '/MD'
]
- self.compile_options.append('/MD' if self._vcruntime_redist else '/MT')
self.compile_options_debug = [
'/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
@@ -289,8 +258,6 @@ class MSVCCompiler(CCompiler) :
ldflags = [
'/nologo', '/INCREMENTAL:NO', '/LTCG'
]
- if not self._vcruntime_redist:
- ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib'))
ldflags_debug = [
'/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
@@ -532,24 +499,11 @@ class MSVCCompiler(CCompiler) :
try:
log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
self.spawn([self.linker] + ld_args)
- self._copy_vcruntime(output_dir)
except DistutilsExecError as msg:
raise LinkError(msg)
else:
log.debug("skipping %s (up-to-date)", output_filename)
- def _copy_vcruntime(self, output_dir):
- vcruntime = self._vcruntime_redist
- if not vcruntime or not os.path.isfile(vcruntime):
- return
-
- if os.path.basename(vcruntime).lower() in _BUNDLED_DLLS:
- return
-
- log.debug('Copying "%s"', vcruntime)
- vcruntime = shutil.copy(vcruntime, output_dir)
- os.chmod(vcruntime, stat.S_IWRITE)
-
def spawn(self, cmd):
old_path = os.getenv('path')
try:
diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py
index 2d7cdf0..dbcd9d1 100644
--- a/Lib/distutils/command/build_ext.py
+++ b/Lib/distutils/command/build_ext.py
@@ -688,7 +688,15 @@ class build_ext(Command):
provided, "PyInit_" + module_name. Only relevant on Windows, where
the .pyd file (DLL) must export the module "PyInit_" function.
"""
- initfunc_name = "PyInit_" + ext.name.split('.')[-1]
+ suffix = '_' + ext.name.split('.')[-1]
+ try:
+ # Unicode module name support as defined in PEP-489
+ # https://www.python.org/dev/peps/pep-0489/#export-hook-name
+ suffix.encode('ascii')
+ except UnicodeEncodeError:
+ suffix = 'U' + suffix.encode('punycode').replace(b'-', b'_').decode('ascii')
+
+ initfunc_name = "PyInit" + suffix
if initfunc_name not in ext.export_symbols:
ext.export_symbols.append(initfunc_name)
return ext.export_symbols
diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py
index 52d36b2..5e47e07 100644
--- a/Lib/distutils/tests/test_build_ext.py
+++ b/Lib/distutils/tests/test_build_ext.py
@@ -304,6 +304,19 @@ class BuildExtTestCase(TempdirManager,
cmd.ensure_finalized()
self.assertEqual(cmd.get_source_files(), ['xxx'])
+ def test_unicode_module_names(self):
+ modules = [
+ Extension('foo', ['aaa'], optional=False),
+ Extension('föö', ['uuu'], optional=False),
+ ]
+ dist = Distribution({'name': 'xx', 'ext_modules': modules})
+ cmd = self.build_ext(dist)
+ cmd.ensure_finalized()
+ self.assertRegex(cmd.get_ext_filename(modules[0].name), r'foo(_d)?\..*')
+ self.assertRegex(cmd.get_ext_filename(modules[1].name), r'föö(_d)?\..*')
+ self.assertEqual(cmd.get_export_symbols(modules[0]), ['PyInit_foo'])
+ self.assertEqual(cmd.get_export_symbols(modules[1]), ['PyInitU_f_gkaa'])
+
def test_compiler_option(self):
# cmd.compiler is an option and
# should not be overridden by a compiler instance
diff --git a/Lib/distutils/tests/test_config_cmd.py b/Lib/distutils/tests/test_config_cmd.py
index b735fd3..8bd2c94 100644
--- a/Lib/distutils/tests/test_config_cmd.py
+++ b/Lib/distutils/tests/test_config_cmd.py
@@ -47,8 +47,7 @@ class ConfigTestCase(support.LoggingSilencer,
cmd = config(dist)
cmd._check_compiler()
compiler = cmd.compiler
- is_xlc = shutil.which(compiler.preprocessor[0]).startswith("/usr/vac")
- if is_xlc:
+ if sys.platform[:3] == "aix" and "xlc" in compiler.preprocessor[0].lower():
self.skipTest('xlc: The -E option overrides the -P, -o, and -qsyntaxonly options')
# simple pattern searches
diff --git a/Lib/distutils/tests/test_msvccompiler.py b/Lib/distutils/tests/test_msvccompiler.py
index 70a9c93..b518d6a 100644
--- a/Lib/distutils/tests/test_msvccompiler.py
+++ b/Lib/distutils/tests/test_msvccompiler.py
@@ -32,57 +32,6 @@ class msvccompilerTestCase(support.TempdirManager,
finally:
_msvccompiler._find_vcvarsall = old_find_vcvarsall
- def test_compiler_options(self):
- import distutils._msvccompiler as _msvccompiler
- # suppress path to vcruntime from _find_vcvarsall to
- # check that /MT is added to compile options
- old_find_vcvarsall = _msvccompiler._find_vcvarsall
- def _find_vcvarsall(plat_spec):
- return old_find_vcvarsall(plat_spec)[0], None
- _msvccompiler._find_vcvarsall = _find_vcvarsall
- try:
- compiler = _msvccompiler.MSVCCompiler()
- compiler.initialize()
-
- self.assertIn('/MT', compiler.compile_options)
- self.assertNotIn('/MD', compiler.compile_options)
- finally:
- _msvccompiler._find_vcvarsall = old_find_vcvarsall
-
- def test_vcruntime_copy(self):
- import distutils._msvccompiler as _msvccompiler
- # force path to a known file - it doesn't matter
- # what we copy as long as its name is not in
- # _msvccompiler._BUNDLED_DLLS
- old_find_vcvarsall = _msvccompiler._find_vcvarsall
- def _find_vcvarsall(plat_spec):
- return old_find_vcvarsall(plat_spec)[0], __file__
- _msvccompiler._find_vcvarsall = _find_vcvarsall
- try:
- tempdir = self.mkdtemp()
- compiler = _msvccompiler.MSVCCompiler()
- compiler.initialize()
- compiler._copy_vcruntime(tempdir)
-
- self.assertTrue(os.path.isfile(os.path.join(
- tempdir, os.path.basename(__file__))))
- finally:
- _msvccompiler._find_vcvarsall = old_find_vcvarsall
-
- def test_vcruntime_skip_copy(self):
- import distutils._msvccompiler as _msvccompiler
-
- tempdir = self.mkdtemp()
- compiler = _msvccompiler.MSVCCompiler()
- compiler.initialize()
- dll = compiler._vcruntime_redist
- self.assertTrue(os.path.isfile(dll), dll or "")
-
- compiler._copy_vcruntime(tempdir)
-
- self.assertFalse(os.path.isfile(os.path.join(
- tempdir, os.path.basename(dll))), dll or "")
-
def test_get_vc_env_unicode(self):
import distutils._msvccompiler as _msvccompiler
diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py
index d10a78d..4d7a6de 100644
--- a/Lib/distutils/unixccompiler.py
+++ b/Lib/distutils/unixccompiler.py
@@ -288,7 +288,7 @@ class UnixCCompiler(CCompiler):
# vs
# /usr/lib/libedit.dylib
cflags = sysconfig.get_config_var('CFLAGS')
- m = re.search(r'-isysroot\s+(\S+)', cflags)
+ m = re.search(r'-isysroot\s*(\S+)', cflags)
if m is None:
sysroot = '/'
else:
diff --git a/Lib/doctest.py b/Lib/doctest.py
index dcbcfe5..ee71984 100644
--- a/Lib/doctest.py
+++ b/Lib/doctest.py
@@ -211,6 +211,13 @@ def _normalize_module(module, depth=2):
else:
raise TypeError("Expected a module, string, or None")
+def _newline_convert(data):
+ # We have two cases to cover and we need to make sure we do
+ # them in the right order
+ for newline in ('\r\n', '\r'):
+ data = data.replace(newline, '\n')
+ return data
+
def _load_testfile(filename, package, module_relative, encoding):
if module_relative:
package = _normalize_module(package, 3)
@@ -221,7 +228,7 @@ def _load_testfile(filename, package, module_relative, encoding):
file_contents = file_contents.decode(encoding)
# get_data() opens files as 'rb', so one must do the equivalent
# conversion as universal newlines would do.
- return file_contents.replace(os.linesep, '\n'), filename
+ return _newline_convert(file_contents), filename
with open(filename, encoding=encoding) as f:
return f.read(), filename
diff --git a/Lib/encodings/punycode.py b/Lib/encodings/punycode.py
index 66c5101..1c57264 100644
--- a/Lib/encodings/punycode.py
+++ b/Lib/encodings/punycode.py
@@ -143,7 +143,7 @@ def decode_generalized_number(extended, extpos, bias, errors):
digit = char - 22 # 0x30-26
elif errors == "strict":
raise UnicodeError("Invalid extended code point '%s'"
- % extended[extpos])
+ % extended[extpos-1])
else:
return extpos, None
t = T(j, bias)
diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py
index fc0edec..566fb2a 100644
--- a/Lib/ensurepip/__init__.py
+++ b/Lib/ensurepip/__init__.py
@@ -2,6 +2,7 @@ import os
import os.path
import pkgutil
import sys
+import runpy
import tempfile
@@ -23,9 +24,18 @@ def _run_pip(args, additional_paths=None):
if additional_paths is not None:
sys.path = additional_paths + sys.path
- # Install the bundled software
- import pip._internal
- return pip._internal.main(args)
+ # Invoke pip as if it's the main module, and catch the exit.
+ backup_argv = sys.argv[:]
+ sys.argv[1:] = args
+ try:
+ # run_module() alters sys.modules and sys.argv, but restores them at exit
+ runpy.run_module("pip", run_name="__main__", alter_sys=True)
+ except SystemExit as exc:
+ return exc.code
+ finally:
+ sys.argv[:] = backup_argv
+
+ raise SystemError("pip did not exit, this should never happen")
def version():
diff --git a/Lib/fractions.py b/Lib/fractions.py
index e774d58..e4fcc89 100644
--- a/Lib/fractions.py
+++ b/Lib/fractions.py
@@ -636,7 +636,9 @@ class Fraction(numbers.Rational):
def __bool__(a):
"""a != 0"""
- return a._numerator != 0
+ # bpo-39274: Use bool() because (a._numerator != 0) can return an
+ # object which is not a bool.
+ return bool(a._numerator)
# support for pickling, copy, and deepcopy
diff --git a/Lib/functools.py b/Lib/functools.py
index b41dea7..4cde5f5 100644
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -11,7 +11,8 @@
__all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES',
'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial',
- 'partialmethod', 'singledispatch', 'singledispatchmethod']
+ 'partialmethod', 'singledispatch', 'singledispatchmethod',
+ "cached_property"]
from abc import get_cache_token
from collections import namedtuple
diff --git a/Lib/glob.py b/Lib/glob.py
index 0b3fcc6..0dd2f8b 100644
--- a/Lib/glob.py
+++ b/Lib/glob.py
@@ -31,6 +31,7 @@ def iglob(pathname, *, recursive=False):
If recursive is true, the pattern '**' will match any files and
zero or more directories and subdirectories.
"""
+ sys.audit("glob.glob", pathname, recursive)
it = _iglob(pathname, recursive, False)
if recursive and _isrecursive(pathname):
s = next(it) # skip empty string
@@ -38,7 +39,6 @@ def iglob(pathname, *, recursive=False):
return it
def _iglob(pathname, recursive, dironly):
- sys.audit("glob.glob", pathname, recursive)
dirname, basename = os.path.split(pathname)
if not has_magic(pathname):
assert not dironly
diff --git a/Lib/gzip.py b/Lib/gzip.py
index 2968f47..87b553d 100644
--- a/Lib/gzip.py
+++ b/Lib/gzip.py
@@ -201,7 +201,7 @@ class GzipFile(_compression.BaseStream):
self.fileobj = fileobj
if self.mode == WRITE:
- self._write_gzip_header()
+ self._write_gzip_header(compresslevel)
@property
def filename(self):
@@ -228,7 +228,7 @@ class GzipFile(_compression.BaseStream):
self.bufsize = 0
self.offset = 0 # Current file offset for seek(), tell(), etc
- def _write_gzip_header(self):
+ def _write_gzip_header(self, compresslevel):
self.fileobj.write(b'\037\213') # magic header
self.fileobj.write(b'\010') # compression method
try:
@@ -249,7 +249,13 @@ class GzipFile(_compression.BaseStream):
if mtime is None:
mtime = time.time()
write32u(self.fileobj, int(mtime))
- self.fileobj.write(b'\002')
+ if compresslevel == _COMPRESS_LEVEL_BEST:
+ xfl = b'\002'
+ elif compresslevel == _COMPRESS_LEVEL_FAST:
+ xfl = b'\004'
+ else:
+ xfl = b'\000'
+ self.fileobj.write(xfl)
self.fileobj.write(b'\377')
if fname:
self.fileobj.write(fname + b'\000')
diff --git a/Lib/http/client.py b/Lib/http/client.py
index 33a4347..019380a 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -828,6 +828,8 @@ class HTTPConnection:
(self.host, self.port) = self._get_hostport(host, port)
+ self._validate_host(self.host)
+
# This is stored as an instance variable to allow unit
# tests to replace it with a suitable mockup
self._create_connection = socket.create_connection
@@ -1183,6 +1185,14 @@ class HTTPConnection:
raise InvalidURL(f"URL can't contain control characters. {url!r} "
f"(found at least {match.group()!r})")
+ def _validate_host(self, host):
+ """Validate a host so it doesn't contain control characters."""
+ # Prevent CVE-2019-18348.
+ match = _contains_disallowed_url_pchar_re.search(host)
+ if match:
+ raise InvalidURL(f"URL can't contain control characters. {host!r} "
+ f"(found at least {match.group()!r})")
+
def putheader(self, header, *values):
"""Send a request header line to the server.
diff --git a/Lib/http/server.py b/Lib/http/server.py
index b247675..38f7acc 100644
--- a/Lib/http/server.py
+++ b/Lib/http/server.py
@@ -103,6 +103,7 @@ import socketserver
import sys
import time
import urllib.parse
+import contextlib
from functools import partial
from http import HTTPStatus
@@ -1280,4 +1281,19 @@ if __name__ == '__main__':
else:
handler_class = partial(SimpleHTTPRequestHandler,
directory=args.directory)
- test(HandlerClass=handler_class, port=args.port, bind=args.bind)
+
+ # ensure dual-stack is not disabled; ref #38907
+ class DualStackServer(ThreadingHTTPServer):
+ def server_bind(self):
+ # suppress exception when protocol is IPv4
+ with contextlib.suppress(Exception):
+ self.socket.setsockopt(
+ socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
+ return super().server_bind()
+
+ test(
+ HandlerClass=handler_class,
+ ServerClass=DualStackServer,
+ port=args.port,
+ bind=args.bind,
+ )
diff --git a/Lib/idlelib/Icons/README.txt b/Lib/idlelib/Icons/README.txt
new file mode 100644
index 0000000..8b47162
--- /dev/null
+++ b/Lib/idlelib/Icons/README.txt
@@ -0,0 +1,9 @@
+The IDLE icons are from https://bugs.python.org/issue1490384
+
+Created by Andrew Clover.
+
+The original sources are available from Andrew's website:
+https://www.doxdesk.com/software/py/pyicons.html
+
+Various different formats and sizes are available at this GitHub Pull Request:
+https://github.com/python/cpython/pull/17473
diff --git a/Lib/idlelib/Icons/idle.icns b/Lib/idlelib/Icons/idle.icns
deleted file mode 100644
index f65e3130f0afff1aa1bb13599f7a7d67968c9c42..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 57435
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