From 351c67416ba4451eb3928fa0b2e933c2f25df1a3 Mon Sep 17 00:00:00 2001
From: Jeroen Demeyer
Date: Fri, 10 May 2019 19:21:11 +0200
Subject: [PATCH 001/199] bpo-35983: skip trashcan for subclasses (GH-11841)
Add new trashcan macros to deal with a double deallocation that could occur when the `tp_dealloc` of a subclass calls the `tp_dealloc` of a base class and that base class uses the trashcan mechanism.
Patch by Jeroen Demeyer.
---
Include/object.h | 51 +++++++++----
Lib/test/test_capi.py | 43 +++++++++++
Lib/test/test_ordered_dict.py | 8 +-
.../2019-02-13-16-47-19.bpo-35983.bNxsXv.rst | 3 +
Modules/_elementtree.c | 4 +-
Modules/_testcapimodule.c | 76 +++++++++++++++++++
Objects/descrobject.c | 4 +-
Objects/dictobject.c | 4 +-
Objects/listobject.c | 4 +-
Objects/odictobject.c | 15 +---
Objects/setobject.c | 4 +-
Objects/tupleobject.c | 4 +-
Objects/typeobject.c | 74 +-----------------
Python/hamt.c | 12 +--
Python/traceback.c | 4 +-
15 files changed, 189 insertions(+), 121 deletions(-)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-02-13-16-47-19.bpo-35983.bNxsXv.rst
diff --git a/Include/object.h b/Include/object.h
index 13e88a6dc6f..6464f33be49 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -649,11 +649,11 @@ times.
When deallocating a container object, it's possible to trigger an unbounded
chain of deallocations, as each Py_DECREF in turn drops the refcount on "the
-next" object in the chain to 0. This can easily lead to stack faults, and
+next" object in the chain to 0. This can easily lead to stack overflows,
especially in threads (which typically have less stack space to work with).
-A container object that participates in cyclic gc can avoid this by
-bracketing the body of its tp_dealloc function with a pair of macros:
+A container object can avoid this by bracketing the body of its tp_dealloc
+function with a pair of macros:
static void
mytype_dealloc(mytype *p)
@@ -661,14 +661,14 @@ mytype_dealloc(mytype *p)
... declarations go here ...
PyObject_GC_UnTrack(p); // must untrack first
- Py_TRASHCAN_SAFE_BEGIN(p)
+ Py_TRASHCAN_BEGIN(p, mytype_dealloc)
... The body of the deallocator goes here, including all calls ...
... to Py_DECREF on contained objects. ...
- Py_TRASHCAN_SAFE_END(p)
+ Py_TRASHCAN_END // there should be no code after this
}
CAUTION: Never return from the middle of the body! If the body needs to
-"get out early", put a label immediately before the Py_TRASHCAN_SAFE_END
+"get out early", put a label immediately before the Py_TRASHCAN_END
call, and goto it. Else the call-depth counter (see below) will stay
above 0 forever, and the trashcan will never get emptied.
@@ -684,6 +684,12 @@ notices this, and calls another routine to deallocate all the objects that
may have been added to the list of deferred deallocations. In effect, a
chain of N deallocations is broken into (N-1)/(PyTrash_UNWIND_LEVEL-1) pieces,
with the call stack never exceeding a depth of PyTrash_UNWIND_LEVEL.
+
+Since the tp_dealloc of a subclass typically calls the tp_dealloc of the base
+class, we need to ensure that the trashcan is only triggered on the tp_dealloc
+of the actual class being deallocated. Otherwise we might end up with a
+partially-deallocated object. To check this, the tp_dealloc function must be
+passed as second argument to Py_TRASHCAN_BEGIN().
*/
/* The new thread-safe private API, invoked by the macros below. */
@@ -692,21 +698,38 @@ PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void);
#define PyTrash_UNWIND_LEVEL 50
-#define Py_TRASHCAN_SAFE_BEGIN(op) \
+#define Py_TRASHCAN_BEGIN_CONDITION(op, cond) \
do { \
- PyThreadState *_tstate = PyThreadState_GET(); \
- if (_tstate->trash_delete_nesting < PyTrash_UNWIND_LEVEL) { \
- ++_tstate->trash_delete_nesting;
- /* The body of the deallocator is here. */
-#define Py_TRASHCAN_SAFE_END(op) \
+ PyThreadState *_tstate = NULL; \
+ /* If "cond" is false, then _tstate remains NULL and the deallocator \
+ * is run normally without involving the trashcan */ \
+ if (cond) { \
+ _tstate = PyThreadState_GET(); \
+ if (_tstate->trash_delete_nesting >= PyTrash_UNWIND_LEVEL) { \
+ /* Store the object (to be deallocated later) and jump past \
+ * Py_TRASHCAN_END, skipping the body of the deallocator */ \
+ _PyTrash_thread_deposit_object(_PyObject_CAST(op)); \
+ break; \
+ } \
+ ++_tstate->trash_delete_nesting; \
+ }
+ /* The body of the deallocator is here. */
+#define Py_TRASHCAN_END \
+ if (_tstate) { \
--_tstate->trash_delete_nesting; \
if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \
_PyTrash_thread_destroy_chain(); \
} \
- else \
- _PyTrash_thread_deposit_object(_PyObject_CAST(op)); \
} while (0);
+#define Py_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_BEGIN_CONDITION(op, \
+ Py_TYPE(op)->tp_dealloc == (destructor)(dealloc))
+
+/* For backwards compatibility, these macros enable the trashcan
+ * unconditionally */
+#define Py_TRASHCAN_SAFE_BEGIN(op) Py_TRASHCAN_BEGIN_CONDITION(op, 1)
+#define Py_TRASHCAN_SAFE_END(op) Py_TRASHCAN_END
+
#ifndef Py_LIMITED_API
# define Py_CPYTHON_OBJECT_H
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 31dab6a423e..8bcbd82b2d9 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -333,6 +333,49 @@ def test_negative_refcount(self):
br'_Py_NegativeRefcount: Assertion failed: '
br'object has negative ref count')
+ def test_trashcan_subclass(self):
+ # bpo-35983: Check that the trashcan mechanism for "list" is NOT
+ # activated when its tp_dealloc is being called by a subclass
+ from _testcapi import MyList
+ L = None
+ for i in range(1000):
+ L = MyList((L,))
+
+ def test_trashcan_python_class1(self):
+ self.do_test_trashcan_python_class(list)
+
+ def test_trashcan_python_class2(self):
+ from _testcapi import MyList
+ self.do_test_trashcan_python_class(MyList)
+
+ def do_test_trashcan_python_class(self, base):
+ # Check that the trashcan mechanism works properly for a Python
+ # subclass of a class using the trashcan (this specific test assumes
+ # that the base class "base" behaves like list)
+ class PyList(base):
+ # Count the number of PyList instances to verify that there is
+ # no memory leak
+ num = 0
+ def __init__(self, *args):
+ __class__.num += 1
+ super().__init__(*args)
+ def __del__(self):
+ __class__.num -= 1
+
+ for parity in (0, 1):
+ L = None
+ # We need in the order of 2**20 iterations here such that a
+ # typical 8MB stack would overflow without the trashcan.
+ for i in range(2**20):
+ L = PyList((L,))
+ L.attr = i
+ if parity:
+ # Add one additional nesting layer
+ L = (L,)
+ self.assertGreater(PyList.num, 0)
+ del L
+ self.assertEqual(PyList.num, 0)
+
class TestPendingCalls(unittest.TestCase):
diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py
index b1d7f86a676..148a9bdc35e 100644
--- a/Lib/test/test_ordered_dict.py
+++ b/Lib/test/test_ordered_dict.py
@@ -459,7 +459,9 @@ def update(self, *args, **kwds):
self.assertEqual(list(MyOD(items).items()), items)
def test_highly_nested(self):
- # Issue 25395: crashes during garbage collection
+ # Issues 25395 and 35983: test that the trashcan mechanism works
+ # correctly for OrderedDict: deleting a highly nested OrderDict
+ # should not crash Python.
OrderedDict = self.OrderedDict
obj = None
for _ in range(1000):
@@ -468,7 +470,9 @@ def test_highly_nested(self):
support.gc_collect()
def test_highly_nested_subclass(self):
- # Issue 25395: crashes during garbage collection
+ # Issues 25395 and 35983: test that the trashcan mechanism works
+ # correctly for OrderedDict: deleting a highly nested OrderDict
+ # should not crash Python.
OrderedDict = self.OrderedDict
deleted = []
class MyOD(OrderedDict):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-02-13-16-47-19.bpo-35983.bNxsXv.rst b/Misc/NEWS.d/next/Core and Builtins/2019-02-13-16-47-19.bpo-35983.bNxsXv.rst
new file mode 100644
index 00000000000..1138df635db
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-02-13-16-47-19.bpo-35983.bNxsXv.rst
@@ -0,0 +1,3 @@
+Added new trashcan macros to deal with a double deallocation that could occur
+when the `tp_dealloc` of a subclass calls the `tp_dealloc` of a base class
+and that base class uses the trashcan mechanism. Patch by Jeroen Demeyer.
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index e9a0ea21b29..f5fc4437deb 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -669,7 +669,7 @@ element_dealloc(ElementObject* self)
{
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(self);
- Py_TRASHCAN_SAFE_BEGIN(self)
+ Py_TRASHCAN_BEGIN(self, element_dealloc)
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
@@ -680,7 +680,7 @@ element_dealloc(ElementObject* self)
RELEASE(sizeof(ElementObject), "destroy element");
Py_TYPE(self)->tp_free((PyObject *)self);
- Py_TRASHCAN_SAFE_END(self)
+ Py_TRASHCAN_END
}
/* -------------------------------------------------------------------- */
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index c52e3499638..04d75ace6ec 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -5451,6 +5451,76 @@ recurse_infinitely_error_init(PyObject *self, PyObject *args, PyObject *kwds)
}
+/* Test bpo-35983: create a subclass of "list" which checks that instances
+ * are not deallocated twice */
+
+typedef struct {
+ PyListObject list;
+ int deallocated;
+} MyListObject;
+
+static PyObject *
+MyList_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject* op = PyList_Type.tp_new(type, args, kwds);
+ ((MyListObject*)op)->deallocated = 0;
+ return op;
+}
+
+void
+MyList_dealloc(MyListObject* op)
+{
+ if (op->deallocated) {
+ /* We cannot raise exceptions here but we still want the testsuite
+ * to fail when we hit this */
+ Py_FatalError("MyList instance deallocated twice");
+ }
+ op->deallocated = 1;
+ PyList_Type.tp_dealloc((PyObject *)op);
+}
+
+static PyTypeObject MyList_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "MyList",
+ sizeof(MyListObject),
+ 0,
+ (destructor)MyList_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* &PyList_Type */ /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ MyList_new, /* tp_new */
+};
+
+
/* Test PEP 560 */
typedef struct {
@@ -5564,6 +5634,12 @@ PyInit__testcapi(void)
Py_INCREF(&awaitType);
PyModule_AddObject(m, "awaitType", (PyObject *)&awaitType);
+ MyList_Type.tp_base = &PyList_Type;
+ if (PyType_Ready(&MyList_Type) < 0)
+ return NULL;
+ Py_INCREF(&MyList_Type);
+ PyModule_AddObject(m, "MyList", (PyObject *)&MyList_Type);
+
if (PyType_Ready(&GenericAlias_Type) < 0)
return NULL;
Py_INCREF(&GenericAlias_Type);
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 0fe9a441b82..8f1a823768f 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -1021,11 +1021,11 @@ static void
wrapper_dealloc(wrapperobject *wp)
{
PyObject_GC_UnTrack(wp);
- Py_TRASHCAN_SAFE_BEGIN(wp)
+ Py_TRASHCAN_BEGIN(wp, wrapper_dealloc)
Py_XDECREF(wp->descr);
Py_XDECREF(wp->self);
PyObject_GC_Del(wp);
- Py_TRASHCAN_SAFE_END(wp)
+ Py_TRASHCAN_END
}
static PyObject *
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index c8c88d2c0fc..88ac1a9dcd0 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1978,7 +1978,7 @@ dict_dealloc(PyDictObject *mp)
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(mp);
- Py_TRASHCAN_SAFE_BEGIN(mp)
+ Py_TRASHCAN_BEGIN(mp, dict_dealloc)
if (values != NULL) {
if (values != empty_values) {
for (i = 0, n = mp->ma_keys->dk_nentries; i < n; i++) {
@@ -1996,7 +1996,7 @@ dict_dealloc(PyDictObject *mp)
free_list[numfree++] = mp;
else
Py_TYPE(mp)->tp_free((PyObject *)mp);
- Py_TRASHCAN_SAFE_END(mp)
+ Py_TRASHCAN_END
}
diff --git a/Objects/listobject.c b/Objects/listobject.c
index c29954283c4..08b3e89a957 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -361,7 +361,7 @@ list_dealloc(PyListObject *op)
{
Py_ssize_t i;
PyObject_GC_UnTrack(op);
- Py_TRASHCAN_SAFE_BEGIN(op)
+ Py_TRASHCAN_BEGIN(op, list_dealloc)
if (op->ob_item != NULL) {
/* Do it backwards, for Christian Tismer.
There's a simple test case where somehow this reduces
@@ -377,7 +377,7 @@ list_dealloc(PyListObject *op)
free_list[numfree++] = op;
else
Py_TYPE(op)->tp_free((PyObject *)op);
- Py_TRASHCAN_SAFE_END(op)
+ Py_TRASHCAN_END
}
static PyObject *
diff --git a/Objects/odictobject.c b/Objects/odictobject.c
index 6c75a42f4ee..773827d85b3 100644
--- a/Objects/odictobject.c
+++ b/Objects/odictobject.c
@@ -1356,28 +1356,17 @@ static PyGetSetDef odict_getset[] = {
static void
odict_dealloc(PyODictObject *self)
{
- PyThreadState *tstate = _PyThreadState_GET();
-
PyObject_GC_UnTrack(self);
- Py_TRASHCAN_SAFE_BEGIN(self)
+ Py_TRASHCAN_BEGIN(self, odict_dealloc)
Py_XDECREF(self->od_inst_dict);
if (self->od_weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)self);
_odict_clear_nodes(self);
-
- /* Call the base tp_dealloc(). Since it too uses the trashcan mechanism,
- * temporarily decrement trash_delete_nesting to prevent triggering it
- * and putting the partially deallocated object on the trashcan's
- * to-be-deleted-later list.
- */
- --tstate->trash_delete_nesting;
- assert(_tstate->trash_delete_nesting < PyTrash_UNWIND_LEVEL);
PyDict_Type.tp_dealloc((PyObject *)self);
- ++tstate->trash_delete_nesting;
- Py_TRASHCAN_SAFE_END(self)
+ Py_TRASHCAN_END
}
/* tp_repr */
diff --git a/Objects/setobject.c b/Objects/setobject.c
index a43ecd52853..82e9639d288 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -559,7 +559,7 @@ set_dealloc(PySetObject *so)
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(so);
- Py_TRASHCAN_SAFE_BEGIN(so)
+ Py_TRASHCAN_BEGIN(so, set_dealloc)
if (so->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) so);
@@ -572,7 +572,7 @@ set_dealloc(PySetObject *so)
if (so->table != so->smalltable)
PyMem_DEL(so->table);
Py_TYPE(so)->tp_free(so);
- Py_TRASHCAN_SAFE_END(so)
+ Py_TRASHCAN_END
}
static PyObject *
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 75d2bf95e66..9f0fc1cc2c3 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -240,7 +240,7 @@ tupledealloc(PyTupleObject *op)
Py_ssize_t i;
Py_ssize_t len = Py_SIZE(op);
PyObject_GC_UnTrack(op);
- Py_TRASHCAN_SAFE_BEGIN(op)
+ Py_TRASHCAN_BEGIN(op, tupledealloc)
if (len > 0) {
i = len;
while (--i >= 0)
@@ -259,7 +259,7 @@ tupledealloc(PyTupleObject *op)
}
Py_TYPE(op)->tp_free((PyObject *)op);
done:
- Py_TRASHCAN_SAFE_END(op)
+ Py_TRASHCAN_END
}
static PyObject *
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index b28f494962e..bfbd320b1f5 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1120,7 +1120,6 @@ subtype_dealloc(PyObject *self)
{
PyTypeObject *type, *base;
destructor basedealloc;
- PyThreadState *tstate = _PyThreadState_GET();
int has_finalizer;
/* Extract the type; we expect it to be a heap type */
@@ -1174,11 +1173,7 @@ subtype_dealloc(PyObject *self)
/* UnTrack and re-Track around the trashcan macro, alas */
/* See explanation at end of function for full disclosure */
PyObject_GC_UnTrack(self);
- ++_PyRuntime.gc.trash_delete_nesting;
- ++ tstate->trash_delete_nesting;
- Py_TRASHCAN_SAFE_BEGIN(self);
- --_PyRuntime.gc.trash_delete_nesting;
- -- tstate->trash_delete_nesting;
+ Py_TRASHCAN_BEGIN(self, subtype_dealloc);
/* Find the nearest base with a different tp_dealloc */
base = type;
@@ -1271,11 +1266,7 @@ subtype_dealloc(PyObject *self)
Py_DECREF(type);
endlabel:
- ++_PyRuntime.gc.trash_delete_nesting;
- ++ tstate->trash_delete_nesting;
- Py_TRASHCAN_SAFE_END(self);
- --_PyRuntime.gc.trash_delete_nesting;
- -- tstate->trash_delete_nesting;
+ Py_TRASHCAN_END
/* Explanation of the weirdness around the trashcan macros:
@@ -1312,67 +1303,6 @@ subtype_dealloc(PyObject *self)
looks like trash to gc too, and gc also tries to delete self
then. But we're already deleting self. Double deallocation is
a subtle disaster.
-
- Q. Why the bizarre (net-zero) manipulation of
- _PyRuntime.trash_delete_nesting around the trashcan macros?
-
- A. Some base classes (e.g. list) also use the trashcan mechanism.
- The following scenario used to be possible:
-
- - suppose the trashcan level is one below the trashcan limit
-
- - subtype_dealloc() is called
-
- - the trashcan limit is not yet reached, so the trashcan level
- is incremented and the code between trashcan begin and end is
- executed
-
- - this destroys much of the object's contents, including its
- slots and __dict__
-
- - basedealloc() is called; this is really list_dealloc(), or
- some other type which also uses the trashcan macros
-
- - the trashcan limit is now reached, so the object is put on the
- trashcan's to-be-deleted-later list
-
- - basedealloc() returns
-
- - subtype_dealloc() decrefs the object's type
-
- - subtype_dealloc() returns
-
- - later, the trashcan code starts deleting the objects from its
- to-be-deleted-later list
-
- - subtype_dealloc() is called *AGAIN* for the same object
-
- - at the very least (if the destroyed slots and __dict__ don't
- cause problems) the object's type gets decref'ed a second
- time, which is *BAD*!!!
-
- The remedy is to make sure that if the code between trashcan
- begin and end in subtype_dealloc() is called, the code between
- trashcan begin and end in basedealloc() will also be called.
- This is done by decrementing the level after passing into the
- trashcan block, and incrementing it just before leaving the
- block.
-
- But now it's possible that a chain of objects consisting solely
- of objects whose deallocator is subtype_dealloc() will defeat
- the trashcan mechanism completely: the decremented level means
- that the effective level never reaches the limit. Therefore, we
- *increment* the level *before* entering the trashcan block, and
- matchingly decrement it after leaving. This means the trashcan
- code will trigger a little early, but that's no big deal.
-
- Q. Are there any live examples of code in need of all this
- complexity?
-
- A. Yes. See SF bug 668433 for code that crashed (when Python was
- compiled in debug mode) before the trashcan level manipulations
- were added. For more discussion, see SF patches 581742, 575073
- and bug 574207.
*/
}
diff --git a/Python/hamt.c b/Python/hamt.c
index 67af04c4377..b3cbf9ac820 100644
--- a/Python/hamt.c
+++ b/Python/hamt.c
@@ -1176,7 +1176,7 @@ hamt_node_bitmap_dealloc(PyHamtNode_Bitmap *self)
Py_ssize_t i;
PyObject_GC_UnTrack(self);
- Py_TRASHCAN_SAFE_BEGIN(self)
+ Py_TRASHCAN_BEGIN(self, hamt_node_bitmap_dealloc)
if (len > 0) {
i = len;
@@ -1186,7 +1186,7 @@ hamt_node_bitmap_dealloc(PyHamtNode_Bitmap *self)
}
Py_TYPE(self)->tp_free((PyObject *)self);
- Py_TRASHCAN_SAFE_END(self)
+ Py_TRASHCAN_END
}
#ifdef Py_DEBUG
@@ -1584,7 +1584,7 @@ hamt_node_collision_dealloc(PyHamtNode_Collision *self)
Py_ssize_t len = Py_SIZE(self);
PyObject_GC_UnTrack(self);
- Py_TRASHCAN_SAFE_BEGIN(self)
+ Py_TRASHCAN_BEGIN(self, hamt_node_collision_dealloc)
if (len > 0) {
@@ -1594,7 +1594,7 @@ hamt_node_collision_dealloc(PyHamtNode_Collision *self)
}
Py_TYPE(self)->tp_free((PyObject *)self);
- Py_TRASHCAN_SAFE_END(self)
+ Py_TRASHCAN_END
}
#ifdef Py_DEBUG
@@ -1969,14 +1969,14 @@ hamt_node_array_dealloc(PyHamtNode_Array *self)
Py_ssize_t i;
PyObject_GC_UnTrack(self);
- Py_TRASHCAN_SAFE_BEGIN(self)
+ Py_TRASHCAN_BEGIN(self, hamt_node_array_dealloc)
for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) {
Py_XDECREF(self->a_array[i]);
}
Py_TYPE(self)->tp_free((PyObject *)self);
- Py_TRASHCAN_SAFE_END(self)
+ Py_TRASHCAN_END
}
#ifdef Py_DEBUG
diff --git a/Python/traceback.c b/Python/traceback.c
index bd1061ed43b..18bd0bf7341 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -163,11 +163,11 @@ static void
tb_dealloc(PyTracebackObject *tb)
{
PyObject_GC_UnTrack(tb);
- Py_TRASHCAN_SAFE_BEGIN(tb)
+ Py_TRASHCAN_BEGIN(tb, tb_dealloc)
Py_XDECREF(tb->tb_next);
Py_XDECREF(tb->tb_frame);
PyObject_GC_Del(tb);
- Py_TRASHCAN_SAFE_END(tb)
+ Py_TRASHCAN_END
}
static int
From 86ea58149c3e83f402cecd17e6a536865fb06ce1 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Fri, 10 May 2019 13:29:55 -0400
Subject: [PATCH 002/199] bpo-36737: Use the module state C-API for warnings.
(gh-13159)
---
Include/internal/pycore_pylifecycle.h | 2 +-
Include/internal/pycore_pystate.h | 3 +-
.../2019-05-07-12-18-11.bpo-36737.XAo6LY.rst | 2 +
Python/_warnings.c | 321 +++++++++++-------
Python/pylifecycle.c | 2 +-
Python/pystate.c | 4 +
6 files changed, 210 insertions(+), 124 deletions(-)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-05-07-12-18-11.bpo-36737.XAo6LY.rst
diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h
index adb1f5d90a5..7144bbcda7c 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -81,7 +81,7 @@ extern void PyLong_Fini(void);
extern void _PyFaulthandler_Fini(void);
extern void _PyHash_Fini(void);
extern int _PyTraceMalloc_Fini(void);
-extern void _PyWarnings_Fini(_PyRuntimeState *runtime);
+extern void _PyWarnings_Fini(PyInterpreterState *interp);
extern void _PyGILState_Init(
_PyRuntimeState *runtime,
diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h
index 67bcd147e28..69ceecba40d 100644
--- a/Include/internal/pycore_pystate.h
+++ b/Include/internal/pycore_pystate.h
@@ -90,6 +90,8 @@ struct _is {
PyObject *pyexitmodule;
uint64_t tstate_next_unique_id;
+
+ struct _warnings_runtime_state warnings;
};
PyAPI_FUNC(struct _is*) _PyInterpreterState_LookUpID(PY_INT64_T);
@@ -179,7 +181,6 @@ typedef struct pyruntimestate {
int nexitfuncs;
struct _gc_runtime_state gc;
- struct _warnings_runtime_state warnings;
struct _ceval_runtime_state ceval;
struct _gilstate_runtime_state gilstate;
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-07-12-18-11.bpo-36737.XAo6LY.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-07-12-18-11.bpo-36737.XAo6LY.rst
new file mode 100644
index 00000000000..7a2c647dbff
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-07-12-18-11.bpo-36737.XAo6LY.rst
@@ -0,0 +1,2 @@
+Move PyRuntimeState.warnings into per-interpreter state (via "module
+state").
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 388b2995408..0b192580e10 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -15,6 +15,134 @@ _Py_IDENTIFIER(default);
_Py_IDENTIFIER(ignore);
#endif
+
+/*************************************************************************/
+
+typedef struct _warnings_runtime_state WarningsState;
+
+/* Forward declaration of the _warnings module definition. */
+static struct PyModuleDef warningsmodule;
+
+/* Given a module object, get its per-module state. */
+static WarningsState *
+_Warnings_GetState()
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ if (tstate == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "_Warnings_GetState: could not identify current interpreter");
+ return NULL;
+ }
+ return &tstate->interp->warnings;
+}
+
+/* Clear the given warnings module state. */
+static void
+_Warnings_ClearState(WarningsState *st)
+{
+ Py_CLEAR(st->filters);
+ Py_CLEAR(st->once_registry);
+ Py_CLEAR(st->default_action);
+}
+
+#ifndef Py_DEBUG
+static PyObject *
+create_filter(PyObject *category, _Py_Identifier *id, const char *modname)
+{
+ PyObject *modname_obj = NULL;
+ PyObject *action_str = _PyUnicode_FromId(id);
+ if (action_str == NULL) {
+ return NULL;
+ }
+
+ /* Default to "no module name" for initial filter set */
+ if (modname != NULL) {
+ modname_obj = PyUnicode_InternFromString(modname);
+ if (modname_obj == NULL) {
+ return NULL;
+ }
+ } else {
+ modname_obj = Py_None;
+ }
+
+ /* This assumes the line number is zero for now. */
+ return PyTuple_Pack(5, action_str, Py_None,
+ category, modname_obj, _PyLong_Zero);
+}
+#endif
+
+static PyObject *
+init_filters(void)
+{
+#ifdef Py_DEBUG
+ /* Py_DEBUG builds show all warnings by default */
+ return PyList_New(0);
+#else
+ /* Other builds ignore a number of warning categories by default */
+ PyObject *filters = PyList_New(5);
+ if (filters == NULL) {
+ return NULL;
+ }
+
+ size_t pos = 0; /* Post-incremented in each use. */
+ PyList_SET_ITEM(filters, pos++,
+ create_filter(PyExc_DeprecationWarning, &PyId_default, "__main__"));
+ PyList_SET_ITEM(filters, pos++,
+ create_filter(PyExc_DeprecationWarning, &PyId_ignore, NULL));
+ PyList_SET_ITEM(filters, pos++,
+ create_filter(PyExc_PendingDeprecationWarning, &PyId_ignore, NULL));
+ PyList_SET_ITEM(filters, pos++,
+ create_filter(PyExc_ImportWarning, &PyId_ignore, NULL));
+ PyList_SET_ITEM(filters, pos++,
+ create_filter(PyExc_ResourceWarning, &PyId_ignore, NULL));
+
+ for (size_t x = 0; x < pos; x++) {
+ if (PyList_GET_ITEM(filters, x) == NULL) {
+ Py_DECREF(filters);
+ return NULL;
+ }
+ }
+ return filters;
+#endif
+}
+
+/* Initialize the given warnings module state. */
+static int
+_Warnings_InitState(WarningsState *st)
+{
+ if (st->filters == NULL) {
+ st->filters = init_filters();
+ if (st->filters == NULL) {
+ goto error;
+ }
+ }
+
+ if (st->once_registry == NULL) {
+ st->once_registry = PyDict_New();
+ if (st->once_registry == NULL) {
+ goto error;
+ }
+ }
+
+ if (st->default_action == NULL) {
+ st->default_action = PyUnicode_FromString("default");
+ if (st->default_action == NULL) {
+ goto error;
+ }
+ }
+
+ st->filters_version = 0;
+
+ return 0;
+
+error:
+ _Warnings_ClearState(st);
+ return -1;
+}
+
+
+/*************************************************************************/
+
static int
check_matched(PyObject *obj, PyObject *arg)
{
@@ -93,7 +221,7 @@ get_warnings_attr(_Py_Identifier *attr_id, int try_import)
static PyObject *
-get_once_registry(void)
+get_once_registry(WarningsState *st)
{
PyObject *registry;
_Py_IDENTIFIER(onceregistry);
@@ -102,8 +230,8 @@ get_once_registry(void)
if (registry == NULL) {
if (PyErr_Occurred())
return NULL;
- assert(_PyRuntime.warnings.once_registry);
- return _PyRuntime.warnings.once_registry;
+ assert(st->once_registry);
+ return st->once_registry;
}
if (!PyDict_Check(registry)) {
PyErr_Format(PyExc_TypeError,
@@ -113,13 +241,13 @@ get_once_registry(void)
Py_DECREF(registry);
return NULL;
}
- Py_SETREF(_PyRuntime.warnings.once_registry, registry);
+ Py_SETREF(st->once_registry, registry);
return registry;
}
static PyObject *
-get_default_action(void)
+get_default_action(WarningsState *st)
{
PyObject *default_action;
_Py_IDENTIFIER(defaultaction);
@@ -129,8 +257,8 @@ get_default_action(void)
if (PyErr_Occurred()) {
return NULL;
}
- assert(_PyRuntime.warnings.default_action);
- return _PyRuntime.warnings.default_action;
+ assert(st->default_action);
+ return st->default_action;
}
if (!PyUnicode_Check(default_action)) {
PyErr_Format(PyExc_TypeError,
@@ -140,7 +268,7 @@ get_default_action(void)
Py_DECREF(default_action);
return NULL;
}
- Py_SETREF(_PyRuntime.warnings.default_action, default_action);
+ Py_SETREF(st->default_action, default_action);
return default_action;
}
@@ -154,6 +282,10 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
Py_ssize_t i;
PyObject *warnings_filters;
_Py_IDENTIFIER(filters);
+ WarningsState *st = _Warnings_GetState();
+ if (st == NULL) {
+ return NULL;
+ }
warnings_filters = get_warnings_attr(&PyId_filters, 0);
if (warnings_filters == NULL) {
@@ -161,17 +293,17 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
return NULL;
}
else {
- Py_SETREF(_PyRuntime.warnings.filters, warnings_filters);
+ Py_SETREF(st->filters, warnings_filters);
}
- PyObject *filters = _PyRuntime.warnings.filters;
+ PyObject *filters = st->filters;
if (filters == NULL || !PyList_Check(filters)) {
PyErr_SetString(PyExc_ValueError,
MODULE_NAME ".filters must be a list");
return NULL;
}
- /* _PyRuntime.warnings.filters could change while we are iterating over it. */
+ /* WarningsState.filters could change while we are iterating over it. */
for (i = 0; i < PyList_GET_SIZE(filters); i++) {
PyObject *tmp_item, *action, *msg, *cat, *mod, *ln_obj;
Py_ssize_t ln;
@@ -232,7 +364,7 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
Py_DECREF(tmp_item);
}
- action = get_default_action();
+ action = get_default_action(st);
if (action != NULL) {
Py_INCREF(Py_None);
*item = Py_None;
@@ -252,16 +384,20 @@ already_warned(PyObject *registry, PyObject *key, int should_set)
if (key == NULL)
return -1;
+ WarningsState *st = _Warnings_GetState();
+ if (st == NULL) {
+ return -1;
+ }
version_obj = _PyDict_GetItemIdWithError(registry, &PyId_version);
if (version_obj == NULL
|| !PyLong_CheckExact(version_obj)
- || PyLong_AsLong(version_obj) != _PyRuntime.warnings.filters_version)
+ || PyLong_AsLong(version_obj) != st->filters_version)
{
if (PyErr_Occurred()) {
return -1;
}
PyDict_Clear(registry);
- version_obj = PyLong_FromLong(_PyRuntime.warnings.filters_version);
+ version_obj = PyLong_FromLong(st->filters_version);
if (version_obj == NULL)
return -1;
if (_PyDict_SetItemId(registry, &PyId_version, version_obj) < 0) {
@@ -567,11 +703,15 @@ warn_explicit(PyObject *category, PyObject *message,
if (_PyUnicode_EqualToASCIIString(action, "once")) {
if (registry == NULL || registry == Py_None) {
- registry = get_once_registry();
+ WarningsState *st = _Warnings_GetState();
+ if (st == NULL) {
+ goto cleanup;
+ }
+ registry = get_once_registry(st);
if (registry == NULL)
goto cleanup;
}
- /* _PyRuntime.warnings.once_registry[(text, category)] = 1 */
+ /* WarningsState.once_registry[(text, category)] = 1 */
rc = update_registry(registry, text, category, 0);
}
else if (_PyUnicode_EqualToASCIIString(action, "module")) {
@@ -925,7 +1065,11 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
static PyObject *
warnings_filters_mutated(PyObject *self, PyObject *args)
{
- _PyRuntime.warnings.filters_version++;
+ WarningsState *st = _Warnings_GetState();
+ if (st == NULL) {
+ return NULL;
+ }
+ st->filters_version++;
Py_RETURN_NONE;
}
@@ -1175,78 +1319,16 @@ static PyMethodDef warnings_functions[] = {
};
-#ifndef Py_DEBUG
-static PyObject *
-create_filter(PyObject *category, _Py_Identifier *id, const char *modname)
-{
- PyObject *modname_obj = NULL;
- PyObject *action_str = _PyUnicode_FromId(id);
- if (action_str == NULL) {
- return NULL;
- }
-
- /* Default to "no module name" for initial filter set */
- if (modname != NULL) {
- modname_obj = PyUnicode_InternFromString(modname);
- if (modname_obj == NULL) {
- return NULL;
- }
- } else {
- modname_obj = Py_None;
- }
-
- /* This assumes the line number is zero for now. */
- return PyTuple_Pack(5, action_str, Py_None,
- category, modname_obj, _PyLong_Zero);
-}
-#endif
-
-
-static PyObject *
-init_filters(void)
-{
-#ifdef Py_DEBUG
- /* Py_DEBUG builds show all warnings by default */
- return PyList_New(0);
-#else
- /* Other builds ignore a number of warning categories by default */
- PyObject *filters = PyList_New(5);
- if (filters == NULL) {
- return NULL;
- }
-
- size_t pos = 0; /* Post-incremented in each use. */
- PyList_SET_ITEM(filters, pos++,
- create_filter(PyExc_DeprecationWarning, &PyId_default, "__main__"));
- PyList_SET_ITEM(filters, pos++,
- create_filter(PyExc_DeprecationWarning, &PyId_ignore, NULL));
- PyList_SET_ITEM(filters, pos++,
- create_filter(PyExc_PendingDeprecationWarning, &PyId_ignore, NULL));
- PyList_SET_ITEM(filters, pos++,
- create_filter(PyExc_ImportWarning, &PyId_ignore, NULL));
- PyList_SET_ITEM(filters, pos++,
- create_filter(PyExc_ResourceWarning, &PyId_ignore, NULL));
-
- for (size_t x = 0; x < pos; x++) {
- if (PyList_GET_ITEM(filters, x) == NULL) {
- Py_DECREF(filters);
- return NULL;
- }
- }
- return filters;
-#endif
-}
-
static struct PyModuleDef warningsmodule = {
PyModuleDef_HEAD_INIT,
- MODULE_NAME,
- warnings__doc__,
- 0,
- warnings_functions,
- NULL,
- NULL,
- NULL,
- NULL
+ MODULE_NAME, /* m_name */
+ warnings__doc__, /* m_doc */
+ 0, /* m_size */
+ warnings_functions, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL /* m_free */
};
@@ -1256,49 +1338,46 @@ _PyWarnings_Init(void)
PyObject *m;
m = PyModule_Create(&warningsmodule);
- if (m == NULL)
+ if (m == NULL) {
return NULL;
-
- struct _warnings_runtime_state *state = &_PyRuntime.warnings;
- if (state->filters == NULL) {
- state->filters = init_filters();
- if (state->filters == NULL)
- return NULL;
}
- Py_INCREF(state->filters);
- if (PyModule_AddObject(m, "filters", state->filters) < 0)
- return NULL;
- if (state->once_registry == NULL) {
- state->once_registry = PyDict_New();
- if (state->once_registry == NULL)
- return NULL;
+ WarningsState *st = _Warnings_GetState();
+ if (st == NULL) {
+ goto error;
}
- Py_INCREF(state->once_registry);
- if (PyModule_AddObject(m, "_onceregistry",
- state->once_registry) < 0)
- return NULL;
-
- if (state->default_action == NULL) {
- state->default_action = PyUnicode_FromString("default");
- if (state->default_action == NULL)
- return NULL;
+ if (_Warnings_InitState(st) < 0) {
+ goto error;
+ }
+
+ Py_INCREF(st->filters);
+ if (PyModule_AddObject(m, "filters", st->filters) < 0) {
+ goto error;
+ }
+
+ Py_INCREF(st->once_registry);
+ if (PyModule_AddObject(m, "_onceregistry", st->once_registry) < 0) {
+ goto error;
+ }
+
+ Py_INCREF(st->default_action);
+ if (PyModule_AddObject(m, "_defaultaction", st->default_action) < 0) {
+ goto error;
}
- Py_INCREF(state->default_action);
- if (PyModule_AddObject(m, "_defaultaction",
- state->default_action) < 0)
- return NULL;
- state->filters_version = 0;
return m;
+
+error:
+ if (st != NULL) {
+ _Warnings_ClearState(st);
+ }
+ Py_DECREF(m);
+ return NULL;
}
-
+// We need this to ensure that warnings still work until late in finalization.
void
-_PyWarnings_Fini(_PyRuntimeState *runtime)
+_PyWarnings_Fini(PyInterpreterState *interp)
{
- struct _warnings_runtime_state *state = &runtime->warnings;
- Py_CLEAR(state->filters);
- Py_CLEAR(state->once_registry);
- Py_CLEAR(state->default_action);
+ _Warnings_ClearState(&interp->warnings);
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index bd4d1d92662..32902aa0d59 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -1288,7 +1288,7 @@ Py_FinalizeEx(void)
PyDict_Fini();
PySlice_Fini();
_PyGC_Fini(runtime);
- _PyWarnings_Fini(runtime);
+ _PyWarnings_Fini(interp);
_Py_HashRandomization_Fini();
_PyArg_Fini();
PyAsyncGen_Fini();
diff --git a/Python/pystate.c b/Python/pystate.c
index e9c4c7d8376..44acfed6b98 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -5,6 +5,7 @@
#include "pycore_coreconfig.h"
#include "pycore_pymem.h"
#include "pycore_pystate.h"
+#include "pycore_pylifecycle.h"
/* --------------------------------------------------------------------------
CAUTION
@@ -257,6 +258,9 @@ _PyInterpreterState_Clear(_PyRuntimeState *runtime, PyInterpreterState *interp)
Py_CLEAR(interp->after_forkers_parent);
Py_CLEAR(interp->after_forkers_child);
#endif
+ if (runtime->finalizing == NULL) {
+ _PyWarnings_Fini(interp);
+ }
// XXX Once we have one allocator per interpreter (i.e.
// per-interpreter GC) we must ensure that all of the interpreter's
// objects have been cleaned up at the point.
From d0d64ad1f5f1dc1630004091d7f8209546c1220a Mon Sep 17 00:00:00 2001
From: Pierre Glaser
Date: Fri, 10 May 2019 20:42:35 +0200
Subject: [PATCH 003/199] bpo-36368: Ignore SIGINT in SharedMemoryManager
servers. (GH-12483)
Fix a bug crashing SharedMemoryManager instances in interactive sessions after
a Ctrl-C (KeyboardInterrupt) was sent.
---
Lib/multiprocessing/managers.py | 4 ++++
Lib/test/_test_multiprocessing.py | 24 +++++++++++++++++++
.../2019-03-21-16-00-00.bpo-36368.zsRT1.rst | 2 ++
3 files changed, 30 insertions(+)
create mode 100644 Misc/NEWS.d/next/Library/2019-03-21-16-00-00.bpo-36368.zsRT1.rst
diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py
index 22abd47fb1f..2bad636855f 100644
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -17,6 +17,7 @@
import sys
import threading
+import signal
import array
import queue
import time
@@ -596,6 +597,9 @@ def _run_server(cls, registry, address, authkey, serializer, writer,
'''
Create a server, report its address and run it
'''
+ # bpo-36368: protect server process from KeyboardInterrupt signals
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+
if initializer is not None:
initializer(*initargs)
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index 836fde88cd2..d97e4232f7a 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -3734,6 +3734,30 @@ def test_shared_memory_across_processes(self):
sms.close()
+ @unittest.skipIf(os.name != "posix", "not feasible in non-posix platforms")
+ def test_shared_memory_SharedMemoryServer_ignores_sigint(self):
+ # bpo-36368: protect SharedMemoryManager server process from
+ # KeyboardInterrupt signals.
+ smm = multiprocessing.managers.SharedMemoryManager()
+ smm.start()
+
+ # make sure the manager works properly at the beginning
+ sl = smm.ShareableList(range(10))
+
+ # the manager's server should ignore KeyboardInterrupt signals, and
+ # maintain its connection with the current process, and success when
+ # asked to deliver memory segments.
+ os.kill(smm._process.pid, signal.SIGINT)
+
+ sl2 = smm.ShareableList(range(10))
+
+ # test that the custom signal handler registered in the Manager does
+ # not affect signal handling in the parent process.
+ with self.assertRaises(KeyboardInterrupt):
+ os.kill(os.getpid(), signal.SIGINT)
+
+ smm.shutdown()
+
def test_shared_memory_SharedMemoryManager_basics(self):
smm1 = multiprocessing.managers.SharedMemoryManager()
with self.assertRaises(ValueError):
diff --git a/Misc/NEWS.d/next/Library/2019-03-21-16-00-00.bpo-36368.zsRT1.rst b/Misc/NEWS.d/next/Library/2019-03-21-16-00-00.bpo-36368.zsRT1.rst
new file mode 100644
index 00000000000..d8426827ced
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-03-21-16-00-00.bpo-36368.zsRT1.rst
@@ -0,0 +1,2 @@
+Fix a bug crashing SharedMemoryManager instances in interactive sessions after
+a ctrl-c (KeyboardInterrupt) was sent
From f22cc69b012f52882d434a5c44a004bc3aa5c33c Mon Sep 17 00:00:00 2001
From: Pierre Glaser
Date: Fri, 10 May 2019 22:59:08 +0200
Subject: [PATCH 004/199] bpo-36867: Make semaphore_tracker track other system
resources (GH-13222)
The multiprocessing.resource_tracker replaces the multiprocessing.semaphore_tracker module. Other than semaphores, resource_tracker also tracks shared_memory segments. Patch by Pierre Glaser.
---
Lib/multiprocessing/forkserver.py | 8 +-
Lib/multiprocessing/popen_spawn_posix.py | 4 +-
...maphore_tracker.py => resource_tracker.py} | 133 ++++++++------
Lib/multiprocessing/shared_memory.py | 5 +
Lib/multiprocessing/spawn.py | 4 +-
Lib/multiprocessing/synchronize.py | 8 +-
Lib/test/_test_multiprocessing.py | 168 ++++++++++++------
.../2019-05-09-18-12-55.bpo-36867.FuwVTi.rst | 1 +
PCbuild/lib.pyproj | 2 +-
9 files changed, 209 insertions(+), 124 deletions(-)
rename Lib/multiprocessing/{semaphore_tracker.py => resource_tracker.py} (53%)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-09-18-12-55.bpo-36867.FuwVTi.rst
diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py
index 040b46e66a0..dabf7bcbe6d 100644
--- a/Lib/multiprocessing/forkserver.py
+++ b/Lib/multiprocessing/forkserver.py
@@ -11,7 +11,7 @@
from . import connection
from . import process
from .context import reduction
-from . import semaphore_tracker
+from . import resource_tracker
from . import spawn
from . import util
@@ -69,7 +69,7 @@ def connect_to_new_process(self, fds):
parent_r, child_w = os.pipe()
child_r, parent_w = os.pipe()
allfds = [child_r, child_w, self._forkserver_alive_fd,
- semaphore_tracker.getfd()]
+ resource_tracker.getfd()]
allfds += fds
try:
reduction.sendfds(client, allfds)
@@ -90,7 +90,7 @@ def ensure_running(self):
ensure_running() will do nothing.
'''
with self._lock:
- semaphore_tracker.ensure_running()
+ resource_tracker.ensure_running()
if self._forkserver_pid is not None:
# forkserver was launched before, is it still running?
pid, status = os.waitpid(self._forkserver_pid, os.WNOHANG)
@@ -290,7 +290,7 @@ def _serve_one(child_r, fds, unused_fds, handlers):
os.close(fd)
(_forkserver._forkserver_alive_fd,
- semaphore_tracker._semaphore_tracker._fd,
+ resource_tracker._resource_tracker._fd,
*_forkserver._inherited_fds) = fds
# Run process object received over pipe
diff --git a/Lib/multiprocessing/popen_spawn_posix.py b/Lib/multiprocessing/popen_spawn_posix.py
index 38151060efa..59f8e452cae 100644
--- a/Lib/multiprocessing/popen_spawn_posix.py
+++ b/Lib/multiprocessing/popen_spawn_posix.py
@@ -36,8 +36,8 @@ def duplicate_for_child(self, fd):
return fd
def _launch(self, process_obj):
- from . import semaphore_tracker
- tracker_fd = semaphore_tracker.getfd()
+ from . import resource_tracker
+ tracker_fd = resource_tracker.getfd()
self._fds.append(tracker_fd)
prep_data = spawn.get_preparation_data(process_obj._name)
fp = io.BytesIO()
diff --git a/Lib/multiprocessing/semaphore_tracker.py b/Lib/multiprocessing/resource_tracker.py
similarity index 53%
rename from Lib/multiprocessing/semaphore_tracker.py
rename to Lib/multiprocessing/resource_tracker.py
index 3c2c3ad61ae..e67e0b213eb 100644
--- a/Lib/multiprocessing/semaphore_tracker.py
+++ b/Lib/multiprocessing/resource_tracker.py
@@ -1,15 +1,19 @@
+###############################################################################
+# Server process to keep track of unlinked resources (like shared memory
+# segments, semaphores etc.) and clean them.
#
# On Unix we run a server process which keeps track of unlinked
-# semaphores. The server ignores SIGINT and SIGTERM and reads from a
+# resources. The server ignores SIGINT and SIGTERM and reads from a
# pipe. Every other process of the program has a copy of the writable
# end of the pipe, so we get EOF when all other processes have exited.
-# Then the server process unlinks any remaining semaphore names.
-#
-# This is important because the system only supports a limited number
-# of named semaphores, and they will not be automatically removed till
-# the next reboot. Without this semaphore tracker process, "killall
-# python" would probably leave unlinked semaphores.
+# Then the server process unlinks any remaining resource names.
#
+# This is important because there may be system limits for such resources: for
+# instance, the system only supports a limited number of named semaphores, and
+# shared-memory segments live in the RAM. If a python process leaks such a
+# resource, this resource will not be removed till the next reboot. Without
+# this resource tracker process, "killall python" would probably leave unlinked
+# resources.
import os
import signal
@@ -17,6 +21,7 @@
import threading
import warnings
import _multiprocessing
+import _posixshmem
from . import spawn
from . import util
@@ -26,8 +31,14 @@
_HAVE_SIGMASK = hasattr(signal, 'pthread_sigmask')
_IGNORED_SIGNALS = (signal.SIGINT, signal.SIGTERM)
+_CLEANUP_FUNCS = {
+ 'noop': lambda: None,
+ 'semaphore': _multiprocessing.sem_unlink,
+ 'shared_memory': _posixshmem.shm_unlink
+}
-class SemaphoreTracker(object):
+
+class ResourceTracker(object):
def __init__(self):
self._lock = threading.Lock()
@@ -39,13 +50,13 @@ def getfd(self):
return self._fd
def ensure_running(self):
- '''Make sure that semaphore tracker process is running.
+ '''Make sure that resource tracker process is running.
This can be run from any process. Usually a child process will use
- the semaphore created by its parent.'''
+ the resource created by its parent.'''
with self._lock:
if self._fd is not None:
- # semaphore tracker was launched before, is it still running?
+ # resource tracker was launched before, is it still running?
if self._check_alive():
# => still alive
return
@@ -55,24 +66,24 @@ def ensure_running(self):
# Clean-up to avoid dangling processes.
try:
# _pid can be None if this process is a child from another
- # python process, which has started the semaphore_tracker.
+ # python process, which has started the resource_tracker.
if self._pid is not None:
os.waitpid(self._pid, 0)
except ChildProcessError:
- # The semaphore_tracker has already been terminated.
+ # The resource_tracker has already been terminated.
pass
self._fd = None
self._pid = None
- warnings.warn('semaphore_tracker: process died unexpectedly, '
- 'relaunching. Some semaphores might leak.')
+ warnings.warn('resource_tracker: process died unexpectedly, '
+ 'relaunching. Some resources might leak.')
fds_to_pass = []
try:
fds_to_pass.append(sys.stderr.fileno())
except Exception:
pass
- cmd = 'from multiprocessing.semaphore_tracker import main;main(%d)'
+ cmd = 'from multiprocessing.resource_tracker import main;main(%d)'
r, w = os.pipe()
try:
fds_to_pass.append(r)
@@ -107,23 +118,23 @@ def _check_alive(self):
try:
# We cannot use send here as it calls ensure_running, creating
# a cycle.
- os.write(self._fd, b'PROBE:0\n')
+ os.write(self._fd, b'PROBE:0:noop\n')
except OSError:
return False
else:
return True
- def register(self, name):
- '''Register name of semaphore with semaphore tracker.'''
- self._send('REGISTER', name)
+ def register(self, name, rtype):
+ '''Register name of resource with resource tracker.'''
+ self._send('REGISTER', name, rtype)
- def unregister(self, name):
- '''Unregister name of semaphore with semaphore tracker.'''
- self._send('UNREGISTER', name)
+ def unregister(self, name, rtype):
+ '''Unregister name of resource with resource tracker.'''
+ self._send('UNREGISTER', name, rtype)
- def _send(self, cmd, name):
+ def _send(self, cmd, name, rtype):
self.ensure_running()
- msg = '{0}:{1}\n'.format(cmd, name).encode('ascii')
+ msg = '{0}:{1}:{2}\n'.format(cmd, name, rtype).encode('ascii')
if len(name) > 512:
# posix guarantees that writes to a pipe of less than PIPE_BUF
# bytes are atomic, and that PIPE_BUF >= 512
@@ -133,14 +144,14 @@ def _send(self, cmd, name):
nbytes, len(msg))
-_semaphore_tracker = SemaphoreTracker()
-ensure_running = _semaphore_tracker.ensure_running
-register = _semaphore_tracker.register
-unregister = _semaphore_tracker.unregister
-getfd = _semaphore_tracker.getfd
+_resource_tracker = ResourceTracker()
+ensure_running = _resource_tracker.ensure_running
+register = _resource_tracker.register
+unregister = _resource_tracker.unregister
+getfd = _resource_tracker.getfd
def main(fd):
- '''Run semaphore tracker.'''
+ '''Run resource tracker.'''
# protect the process from ^C and "killall python" etc
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTERM, signal.SIG_IGN)
@@ -153,18 +164,24 @@ def main(fd):
except Exception:
pass
- cache = set()
+ cache = {rtype: set() for rtype in _CLEANUP_FUNCS.keys()}
try:
- # keep track of registered/unregistered semaphores
+ # keep track of registered/unregistered resources
with open(fd, 'rb') as f:
for line in f:
try:
- cmd, name = line.strip().split(b':')
- if cmd == b'REGISTER':
- cache.add(name)
- elif cmd == b'UNREGISTER':
- cache.remove(name)
- elif cmd == b'PROBE':
+ cmd, name, rtype = line.strip().decode('ascii').split(':')
+ cleanup_func = _CLEANUP_FUNCS.get(rtype, None)
+ if cleanup_func is None:
+ raise ValueError(
+ f'Cannot register {name} for automatic cleanup: '
+ f'unknown resource type {rtype}')
+
+ if cmd == 'REGISTER':
+ cache[rtype].add(name)
+ elif cmd == 'UNREGISTER':
+ cache[rtype].remove(name)
+ elif cmd == 'PROBE':
pass
else:
raise RuntimeError('unrecognized command %r' % cmd)
@@ -174,23 +191,23 @@ def main(fd):
except:
pass
finally:
- # all processes have terminated; cleanup any remaining semaphores
- if cache:
- try:
- warnings.warn('semaphore_tracker: There appear to be %d '
- 'leaked semaphores to clean up at shutdown' %
- len(cache))
- except Exception:
- pass
- for name in cache:
- # For some reason the process which created and registered this
- # semaphore has failed to unregister it. Presumably it has died.
- # We therefore unlink it.
- try:
- name = name.decode('ascii')
+ # all processes have terminated; cleanup any remaining resources
+ for rtype, rtype_cache in cache.items():
+ if rtype_cache:
try:
- _multiprocessing.sem_unlink(name)
- except Exception as e:
- warnings.warn('semaphore_tracker: %r: %s' % (name, e))
- finally:
- pass
+ warnings.warn('resource_tracker: There appear to be %d '
+ 'leaked %s objects to clean up at shutdown' %
+ (len(rtype_cache), rtype))
+ except Exception:
+ pass
+ for name in rtype_cache:
+ # For some reason the process which created and registered this
+ # resource has failed to unregister it. Presumably it has
+ # died. We therefore unlink it.
+ try:
+ try:
+ _CLEANUP_FUNCS[rtype](name)
+ except Exception as e:
+ warnings.warn('resource_tracker: %r: %s' % (name, e))
+ finally:
+ pass
diff --git a/Lib/multiprocessing/shared_memory.py b/Lib/multiprocessing/shared_memory.py
index ebc88858762..184e36704ba 100644
--- a/Lib/multiprocessing/shared_memory.py
+++ b/Lib/multiprocessing/shared_memory.py
@@ -113,6 +113,9 @@ def __init__(self, name=None, create=False, size=0):
self.unlink()
raise
+ from .resource_tracker import register
+ register(self._name, "shared_memory")
+
else:
# Windows Named Shared Memory
@@ -231,7 +234,9 @@ def unlink(self):
called once (and only once) across all processes which have access
to the shared memory block."""
if _USE_POSIX and self._name:
+ from .resource_tracker import unregister
_posixshmem.shm_unlink(self._name)
+ unregister(self._name, "shared_memory")
_encoding = "utf8"
diff --git a/Lib/multiprocessing/spawn.py b/Lib/multiprocessing/spawn.py
index 6759351f13a..f66b5aa9267 100644
--- a/Lib/multiprocessing/spawn.py
+++ b/Lib/multiprocessing/spawn.py
@@ -111,8 +111,8 @@ def spawn_main(pipe_handle, parent_pid=None, tracker_fd=None):
_winapi.CloseHandle(source_process)
fd = msvcrt.open_osfhandle(new_handle, os.O_RDONLY)
else:
- from . import semaphore_tracker
- semaphore_tracker._semaphore_tracker._fd = tracker_fd
+ from . import resource_tracker
+ resource_tracker._resource_tracker._fd = tracker_fd
fd = pipe_handle
exitcode = _main(fd)
sys.exit(exitcode)
diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py
index 5137c49c1b6..4fcbefc8bbe 100644
--- a/Lib/multiprocessing/synchronize.py
+++ b/Lib/multiprocessing/synchronize.py
@@ -76,16 +76,16 @@ def _after_fork(obj):
# We only get here if we are on Unix with forking
# disabled. When the object is garbage collected or the
# process shuts down we unlink the semaphore name
- from .semaphore_tracker import register
- register(self._semlock.name)
+ from .resource_tracker import register
+ register(self._semlock.name, "semaphore")
util.Finalize(self, SemLock._cleanup, (self._semlock.name,),
exitpriority=0)
@staticmethod
def _cleanup(name):
- from .semaphore_tracker import unregister
+ from .resource_tracker import unregister
sem_unlink(name)
- unregister(name)
+ unregister(name, "semaphore")
def _make_methods(self):
self.acquire = self._semlock.acquire
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index d97e4232f7a..a50293c7616 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -88,6 +88,13 @@ def join_process(process):
support.join_thread(process, timeout=TIMEOUT)
+if os.name == "posix":
+ from multiprocessing import resource_tracker
+
+ def _resource_unlink(name, rtype):
+ resource_tracker._CLEANUP_FUNCS[rtype](name)
+
+
#
# Constants
#
@@ -3896,6 +3903,32 @@ def test_shared_memory_ShareableList_pickling(self):
deserialized_sl.shm.close()
sl.shm.close()
+ def test_shared_memory_cleaned_after_process_termination(self):
+ import subprocess
+ from multiprocessing import shared_memory
+ cmd = '''if 1:
+ import os, time, sys
+ from multiprocessing import shared_memory
+
+ # Create a shared_memory segment, and send the segment name
+ sm = shared_memory.SharedMemory(create=True, size=10)
+ sys.stdout.write(sm._name + '\\n')
+ sys.stdout.flush()
+ time.sleep(100)
+ '''
+ p = subprocess.Popen([sys.executable, '-E', '-c', cmd],
+ stdout=subprocess.PIPE)
+ name = p.stdout.readline().strip().decode()
+
+ # killing abruptly processes holding reference to a shared memory
+ # segment should not leak the given memory segment.
+ p.terminate()
+ p.wait()
+ time.sleep(1.0) # wait for the OS to collect the segment
+
+ with self.assertRaises(FileNotFoundError):
+ smm = shared_memory.SharedMemory(name, create=False)
+
#
#
#
@@ -4827,57 +4860,86 @@ def test_preload_resources(self):
@unittest.skipIf(sys.platform == "win32",
"test semantics don't make sense on Windows")
-class TestSemaphoreTracker(unittest.TestCase):
+class TestResourceTracker(unittest.TestCase):
- def test_semaphore_tracker(self):
+ def test_resource_tracker(self):
#
# Check that killing process does not leak named semaphores
#
import subprocess
cmd = '''if 1:
- import multiprocessing as mp, time, os
+ import time, os, tempfile
+ import multiprocessing as mp
+ from multiprocessing import resource_tracker
+ from multiprocessing.shared_memory import SharedMemory
+
mp.set_start_method("spawn")
- lock1 = mp.Lock()
- lock2 = mp.Lock()
- os.write(%d, lock1._semlock.name.encode("ascii") + b"\\n")
- os.write(%d, lock2._semlock.name.encode("ascii") + b"\\n")
+ rand = tempfile._RandomNameSequence()
+
+
+ def create_and_register_resource(rtype):
+ if rtype == "semaphore":
+ lock = mp.Lock()
+ return lock, lock._semlock.name
+ elif rtype == "shared_memory":
+ sm = SharedMemory(create=True, size=10)
+ return sm, sm._name
+ else:
+ raise ValueError(
+ "Resource type {{}} not understood".format(rtype))
+
+
+ resource1, rname1 = create_and_register_resource("{rtype}")
+ resource2, rname2 = create_and_register_resource("{rtype}")
+
+ os.write({w}, rname1.encode("ascii") + b"\\n")
+ os.write({w}, rname2.encode("ascii") + b"\\n")
+
time.sleep(10)
'''
- r, w = os.pipe()
- p = subprocess.Popen([sys.executable,
- '-E', '-c', cmd % (w, w)],
- pass_fds=[w],
- stderr=subprocess.PIPE)
- os.close(w)
- with open(r, 'rb', closefd=True) as f:
- name1 = f.readline().rstrip().decode('ascii')
- name2 = f.readline().rstrip().decode('ascii')
- _multiprocessing.sem_unlink(name1)
- p.terminate()
- p.wait()
- time.sleep(2.0)
- with self.assertRaises(OSError) as ctx:
- _multiprocessing.sem_unlink(name2)
- # docs say it should be ENOENT, but OSX seems to give EINVAL
- self.assertIn(ctx.exception.errno, (errno.ENOENT, errno.EINVAL))
- err = p.stderr.read().decode('utf-8')
- p.stderr.close()
- expected = 'semaphore_tracker: There appear to be 2 leaked semaphores'
- self.assertRegex(err, expected)
- self.assertRegex(err, r'semaphore_tracker: %r: \[Errno' % name1)
+ for rtype in resource_tracker._CLEANUP_FUNCS:
+ with self.subTest(rtype=rtype):
+ if rtype == "noop":
+ # Artefact resource type used by the resource_tracker
+ continue
+ r, w = os.pipe()
+ p = subprocess.Popen([sys.executable,
+ '-E', '-c', cmd.format(w=w, rtype=rtype)],
+ pass_fds=[w],
+ stderr=subprocess.PIPE)
+ os.close(w)
+ with open(r, 'rb', closefd=True) as f:
+ name1 = f.readline().rstrip().decode('ascii')
+ name2 = f.readline().rstrip().decode('ascii')
+ _resource_unlink(name1, rtype)
+ p.terminate()
+ p.wait()
+ time.sleep(2.0)
+ with self.assertRaises(OSError) as ctx:
+ _resource_unlink(name2, rtype)
+ # docs say it should be ENOENT, but OSX seems to give EINVAL
+ self.assertIn(
+ ctx.exception.errno, (errno.ENOENT, errno.EINVAL))
+ err = p.stderr.read().decode('utf-8')
+ p.stderr.close()
+ expected = ('resource_tracker: There appear to be 2 leaked {} '
+ 'objects'.format(
+ rtype))
+ self.assertRegex(err, expected)
+ self.assertRegex(err, r'resource_tracker: %r: \[Errno' % name1)
- def check_semaphore_tracker_death(self, signum, should_die):
+ def check_resource_tracker_death(self, signum, should_die):
# bpo-31310: if the semaphore tracker process has died, it should
# be restarted implicitly.
- from multiprocessing.semaphore_tracker import _semaphore_tracker
- pid = _semaphore_tracker._pid
+ from multiprocessing.resource_tracker import _resource_tracker
+ pid = _resource_tracker._pid
if pid is not None:
os.kill(pid, signal.SIGKILL)
os.waitpid(pid, 0)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
- _semaphore_tracker.ensure_running()
- pid = _semaphore_tracker._pid
+ _resource_tracker.ensure_running()
+ pid = _resource_tracker._pid
os.kill(pid, signum)
time.sleep(1.0) # give it time to die
@@ -4898,50 +4960,50 @@ def check_semaphore_tracker_death(self, signum, should_die):
self.assertEqual(len(all_warn), 1)
the_warn = all_warn[0]
self.assertTrue(issubclass(the_warn.category, UserWarning))
- self.assertTrue("semaphore_tracker: process died"
+ self.assertTrue("resource_tracker: process died"
in str(the_warn.message))
else:
self.assertEqual(len(all_warn), 0)
- def test_semaphore_tracker_sigint(self):
+ def test_resource_tracker_sigint(self):
# Catchable signal (ignored by semaphore tracker)
- self.check_semaphore_tracker_death(signal.SIGINT, False)
+ self.check_resource_tracker_death(signal.SIGINT, False)
- def test_semaphore_tracker_sigterm(self):
+ def test_resource_tracker_sigterm(self):
# Catchable signal (ignored by semaphore tracker)
- self.check_semaphore_tracker_death(signal.SIGTERM, False)
+ self.check_resource_tracker_death(signal.SIGTERM, False)
- def test_semaphore_tracker_sigkill(self):
+ def test_resource_tracker_sigkill(self):
# Uncatchable signal.
- self.check_semaphore_tracker_death(signal.SIGKILL, True)
+ self.check_resource_tracker_death(signal.SIGKILL, True)
@staticmethod
- def _is_semaphore_tracker_reused(conn, pid):
- from multiprocessing.semaphore_tracker import _semaphore_tracker
- _semaphore_tracker.ensure_running()
+ def _is_resource_tracker_reused(conn, pid):
+ from multiprocessing.resource_tracker import _resource_tracker
+ _resource_tracker.ensure_running()
# The pid should be None in the child process, expect for the fork
# context. It should not be a new value.
- reused = _semaphore_tracker._pid in (None, pid)
- reused &= _semaphore_tracker._check_alive()
+ reused = _resource_tracker._pid in (None, pid)
+ reused &= _resource_tracker._check_alive()
conn.send(reused)
- def test_semaphore_tracker_reused(self):
- from multiprocessing.semaphore_tracker import _semaphore_tracker
- _semaphore_tracker.ensure_running()
- pid = _semaphore_tracker._pid
+ def test_resource_tracker_reused(self):
+ from multiprocessing.resource_tracker import _resource_tracker
+ _resource_tracker.ensure_running()
+ pid = _resource_tracker._pid
r, w = multiprocessing.Pipe(duplex=False)
- p = multiprocessing.Process(target=self._is_semaphore_tracker_reused,
+ p = multiprocessing.Process(target=self._is_resource_tracker_reused,
args=(w, pid))
p.start()
- is_semaphore_tracker_reused = r.recv()
+ is_resource_tracker_reused = r.recv()
# Clean up
p.join()
w.close()
r.close()
- self.assertTrue(is_semaphore_tracker_reused)
+ self.assertTrue(is_resource_tracker_reused)
class TestSimpleQueue(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Library/2019-05-09-18-12-55.bpo-36867.FuwVTi.rst b/Misc/NEWS.d/next/Library/2019-05-09-18-12-55.bpo-36867.FuwVTi.rst
new file mode 100644
index 00000000000..5eaf0a032cc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-09-18-12-55.bpo-36867.FuwVTi.rst
@@ -0,0 +1 @@
+The multiprocessing.resource_tracker replaces the multiprocessing.semaphore_tracker module. Other than semaphores, resource_tracker also tracks shared_memory segments.
\ No newline at end of file
diff --git a/PCbuild/lib.pyproj b/PCbuild/lib.pyproj
index ffb95c6efcd..7ed71bd819c 100644
--- a/PCbuild/lib.pyproj
+++ b/PCbuild/lib.pyproj
@@ -678,7 +678,7 @@
-
+
From 09532feeece39d5ba68a0d47115ce1967bfbd58e Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Fri, 10 May 2019 23:39:09 +0200
Subject: [PATCH 005/199] bpo-36710: Add 'ceval' local variable to ceval.c
(GH-12934)
Add "struct _ceval_runtime_state *ceval = &_PyRuntime.ceval;" local
variables to function to better highlight the dependency on the
global variable _PyRuntime and to point directly to _PyRuntime.ceval
field rather than on the larger _PyRuntime.
Changes:
* Add _PyRuntimeState_GetThreadState(runtime) macro.
* Add _PyEval_AddPendingCall(ceval, ...) and
_PyThreadState_Swap(gilstate, ...) functions.
* _PyThreadState_GET() macro now calls
_PyRuntimeState_GetThreadState() using &_PyRuntime.
* Add 'ceval' parameter to COMPUTE_EVAL_BREAKER(),
SIGNAL_PENDING_SIGNALS(), _PyEval_SignalAsyncExc(),
_PyEval_SignalReceived() and _PyEval_FiniThreads() macros and
functions.
* Add 'tstate' parameter to call_function(), do_call_core() and
do_raise().
* Add 'runtime' parameter to _Py_CURRENTLY_FINALIZING(),
_Py_FinishPendingCalls() and _PyThreadState_DeleteExcept()
macros and functions.
* Declare 'runtime', 'tstate', 'ceval' and 'eval_breaker' variables
as constant.
---
Include/ceval.h | 5 -
Include/internal/pycore_ceval.h | 53 +----
Include/internal/pycore_pystate.h | 59 ++++-
Modules/signalmodule.c | 23 +-
Python/ceval.c | 369 +++++++++++++++++-------------
Python/ceval_gil.h | 156 ++++++-------
Python/pylifecycle.c | 9 +-
Python/pystate.c | 16 +-
8 files changed, 370 insertions(+), 320 deletions(-)
diff --git a/Include/ceval.h b/Include/ceval.h
index 11283c0a570..2d4b67d092b 100644
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -58,7 +58,6 @@ PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
#endif
PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg);
-PyAPI_FUNC(void) _PyEval_SignalReceived(void);
PyAPI_FUNC(int) Py_MakePendingCalls(void);
/* Protection against deeply nested recursive calls
@@ -192,9 +191,6 @@ PyAPI_FUNC(void) PyEval_RestoreThread(PyThreadState *);
PyAPI_FUNC(int) PyEval_ThreadsInitialized(void);
PyAPI_FUNC(void) PyEval_InitThreads(void);
-#ifndef Py_LIMITED_API
-PyAPI_FUNC(void) _PyEval_FiniThreads(void);
-#endif /* !Py_LIMITED_API */
PyAPI_FUNC(void) PyEval_AcquireLock(void) Py_DEPRECATED(3.2);
PyAPI_FUNC(void) PyEval_ReleaseLock(void) /* Py_DEPRECATED(3.2) */;
PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate);
@@ -221,7 +217,6 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
#ifndef Py_LIMITED_API
PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
-PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void);
#endif
/* Masks and values used by FORMAT_VALUE opcode. */
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index 0bb19f1aa3b..cdc73a36e5b 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -9,50 +9,21 @@ extern "C" {
#endif
#include "pycore_atomic.h"
+#include "pycore_pystate.h"
#include "pythread.h"
-PyAPI_FUNC(void) _Py_FinishPendingCalls(void);
-
-struct _pending_calls {
- int finishing;
- PyThread_type_lock lock;
- /* Request for running pending calls. */
- _Py_atomic_int calls_to_do;
- /* Request for looking at the `async_exc` field of the current
- thread state.
- Guarded by the GIL. */
- int async_exc;
-#define NPENDINGCALLS 32
- struct {
- int (*func)(void *);
- void *arg;
- } calls[NPENDINGCALLS];
- int first;
- int last;
-};
-
-#include "pycore_gil.h"
-
-struct _ceval_runtime_state {
- int recursion_limit;
- /* Records whether tracing is on for any thread. Counts the number
- of threads for which tstate->c_tracefunc is non-NULL, so if the
- value is 0, we know we don't have to check this thread's
- c_tracefunc. This speeds up the if statement in
- PyEval_EvalFrameEx() after fast_next_opcode. */
- int tracing_possible;
- /* This single variable consolidates all requests to break out of
- the fast path in the eval loop. */
- _Py_atomic_int eval_breaker;
- /* Request for dropping the GIL */
- _Py_atomic_int gil_drop_request;
- struct _pending_calls pending;
- /* Request for checking signals. */
- _Py_atomic_int signals_pending;
- struct _gil_runtime_state gil;
-};
-
+PyAPI_FUNC(void) _Py_FinishPendingCalls(_PyRuntimeState *runtime);
PyAPI_FUNC(void) _PyEval_Initialize(struct _ceval_runtime_state *);
+PyAPI_FUNC(void) _PyEval_FiniThreads(
+ struct _ceval_runtime_state *ceval);
+PyAPI_FUNC(void) _PyEval_SignalReceived(
+ struct _ceval_runtime_state *ceval);
+PyAPI_FUNC(int) _PyEval_AddPendingCall(
+ struct _ceval_runtime_state *ceval,
+ int (*func)(void *),
+ void *arg);
+PyAPI_FUNC(void) _PyEval_SignalAsyncExc(
+ struct _ceval_runtime_state *ceval);
#ifdef __cplusplus
}
diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h
index 69ceecba40d..1561328e607 100644
--- a/Include/internal/pycore_pystate.h
+++ b/Include/internal/pycore_pystate.h
@@ -12,12 +12,51 @@ extern "C" {
#include "pystate.h"
#include "pythread.h"
-#include "pycore_ceval.h"
+#include "pycore_gil.h" /* _gil_runtime_state */
#include "pycore_pathconfig.h"
#include "pycore_pymem.h"
#include "pycore_warnings.h"
+/* ceval state */
+
+struct _pending_calls {
+ int finishing;
+ PyThread_type_lock lock;
+ /* Request for running pending calls. */
+ _Py_atomic_int calls_to_do;
+ /* Request for looking at the `async_exc` field of the current
+ thread state.
+ Guarded by the GIL. */
+ int async_exc;
+#define NPENDINGCALLS 32
+ struct {
+ int (*func)(void *);
+ void *arg;
+ } calls[NPENDINGCALLS];
+ int first;
+ int last;
+};
+
+struct _ceval_runtime_state {
+ int recursion_limit;
+ /* Records whether tracing is on for any thread. Counts the number
+ of threads for which tstate->c_tracefunc is non-NULL, so if the
+ value is 0, we know we don't have to check this thread's
+ c_tracefunc. This speeds up the if statement in
+ PyEval_EvalFrameEx() after fast_next_opcode. */
+ int tracing_possible;
+ /* This single variable consolidates all requests to break out of
+ the fast path in the eval loop. */
+ _Py_atomic_int eval_breaker;
+ /* Request for dropping the GIL */
+ _Py_atomic_int gil_drop_request;
+ struct _pending_calls pending;
+ /* Request for checking signals. */
+ _Py_atomic_int signals_pending;
+ struct _gil_runtime_state gil;
+};
+
/* interpreter state */
typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int);
@@ -203,13 +242,16 @@ PyAPI_FUNC(_PyInitError) _PyRuntime_Initialize(void);
PyAPI_FUNC(void) _PyRuntime_Finalize(void);
-#define _Py_CURRENTLY_FINALIZING(tstate) \
- (_PyRuntime.finalizing == tstate)
+#define _Py_CURRENTLY_FINALIZING(runtime, tstate) \
+ (runtime->finalizing == tstate)
/* Variable and macro for in-line access to current thread
and interpreter state */
+#define _PyRuntimeState_GetThreadState(runtime) \
+ ((PyThreadState*)_Py_atomic_load_relaxed(&(runtime)->gilstate.tstate_current))
+
/* Get the current Python thread state.
Efficient macro reading directly the 'gilstate.tstate_current' atomic
@@ -219,8 +261,7 @@ PyAPI_FUNC(void) _PyRuntime_Finalize(void);
The caller must hold the GIL.
See also PyThreadState_Get() and PyThreadState_GET(). */
-#define _PyThreadState_GET() \
- ((PyThreadState*)_Py_atomic_load_relaxed(&_PyRuntime.gilstate.tstate_current))
+#define _PyThreadState_GET() _PyRuntimeState_GetThreadState(&_PyRuntime)
/* Redefine PyThreadState_GET() as an alias to _PyThreadState_GET() */
#undef PyThreadState_GET
@@ -242,7 +283,13 @@ PyAPI_FUNC(void) _PyRuntime_Finalize(void);
PyAPI_FUNC(void) _PyThreadState_Init(
_PyRuntimeState *runtime,
PyThreadState *tstate);
-PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate);
+PyAPI_FUNC(void) _PyThreadState_DeleteExcept(
+ _PyRuntimeState *runtime,
+ PyThreadState *tstate);
+
+PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap(
+ struct _gilstate_runtime_state *gilstate,
+ PyThreadState *newts);
PyAPI_FUNC(_PyInitError) _PyInterpreterState_Enable(_PyRuntimeState *runtime);
PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime);
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index 43a4da1a627..b5e6250b1b4 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -5,6 +5,8 @@
#include "Python.h"
#include "pycore_atomic.h"
+#include "pycore_ceval.h"
+#include "pycore_pystate.h"
#ifndef MS_WINDOWS
#include "posixmodule.h"
@@ -256,7 +258,8 @@ trip_signal(int sig_num)
_Py_atomic_store(&is_tripped, 1);
/* Notify ceval.c */
- _PyEval_SignalReceived();
+ _PyRuntimeState *runtime = &_PyRuntime;
+ _PyEval_SignalReceived(&runtime->ceval);
/* And then write to the wakeup fd *after* setting all the globals and
doing the _PyEval_SignalReceived. We used to write to the wakeup fd
@@ -296,8 +299,9 @@ trip_signal(int sig_num)
{
/* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */
- Py_AddPendingCall(report_wakeup_send_error,
- (void *)(intptr_t) last_error);
+ _PyEval_AddPendingCall(&runtime->ceval,
+ report_wakeup_send_error,
+ (void *)(intptr_t) last_error);
}
}
}
@@ -314,8 +318,9 @@ trip_signal(int sig_num)
{
/* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */
- Py_AddPendingCall(report_wakeup_write_error,
- (void *)(intptr_t)errno);
+ _PyEval_AddPendingCall(&runtime->ceval,
+ report_wakeup_write_error,
+ (void *)(intptr_t)errno);
}
}
}
@@ -420,7 +425,7 @@ signal_raise_signal_impl(PyObject *module, int signalnum)
err = raise(signalnum);
_Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
-
+
if (err) {
return PyErr_SetFromErrno(PyExc_OSError);
}
@@ -1076,18 +1081,18 @@ fill_siginfo(siginfo_t *si)
PyStructSequence_SET_ITEM(result, 0, PyLong_FromLong((long)(si->si_signo)));
PyStructSequence_SET_ITEM(result, 1, PyLong_FromLong((long)(si->si_code)));
-#ifdef __VXWORKS__
+#ifdef __VXWORKS__
PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong(0L));
PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong(0L));
PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong(0L));
PyStructSequence_SET_ITEM(result, 5, PyLong_FromLong(0L));
-#else
+#else
PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong((long)(si->si_errno)));
PyStructSequence_SET_ITEM(result, 3, PyLong_FromPid(si->si_pid));
PyStructSequence_SET_ITEM(result, 4, _PyLong_FromUid(si->si_uid));
PyStructSequence_SET_ITEM(result, 5,
PyLong_FromLong((long)(si->si_status)));
-#endif
+#endif
#ifdef HAVE_SIGINFO_T_SI_BAND
PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(si->si_band));
#else
diff --git a/Python/ceval.c b/Python/ceval.c
index 07db1d378b6..17439533a3f 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -10,6 +10,7 @@
#define PY_LOCAL_AGGRESSIVE
#include "Python.h"
+#include "pycore_ceval.h"
#include "pycore_object.h"
#include "pycore_pystate.h"
#include "pycore_tupleobject.h"
@@ -40,9 +41,12 @@ extern int _PyObject_GetMethod(PyObject *, PyObject *, PyObject **);
typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
/* Forward declarations */
-Py_LOCAL_INLINE(PyObject *) call_function(PyObject ***, Py_ssize_t,
- PyObject *);
-static PyObject * do_call_core(PyObject *, PyObject *, PyObject *);
+Py_LOCAL_INLINE(PyObject *) call_function(
+ PyThreadState *tstate, PyObject ***pp_stack,
+ Py_ssize_t oparg, PyObject *kwnames);
+static PyObject * do_call_core(
+ PyThreadState *tstate, PyObject *func,
+ PyObject *callargs, PyObject *kwdict);
#ifdef LLTRACE
static int lltrace;
@@ -76,7 +80,6 @@ static PyObject * special_lookup(PyObject *, _Py_Identifier *);
static int check_args_iterable(PyObject *func, PyObject *vararg);
static void format_kwargs_error(PyObject *func, PyObject *kwargs);
static void format_awaitable_error(PyTypeObject *, int);
-static inline void exit_thread_if_finalizing(PyThreadState *);
#define NAME_ERROR_MSG \
"name '%.200s' is not defined"
@@ -96,66 +99,66 @@ static long dxp[256];
#endif
#endif
-#define GIL_REQUEST _Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request)
+#define GIL_REQUEST _Py_atomic_load_relaxed(&ceval->gil_drop_request)
/* This can set eval_breaker to 0 even though gil_drop_request became
1. We believe this is all right because the eval loop will release
the GIL eventually anyway. */
-#define COMPUTE_EVAL_BREAKER() \
+#define COMPUTE_EVAL_BREAKER(ceval) \
_Py_atomic_store_relaxed( \
- &_PyRuntime.ceval.eval_breaker, \
+ &(ceval)->eval_breaker, \
GIL_REQUEST | \
- _Py_atomic_load_relaxed(&_PyRuntime.ceval.signals_pending) | \
- _Py_atomic_load_relaxed(&_PyRuntime.ceval.pending.calls_to_do) | \
- _PyRuntime.ceval.pending.async_exc)
+ _Py_atomic_load_relaxed(&(ceval)->signals_pending) | \
+ _Py_atomic_load_relaxed(&(ceval)->pending.calls_to_do) | \
+ (ceval)->pending.async_exc)
-#define SET_GIL_DROP_REQUEST() \
+#define SET_GIL_DROP_REQUEST(ceval) \
do { \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 1); \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
+ _Py_atomic_store_relaxed(&(ceval)->gil_drop_request, 1); \
+ _Py_atomic_store_relaxed(&(ceval)->eval_breaker, 1); \
} while (0)
-#define RESET_GIL_DROP_REQUEST() \
+#define RESET_GIL_DROP_REQUEST(ceval) \
do { \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 0); \
- COMPUTE_EVAL_BREAKER(); \
+ _Py_atomic_store_relaxed(&(ceval)->gil_drop_request, 0); \
+ COMPUTE_EVAL_BREAKER(ceval); \
} while (0)
/* Pending calls are only modified under pending_lock */
-#define SIGNAL_PENDING_CALLS() \
+#define SIGNAL_PENDING_CALLS(ceval) \
do { \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.pending.calls_to_do, 1); \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
+ _Py_atomic_store_relaxed(&(ceval)->pending.calls_to_do, 1); \
+ _Py_atomic_store_relaxed(&(ceval)->eval_breaker, 1); \
} while (0)
-#define UNSIGNAL_PENDING_CALLS() \
+#define UNSIGNAL_PENDING_CALLS(ceval) \
do { \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.pending.calls_to_do, 0); \
- COMPUTE_EVAL_BREAKER(); \
+ _Py_atomic_store_relaxed(&(ceval)->pending.calls_to_do, 0); \
+ COMPUTE_EVAL_BREAKER(ceval); \
} while (0)
-#define SIGNAL_PENDING_SIGNALS() \
+#define SIGNAL_PENDING_SIGNALS(ceval) \
do { \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.signals_pending, 1); \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
+ _Py_atomic_store_relaxed(&(ceval)->signals_pending, 1); \
+ _Py_atomic_store_relaxed(&(ceval)->eval_breaker, 1); \
} while (0)
-#define UNSIGNAL_PENDING_SIGNALS() \
+#define UNSIGNAL_PENDING_SIGNALS(ceval) \
do { \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.signals_pending, 0); \
- COMPUTE_EVAL_BREAKER(); \
+ _Py_atomic_store_relaxed(&(ceval)->signals_pending, 0); \
+ COMPUTE_EVAL_BREAKER(ceval); \
} while (0)
-#define SIGNAL_ASYNC_EXC() \
+#define SIGNAL_ASYNC_EXC(ceval) \
do { \
- _PyRuntime.ceval.pending.async_exc = 1; \
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
+ (ceval)->pending.async_exc = 1; \
+ _Py_atomic_store_relaxed(&(ceval)->eval_breaker, 1); \
} while (0)
-#define UNSIGNAL_ASYNC_EXC() \
+#define UNSIGNAL_ASYNC_EXC(ceval) \
do { \
- _PyRuntime.ceval.pending.async_exc = 0; \
- COMPUTE_EVAL_BREAKER(); \
+ (ceval)->pending.async_exc = 0; \
+ COMPUTE_EVAL_BREAKER(ceval); \
} while (0)
@@ -168,48 +171,55 @@ static long dxp[256];
int
PyEval_ThreadsInitialized(void)
{
- return gil_created();
+ return gil_created(&_PyRuntime.ceval.gil);
}
void
PyEval_InitThreads(void)
{
- if (gil_created()) {
+ _PyRuntimeState *runtime = &_PyRuntime;
+ struct _ceval_runtime_state *ceval = &runtime->ceval;
+ struct _gil_runtime_state *gil = &ceval->gil;
+ if (gil_created(gil)) {
return;
}
PyThread_init_thread();
- create_gil();
- take_gil(_PyThreadState_GET());
+ create_gil(gil);
+ PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
+ take_gil(ceval, tstate);
- _PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
- if (_PyRuntime.ceval.pending.lock == NULL) {
+ struct _pending_calls *pending = &ceval->pending;
+ pending->lock = PyThread_allocate_lock();
+ if (pending->lock == NULL) {
Py_FatalError("Can't initialize threads for pending calls");
}
}
void
-_PyEval_FiniThreads(void)
+_PyEval_FiniThreads(struct _ceval_runtime_state *ceval)
{
- if (!gil_created()) {
+ struct _gil_runtime_state *gil = &ceval->gil;
+ if (!gil_created(gil)) {
return;
}
- destroy_gil();
- assert(!gil_created());
+ destroy_gil(gil);
+ assert(!gil_created(gil));
- if (_PyRuntime.ceval.pending.lock != NULL) {
- PyThread_free_lock(_PyRuntime.ceval.pending.lock);
- _PyRuntime.ceval.pending.lock = NULL;
+ struct _pending_calls *pending = &ceval->pending;
+ if (pending->lock != NULL) {
+ PyThread_free_lock(pending->lock);
+ pending->lock = NULL;
}
}
static inline void
-exit_thread_if_finalizing(PyThreadState *tstate)
+exit_thread_if_finalizing(_PyRuntimeState *runtime, PyThreadState *tstate)
{
/* _Py_Finalizing is protected by the GIL */
- if (_Py_IsFinalizing() && !_Py_CURRENTLY_FINALIZING(tstate)) {
- drop_gil(tstate);
+ if (runtime->finalizing != NULL && !_Py_CURRENTLY_FINALIZING(runtime, tstate)) {
+ drop_gil(&runtime->ceval, tstate);
PyThread_exit_thread();
}
}
@@ -217,45 +227,60 @@ exit_thread_if_finalizing(PyThreadState *tstate)
void
PyEval_AcquireLock(void)
{
- PyThreadState *tstate = _PyThreadState_GET();
- if (tstate == NULL)
+ _PyRuntimeState *runtime = &_PyRuntime;
+ struct _ceval_runtime_state *ceval = &runtime->ceval;
+ PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
+ if (tstate == NULL) {
Py_FatalError("PyEval_AcquireLock: current thread state is NULL");
- take_gil(tstate);
- exit_thread_if_finalizing(tstate);
+ }
+ take_gil(ceval, tstate);
+ exit_thread_if_finalizing(runtime, tstate);
}
void
PyEval_ReleaseLock(void)
{
+ _PyRuntimeState *runtime = &_PyRuntime;
+ PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
/* This function must succeed when the current thread state is NULL.
We therefore avoid PyThreadState_Get() which dumps a fatal error
in debug mode.
*/
- drop_gil(_PyThreadState_GET());
+ drop_gil(&runtime->ceval, tstate);
}
void
PyEval_AcquireThread(PyThreadState *tstate)
{
- if (tstate == NULL)
+ if (tstate == NULL) {
Py_FatalError("PyEval_AcquireThread: NULL new thread state");
+ }
+
+ _PyRuntimeState *runtime = &_PyRuntime;
+ struct _ceval_runtime_state *ceval = &runtime->ceval;
+
/* Check someone has called PyEval_InitThreads() to create the lock */
- assert(gil_created());
- take_gil(tstate);
- exit_thread_if_finalizing(tstate);
- if (PyThreadState_Swap(tstate) != NULL)
- Py_FatalError(
- "PyEval_AcquireThread: non-NULL old thread state");
+ assert(gil_created(&ceval->gil));
+ take_gil(ceval, tstate);
+ exit_thread_if_finalizing(runtime, tstate);
+ if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) {
+ Py_FatalError("PyEval_AcquireThread: non-NULL old thread state");
+ }
}
void
PyEval_ReleaseThread(PyThreadState *tstate)
{
- if (tstate == NULL)
+ if (tstate == NULL) {
Py_FatalError("PyEval_ReleaseThread: NULL thread state");
- if (PyThreadState_Swap(NULL) != tstate)
+ }
+
+ _PyRuntimeState *runtime = &_PyRuntime;
+ PyThreadState *new_tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
+ if (new_tstate != tstate) {
Py_FatalError("PyEval_ReleaseThread: wrong thread state");
- drop_gil(tstate);
+ }
+ drop_gil(&runtime->ceval, tstate);
}
/* This function is called from PyOS_AfterFork_Child to destroy all threads
@@ -266,55 +291,65 @@ PyEval_ReleaseThread(PyThreadState *tstate)
void
PyEval_ReInitThreads(void)
{
- PyThreadState *current_tstate = _PyThreadState_GET();
-
- if (!gil_created())
+ _PyRuntimeState *runtime = &_PyRuntime;
+ struct _ceval_runtime_state *ceval = &runtime->ceval;
+ if (!gil_created(&ceval->gil)) {
return;
- recreate_gil();
- take_gil(current_tstate);
+ }
+ recreate_gil(&ceval->gil);
+ PyThreadState *current_tstate = _PyRuntimeState_GetThreadState(runtime);
+ take_gil(ceval, current_tstate);
- _PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
- if (_PyRuntime.ceval.pending.lock == NULL) {
+ struct _pending_calls *pending = &ceval->pending;
+ pending->lock = PyThread_allocate_lock();
+ if (pending->lock == NULL) {
Py_FatalError("Can't initialize threads for pending calls");
}
/* Destroy all threads except the current one */
- _PyThreadState_DeleteExcept(current_tstate);
+ _PyThreadState_DeleteExcept(runtime, current_tstate);
}
/* This function is used to signal that async exceptions are waiting to be
raised. */
void
-_PyEval_SignalAsyncExc(void)
+_PyEval_SignalAsyncExc(struct _ceval_runtime_state *ceval)
{
- SIGNAL_ASYNC_EXC();
+ SIGNAL_ASYNC_EXC(ceval);
}
PyThreadState *
PyEval_SaveThread(void)
{
- PyThreadState *tstate = PyThreadState_Swap(NULL);
- if (tstate == NULL)
+ _PyRuntimeState *runtime = &_PyRuntime;
+ struct _ceval_runtime_state *ceval = &runtime->ceval;
+ PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
+ if (tstate == NULL) {
Py_FatalError("PyEval_SaveThread: NULL tstate");
- assert(gil_created());
- drop_gil(tstate);
+ }
+ assert(gil_created(&ceval->gil));
+ drop_gil(ceval, tstate);
return tstate;
}
void
PyEval_RestoreThread(PyThreadState *tstate)
{
- if (tstate == NULL)
+ _PyRuntimeState *runtime = &_PyRuntime;
+ struct _ceval_runtime_state *ceval = &runtime->ceval;
+
+ if (tstate == NULL) {
Py_FatalError("PyEval_RestoreThread: NULL tstate");
- assert(gil_created());
+ }
+ assert(gil_created(&ceval->gil));
int err = errno;
- take_gil(tstate);
- exit_thread_if_finalizing(tstate);
+ take_gil(ceval, tstate);
+ exit_thread_if_finalizing(runtime, tstate);
errno = err;
- PyThreadState_Swap(tstate);
+ _PyThreadState_Swap(&runtime->gilstate, tstate);
}
@@ -341,12 +376,12 @@ PyEval_RestoreThread(PyThreadState *tstate)
*/
void
-_PyEval_SignalReceived(void)
+_PyEval_SignalReceived(struct _ceval_runtime_state *ceval)
{
/* bpo-30703: Function called when the C signal handler of Python gets a
signal. We cannot queue a callback using Py_AddPendingCall() since
that function is not async-signal-safe. */
- SIGNAL_PENDING_SIGNALS();
+ SIGNAL_PENDING_SIGNALS(ceval);
}
/* Push one item onto the queue while holding the lock. */
@@ -386,9 +421,10 @@ _pop_pending_call(struct _pending_calls *pending,
*/
int
-Py_AddPendingCall(int (*func)(void *), void *arg)
+_PyEval_AddPendingCall(struct _ceval_runtime_state *ceval,
+ int (*func)(void *), void *arg)
{
- struct _pending_calls *pending = &_PyRuntime.ceval.pending;
+ struct _pending_calls *pending = &ceval->pending;
PyThread_acquire_lock(pending->lock, WAIT_LOCK);
if (pending->finishing) {
@@ -407,42 +443,50 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
PyThread_release_lock(pending->lock);
/* signal main loop */
- SIGNAL_PENDING_CALLS();
+ SIGNAL_PENDING_CALLS(ceval);
return result;
}
+int
+Py_AddPendingCall(int (*func)(void *), void *arg)
+{
+ return _PyEval_AddPendingCall(&_PyRuntime.ceval, func, arg);
+}
+
static int
-handle_signals(void)
+handle_signals(_PyRuntimeState *runtime)
{
/* Only handle signals on main thread. PyEval_InitThreads must
* have been called already.
*/
- if (PyThread_get_thread_ident() != _PyRuntime.main_thread) {
+ if (PyThread_get_thread_ident() != runtime->main_thread) {
return 0;
}
/*
* Ensure that the thread isn't currently running some other
* interpreter.
*/
- if (_PyInterpreterState_GET_UNSAFE() != _PyRuntime.interpreters.main) {
+ PyInterpreterState *interp = _PyRuntimeState_GetThreadState(runtime)->interp;
+ if (interp != runtime->interpreters.main) {
return 0;
}
- UNSIGNAL_PENDING_SIGNALS();
+ struct _ceval_runtime_state *ceval = &runtime->ceval;
+ UNSIGNAL_PENDING_SIGNALS(ceval);
if (_PyErr_CheckSignals() < 0) {
- SIGNAL_PENDING_SIGNALS(); /* We're not done yet */
+ SIGNAL_PENDING_SIGNALS(ceval); /* We're not done yet */
return -1;
}
return 0;
}
static int
-make_pending_calls(struct _pending_calls* pending)
+make_pending_calls(_PyRuntimeState *runtime)
{
static int busy = 0;
/* only service pending calls on main thread */
- if (PyThread_get_thread_ident() != _PyRuntime.main_thread) {
+ if (PyThread_get_thread_ident() != runtime->main_thread) {
return 0;
}
@@ -451,12 +495,14 @@ make_pending_calls(struct _pending_calls* pending)
return 0;
}
busy = 1;
+ struct _ceval_runtime_state *ceval = &runtime->ceval;
/* unsignal before starting to call callbacks, so that any callback
added in-between re-signals */
- UNSIGNAL_PENDING_CALLS();
+ UNSIGNAL_PENDING_CALLS(ceval);
int res = 0;
/* perform a bounded number of calls, in case of recursion */
+ struct _pending_calls *pending = &ceval->pending;
for (int i=0; iceval.pending;
+
PyThread_acquire_lock(pending->lock, WAIT_LOCK);
pending->finishing = 1;
PyThread_release_lock(pending->lock);
@@ -500,7 +546,7 @@ _Py_FinishPendingCalls(void)
return;
}
- if (make_pending_calls(pending) < 0) {
+ if (make_pending_calls(runtime) < 0) {
PyObject *exc, *val, *tb;
PyErr_Fetch(&exc, &val, &tb);
PyErr_BadInternalCall();
@@ -518,12 +564,13 @@ Py_MakePendingCalls(void)
/* Python signal handler doesn't really queue a callback: it only signals
that a signal was received, see _PyEval_SignalReceived(). */
- int res = handle_signals();
+ _PyRuntimeState *runtime = &_PyRuntime;
+ int res = handle_signals(runtime);
if (res != 0) {
return res;
}
- res = make_pending_calls(&_PyRuntime.ceval.pending);
+ res = make_pending_calls(runtime);
if (res != 0) {
return res;
}
@@ -556,8 +603,9 @@ Py_GetRecursionLimit(void)
void
Py_SetRecursionLimit(int new_limit)
{
- _PyRuntime.ceval.recursion_limit = new_limit;
- _Py_CheckRecursionLimit = _PyRuntime.ceval.recursion_limit;
+ struct _ceval_runtime_state *ceval = &_PyRuntime.ceval;
+ ceval->recursion_limit = new_limit;
+ _Py_CheckRecursionLimit = ceval->recursion_limit;
}
/* the macro Py_EnterRecursiveCall() only calls _Py_CheckRecursiveCall()
@@ -568,8 +616,9 @@ Py_SetRecursionLimit(int new_limit)
int
_Py_CheckRecursiveCall(const char *where)
{
- PyThreadState *tstate = _PyThreadState_GET();
- int recursion_limit = _PyRuntime.ceval.recursion_limit;
+ _PyRuntimeState *runtime = &_PyRuntime;
+ PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
+ int recursion_limit = runtime->ceval.recursion_limit;
#ifdef USE_STACKCHECK
tstate->stackcheck_counter = 0;
@@ -602,10 +651,10 @@ _Py_CheckRecursiveCall(const char *where)
return 0;
}
-static int do_raise(PyObject *, PyObject *);
+static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause);
static int unpack_iterable(PyObject *, int, int, PyObject **);
-#define _Py_TracingPossible _PyRuntime.ceval.tracing_possible
+#define _Py_TracingPossible(ceval) ((ceval)->tracing_possible)
PyObject *
@@ -649,8 +698,10 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
int oparg; /* Current opcode argument, if any */
PyObject **fastlocals, **freevars;
PyObject *retval = NULL; /* Return value */
- PyThreadState *tstate = _PyThreadState_GET();
- _Py_atomic_int *eval_breaker = &_PyRuntime.ceval.eval_breaker;
+ _PyRuntimeState * const runtime = &_PyRuntime;
+ PyThreadState * const tstate = _PyRuntimeState_GetThreadState(runtime);
+ struct _ceval_runtime_state * const ceval = &runtime->ceval;
+ _Py_atomic_int * const eval_breaker = &ceval->eval_breaker;
PyCodeObject *co;
/* when tracing we set things up so that
@@ -734,18 +785,10 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
op: \
TARGET_##op
-#define DISPATCH() \
- { \
- if (!_Py_atomic_load_relaxed(eval_breaker)) { \
- FAST_DISPATCH(); \
- } \
- continue; \
- }
-
#ifdef LLTRACE
#define FAST_DISPATCH() \
{ \
- if (!lltrace && !_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
+ if (!lltrace && !_Py_TracingPossible(ceval) && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
NEXTOPARG(); \
goto *opcode_targets[opcode]; \
@@ -755,7 +798,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
#else
#define FAST_DISPATCH() \
{ \
- if (!_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
+ if (!_Py_TracingPossible(ceval) && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
NEXTOPARG(); \
goto *opcode_targets[opcode]; \
@@ -764,11 +807,18 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
}
#endif
+#define DISPATCH() \
+ { \
+ if (!_Py_atomic_load_relaxed(eval_breaker)) { \
+ FAST_DISPATCH(); \
+ } \
+ continue; \
+ }
+
#else
#define TARGET(op) op
-
-#define DISPATCH() continue
#define FAST_DISPATCH() goto fast_next_opcode
+#define DISPATCH() continue
#endif
@@ -1063,44 +1113,40 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
goto fast_next_opcode;
}
- if (_Py_atomic_load_relaxed(
- &_PyRuntime.ceval.signals_pending))
- {
- if (handle_signals() != 0) {
+ if (_Py_atomic_load_relaxed(&ceval->signals_pending)) {
+ if (handle_signals(runtime) != 0) {
goto error;
}
}
- if (_Py_atomic_load_relaxed(
- &_PyRuntime.ceval.pending.calls_to_do))
- {
- if (make_pending_calls(&_PyRuntime.ceval.pending) != 0) {
+ if (_Py_atomic_load_relaxed(&ceval->pending.calls_to_do)) {
+ if (make_pending_calls(runtime) != 0) {
goto error;
}
}
- if (_Py_atomic_load_relaxed(
- &_PyRuntime.ceval.gil_drop_request))
- {
+ if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) {
/* Give another thread a chance */
- if (PyThreadState_Swap(NULL) != tstate)
+ if (_PyThreadState_Swap(&runtime->gilstate, NULL) != tstate) {
Py_FatalError("ceval: tstate mix-up");
- drop_gil(tstate);
+ }
+ drop_gil(ceval, tstate);
/* Other threads may run now */
- take_gil(tstate);
+ take_gil(ceval, tstate);
/* Check if we should make a quick exit. */
- exit_thread_if_finalizing(tstate);
+ exit_thread_if_finalizing(runtime, tstate);
- if (PyThreadState_Swap(tstate) != NULL)
+ if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) {
Py_FatalError("ceval: orphan tstate");
+ }
}
/* Check for asynchronous exceptions. */
if (tstate->async_exc != NULL) {
PyObject *exc = tstate->async_exc;
tstate->async_exc = NULL;
- UNSIGNAL_ASYNC_EXC();
+ UNSIGNAL_ASYNC_EXC(ceval);
PyErr_SetNone(exc);
Py_DECREF(exc);
goto error;
@@ -1115,7 +1161,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
/* line-by-line tracing support */
- if (_Py_TracingPossible &&
+ if (_Py_TracingPossible(ceval) &&
tstate->c_tracefunc != NULL && !tstate->tracing) {
int err;
/* see maybe_call_line_trace
@@ -1740,7 +1786,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
exc = POP(); /* exc */
/* fall through */
case 0:
- if (do_raise(exc, cause)) {
+ if (do_raise(tstate, exc, cause)) {
goto exception_unwind;
}
break;
@@ -3268,7 +3314,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
`callable` will be POPed by call_function.
NULL will will be POPed manually later.
*/
- res = call_function(&sp, oparg, NULL);
+ res = call_function(tstate, &sp, oparg, NULL);
stack_pointer = sp;
(void)POP(); /* POP the NULL. */
}
@@ -3285,7 +3331,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
We'll be passing `oparg + 1` to call_function, to
make it accept the `self` as a first argument.
*/
- res = call_function(&sp, oparg + 1, NULL);
+ res = call_function(tstate, &sp, oparg + 1, NULL);
stack_pointer = sp;
}
@@ -3299,7 +3345,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
PREDICTED(CALL_FUNCTION);
PyObject **sp, *res;
sp = stack_pointer;
- res = call_function(&sp, oparg, NULL);
+ res = call_function(tstate, &sp, oparg, NULL);
stack_pointer = sp;
PUSH(res);
if (res == NULL) {
@@ -3314,7 +3360,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
names = POP();
assert(PyTuple_CheckExact(names) && PyTuple_GET_SIZE(names) <= oparg);
sp = stack_pointer;
- res = call_function(&sp, oparg, names);
+ res = call_function(tstate, &sp, oparg, names);
stack_pointer = sp;
PUSH(res);
Py_DECREF(names);
@@ -3358,7 +3404,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
}
assert(PyTuple_CheckExact(callargs));
- result = do_call_core(func, callargs, kwargs);
+ result = do_call_core(tstate, func, callargs, kwargs);
Py_DECREF(func);
Py_DECREF(callargs);
Py_XDECREF(kwargs);
@@ -3855,7 +3901,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
PyFrameObject *f;
PyObject *retval = NULL;
PyObject **fastlocals, **freevars;
- PyThreadState *tstate;
PyObject *x, *u;
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount + co->co_posonlyargcount;
Py_ssize_t i, j, n;
@@ -3868,7 +3913,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
}
/* Create the frame */
- tstate = _PyThreadState_GET();
+ PyThreadState *tstate = _PyThreadState_GET();
assert(tstate != NULL);
f = _PyFrame_New_NoTrack(tstate, co, globals, locals);
if (f == NULL) {
@@ -4180,13 +4225,12 @@ special_lookup(PyObject *o, _Py_Identifier *id)
/* Logic for the raise statement (too complicated for inlining).
This *consumes* a reference count to each of its arguments. */
static int
-do_raise(PyObject *exc, PyObject *cause)
+do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause)
{
PyObject *type = NULL, *value = NULL;
if (exc == NULL) {
/* Reraise */
- PyThreadState *tstate = _PyThreadState_GET();
_PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate);
PyObject *tb;
type = exc_info->exc_type;
@@ -4529,9 +4573,10 @@ PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
void
PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
{
- PyThreadState *tstate = _PyThreadState_GET();
+ _PyRuntimeState *runtime = &_PyRuntime;
+ PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
PyObject *temp = tstate->c_traceobj;
- _Py_TracingPossible += (func != NULL) - (tstate->c_tracefunc != NULL);
+ runtime->ceval.tracing_possible += (func != NULL) - (tstate->c_tracefunc != NULL);
Py_XINCREF(arg);
tstate->c_tracefunc = NULL;
tstate->c_traceobj = NULL;
@@ -4564,7 +4609,6 @@ void
_PyEval_SetCoroutineWrapper(PyObject *wrapper)
{
PyThreadState *tstate = _PyThreadState_GET();
-
Py_XINCREF(wrapper);
Py_XSETREF(tstate->coroutine_wrapper, wrapper);
}
@@ -4580,7 +4624,6 @@ void
_PyEval_SetAsyncGenFirstiter(PyObject *firstiter)
{
PyThreadState *tstate = _PyThreadState_GET();
-
Py_XINCREF(firstiter);
Py_XSETREF(tstate->async_gen_firstiter, firstiter);
}
@@ -4596,7 +4639,6 @@ void
_PyEval_SetAsyncGenFinalizer(PyObject *finalizer)
{
PyThreadState *tstate = _PyThreadState_GET();
-
Py_XINCREF(finalizer);
Py_XSETREF(tstate->async_gen_finalizer, finalizer);
}
@@ -4662,8 +4704,9 @@ PyEval_GetGlobals(void)
PyFrameObject *
PyEval_GetFrame(void)
{
- PyThreadState *tstate = _PyThreadState_GET();
- return _PyThreadState_GetFrame(tstate);
+ _PyRuntimeState *runtime = &_PyRuntime;
+ PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
+ return runtime->gilstate.getframe(tstate);
}
int
@@ -4750,7 +4793,7 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \
/* Issue #29227: Inline call_function() into _PyEval_EvalFrameDefault()
to reduce the stack consumption. */
Py_LOCAL_INLINE(PyObject *) _Py_HOT_FUNCTION
-call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
+call_function(PyThreadState *tstate, PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
{
PyObject **pfunc = (*pp_stack) - oparg - 1;
PyObject *func = *pfunc;
@@ -4763,11 +4806,9 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
presumed to be the most frequent callable object.
*/
if (PyCFunction_Check(func)) {
- PyThreadState *tstate = _PyThreadState_GET();
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
}
else if (Py_TYPE(func) == &PyMethodDescr_Type) {
- PyThreadState *tstate = _PyThreadState_GET();
if (nargs > 0 && tstate->use_tracing) {
/* We need to create a temporary bound method as argument
for profiling.
@@ -4832,17 +4873,15 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
}
static PyObject *
-do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
+do_call_core(PyThreadState *tstate, PyObject *func, PyObject *callargs, PyObject *kwdict)
{
PyObject *result;
if (PyCFunction_Check(func)) {
- PyThreadState *tstate = _PyThreadState_GET();
C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
return result;
}
else if (Py_TYPE(func) == &PyMethodDescr_Type) {
- PyThreadState *tstate = _PyThreadState_GET();
Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
if (nargs > 0 && tstate->use_tracing) {
/* We need to create a temporary bound method as argument
diff --git a/Python/ceval_gil.h b/Python/ceval_gil.h
index f2d5fdba015..34d48c990c4 100644
--- a/Python/ceval_gil.h
+++ b/Python/ceval_gil.h
@@ -7,10 +7,6 @@
#include "pycore_atomic.h"
-/* First some general settings */
-
-#define INTERVAL (_PyRuntime.ceval.gil.interval >= 1 ? _PyRuntime.ceval.gil.interval : 1)
-
/*
Notes about the implementation:
@@ -94,158 +90,156 @@
#define DEFAULT_INTERVAL 5000
-static void _gil_initialize(struct _gil_runtime_state *state)
+static void _gil_initialize(struct _gil_runtime_state *gil)
{
_Py_atomic_int uninitialized = {-1};
- state->locked = uninitialized;
- state->interval = DEFAULT_INTERVAL;
+ gil->locked = uninitialized;
+ gil->interval = DEFAULT_INTERVAL;
}
-static int gil_created(void)
+static int gil_created(struct _gil_runtime_state *gil)
{
- return (_Py_atomic_load_explicit(&_PyRuntime.ceval.gil.locked,
- _Py_memory_order_acquire)
- ) >= 0;
+ return (_Py_atomic_load_explicit(&gil->locked, _Py_memory_order_acquire) >= 0);
}
-static void create_gil(void)
+static void create_gil(struct _gil_runtime_state *gil)
{
- MUTEX_INIT(_PyRuntime.ceval.gil.mutex);
+ MUTEX_INIT(gil->mutex);
#ifdef FORCE_SWITCHING
- MUTEX_INIT(_PyRuntime.ceval.gil.switch_mutex);
+ MUTEX_INIT(gil->switch_mutex);
#endif
- COND_INIT(_PyRuntime.ceval.gil.cond);
+ COND_INIT(gil->cond);
#ifdef FORCE_SWITCHING
- COND_INIT(_PyRuntime.ceval.gil.switch_cond);
+ COND_INIT(gil->switch_cond);
#endif
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.last_holder, 0);
- _Py_ANNOTATE_RWLOCK_CREATE(&_PyRuntime.ceval.gil.locked);
- _Py_atomic_store_explicit(&_PyRuntime.ceval.gil.locked, 0,
- _Py_memory_order_release);
+ _Py_atomic_store_relaxed(&gil->last_holder, 0);
+ _Py_ANNOTATE_RWLOCK_CREATE(&gil->locked);
+ _Py_atomic_store_explicit(&gil->locked, 0, _Py_memory_order_release);
}
-static void destroy_gil(void)
+static void destroy_gil(struct _gil_runtime_state *gil)
{
/* some pthread-like implementations tie the mutex to the cond
* and must have the cond destroyed first.
*/
- COND_FINI(_PyRuntime.ceval.gil.cond);
- MUTEX_FINI(_PyRuntime.ceval.gil.mutex);
+ COND_FINI(gil->cond);
+ MUTEX_FINI(gil->mutex);
#ifdef FORCE_SWITCHING
- COND_FINI(_PyRuntime.ceval.gil.switch_cond);
- MUTEX_FINI(_PyRuntime.ceval.gil.switch_mutex);
+ COND_FINI(gil->switch_cond);
+ MUTEX_FINI(gil->switch_mutex);
#endif
- _Py_atomic_store_explicit(&_PyRuntime.ceval.gil.locked, -1,
+ _Py_atomic_store_explicit(&gil->locked, -1,
_Py_memory_order_release);
- _Py_ANNOTATE_RWLOCK_DESTROY(&_PyRuntime.ceval.gil.locked);
+ _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked);
}
-static void recreate_gil(void)
+static void recreate_gil(struct _gil_runtime_state *gil)
{
- _Py_ANNOTATE_RWLOCK_DESTROY(&_PyRuntime.ceval.gil.locked);
+ _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked);
/* XXX should we destroy the old OS resources here? */
- create_gil();
+ create_gil(gil);
}
-static void drop_gil(PyThreadState *tstate)
+static void
+drop_gil(struct _ceval_runtime_state *ceval, PyThreadState *tstate)
{
- if (!_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked))
+ struct _gil_runtime_state *gil = &ceval->gil;
+ if (!_Py_atomic_load_relaxed(&gil->locked)) {
Py_FatalError("drop_gil: GIL is not locked");
+ }
+
/* tstate is allowed to be NULL (early interpreter init) */
if (tstate != NULL) {
/* Sub-interpreter support: threads might have been switched
under our feet using PyThreadState_Swap(). Fix the GIL last
holder variable so that our heuristics work. */
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.last_holder,
- (uintptr_t)tstate);
+ _Py_atomic_store_relaxed(&gil->last_holder, (uintptr_t)tstate);
}
- MUTEX_LOCK(_PyRuntime.ceval.gil.mutex);
- _Py_ANNOTATE_RWLOCK_RELEASED(&_PyRuntime.ceval.gil.locked, /*is_write=*/1);
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.locked, 0);
- COND_SIGNAL(_PyRuntime.ceval.gil.cond);
- MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex);
+ MUTEX_LOCK(gil->mutex);
+ _Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1);
+ _Py_atomic_store_relaxed(&gil->locked, 0);
+ COND_SIGNAL(gil->cond);
+ MUTEX_UNLOCK(gil->mutex);
#ifdef FORCE_SWITCHING
- if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request) &&
- tstate != NULL)
- {
- MUTEX_LOCK(_PyRuntime.ceval.gil.switch_mutex);
+ if (_Py_atomic_load_relaxed(&ceval->gil_drop_request) && tstate != NULL) {
+ MUTEX_LOCK(gil->switch_mutex);
/* Not switched yet => wait */
- if (((PyThreadState*)_Py_atomic_load_relaxed(
- &_PyRuntime.ceval.gil.last_holder)
- ) == tstate)
+ if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate)
{
- RESET_GIL_DROP_REQUEST();
+ RESET_GIL_DROP_REQUEST(ceval);
/* NOTE: if COND_WAIT does not atomically start waiting when
releasing the mutex, another thread can run through, take
the GIL and drop it again, and reset the condition
before we even had a chance to wait for it. */
- COND_WAIT(_PyRuntime.ceval.gil.switch_cond,
- _PyRuntime.ceval.gil.switch_mutex);
- }
- MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex);
+ COND_WAIT(gil->switch_cond, gil->switch_mutex);
+ }
+ MUTEX_UNLOCK(gil->switch_mutex);
}
#endif
}
-static void take_gil(PyThreadState *tstate)
+static void
+take_gil(struct _ceval_runtime_state *ceval, PyThreadState *tstate)
{
- int err;
- if (tstate == NULL)
+ if (tstate == NULL) {
Py_FatalError("take_gil: NULL tstate");
+ }
- err = errno;
- MUTEX_LOCK(_PyRuntime.ceval.gil.mutex);
+ struct _gil_runtime_state *gil = &ceval->gil;
+ int err = errno;
+ MUTEX_LOCK(gil->mutex);
- if (!_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked))
+ if (!_Py_atomic_load_relaxed(&gil->locked)) {
goto _ready;
+ }
- while (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked)) {
+ while (_Py_atomic_load_relaxed(&gil->locked)) {
int timed_out = 0;
unsigned long saved_switchnum;
- saved_switchnum = _PyRuntime.ceval.gil.switch_number;
- COND_TIMED_WAIT(_PyRuntime.ceval.gil.cond, _PyRuntime.ceval.gil.mutex,
- INTERVAL, timed_out);
+ saved_switchnum = gil->switch_number;
+
+
+ unsigned long interval = (gil->interval >= 1 ? gil->interval : 1);
+ COND_TIMED_WAIT(gil->cond, gil->mutex, interval, timed_out);
/* If we timed out and no switch occurred in the meantime, it is time
to ask the GIL-holding thread to drop it. */
if (timed_out &&
- _Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked) &&
- _PyRuntime.ceval.gil.switch_number == saved_switchnum) {
- SET_GIL_DROP_REQUEST();
+ _Py_atomic_load_relaxed(&gil->locked) &&
+ gil->switch_number == saved_switchnum)
+ {
+ SET_GIL_DROP_REQUEST(ceval);
}
}
_ready:
#ifdef FORCE_SWITCHING
- /* This mutex must be taken before modifying
- _PyRuntime.ceval.gil.last_holder (see drop_gil()). */
- MUTEX_LOCK(_PyRuntime.ceval.gil.switch_mutex);
+ /* This mutex must be taken before modifying gil->last_holder:
+ see drop_gil(). */
+ MUTEX_LOCK(gil->switch_mutex);
#endif
/* We now hold the GIL */
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.locked, 1);
- _Py_ANNOTATE_RWLOCK_ACQUIRED(&_PyRuntime.ceval.gil.locked, /*is_write=*/1);
+ _Py_atomic_store_relaxed(&gil->locked, 1);
+ _Py_ANNOTATE_RWLOCK_ACQUIRED(&gil->locked, /*is_write=*/1);
- if (tstate != (PyThreadState*)_Py_atomic_load_relaxed(
- &_PyRuntime.ceval.gil.last_holder))
- {
- _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.last_holder,
- (uintptr_t)tstate);
- ++_PyRuntime.ceval.gil.switch_number;
+ if (tstate != (PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) {
+ _Py_atomic_store_relaxed(&gil->last_holder, (uintptr_t)tstate);
+ ++gil->switch_number;
}
#ifdef FORCE_SWITCHING
- COND_SIGNAL(_PyRuntime.ceval.gil.switch_cond);
- MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex);
+ COND_SIGNAL(gil->switch_cond);
+ MUTEX_UNLOCK(gil->switch_mutex);
#endif
- if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request)) {
- RESET_GIL_DROP_REQUEST();
+ if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) {
+ RESET_GIL_DROP_REQUEST(ceval);
}
if (tstate->async_exc != NULL) {
- _PyEval_SignalAsyncExc();
+ _PyEval_SignalAsyncExc(ceval);
}
- MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex);
+ MUTEX_UNLOCK(gil->mutex);
errno = err;
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 32902aa0d59..de8595ccb58 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -4,8 +4,9 @@
#include "Python-ast.h"
#undef Yield /* undefine macro conflicting with */
-#include "pycore_coreconfig.h"
+#include "pycore_ceval.h"
#include "pycore_context.h"
+#include "pycore_coreconfig.h"
#include "pycore_fileutils.h"
#include "pycore_hamt.h"
#include "pycore_pathconfig.h"
@@ -527,7 +528,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
another running thread (see issue #9901).
Instead we destroy the previously created GIL here, which ensures
that we can call Py_Initialize / Py_FinalizeEx multiple times. */
- _PyEval_FiniThreads();
+ _PyEval_FiniThreads(&runtime->ceval);
/* Auto-thread-state API */
_PyGILState_Init(runtime, interp, tstate);
@@ -1135,10 +1136,10 @@ Py_FinalizeEx(void)
wait_for_thread_shutdown();
// Make any remaining pending calls.
- _Py_FinishPendingCalls();
+ _Py_FinishPendingCalls(runtime);
/* Get current thread state and interpreter pointer */
- PyThreadState *tstate = _PyThreadState_GET();
+ PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
PyInterpreterState *interp = tstate->interp;
/* The interpreter is still entirely intact at this point, and the
diff --git a/Python/pystate.c b/Python/pystate.c
index 44acfed6b98..67315756ab7 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -2,6 +2,7 @@
/* Thread and interpreter state structures and their interfaces */
#include "Python.h"
+#include "pycore_ceval.h"
#include "pycore_coreconfig.h"
#include "pycore_pymem.h"
#include "pycore_pystate.h"
@@ -39,7 +40,6 @@ extern "C" {
/* Forward declarations */
static PyThreadState *_PyGILState_GetThisThreadState(struct _gilstate_runtime_state *gilstate);
static void _PyThreadState_Delete(_PyRuntimeState *runtime, PyThreadState *tstate);
-static PyThreadState *_PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *newts);
static _PyInitError
@@ -867,9 +867,8 @@ PyThreadState_DeleteCurrent()
* be kept in those other interpreteres.
*/
void
-_PyThreadState_DeleteExcept(PyThreadState *tstate)
+_PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate)
{
- _PyRuntimeState *runtime = &_PyRuntime;
PyInterpreterState *interp = tstate->interp;
PyThreadState *p, *next, *garbage;
HEAD_LOCK(runtime);
@@ -915,7 +914,7 @@ PyThreadState_Get(void)
}
-static PyThreadState *
+PyThreadState *
_PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *newts)
{
PyThreadState *oldts = _PyRuntimeGILState_GetThreadState(gilstate);
@@ -980,8 +979,8 @@ PyThreadState_GetDict(void)
int
PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
{
- PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
- PyThreadState *p;
+ _PyRuntimeState *runtime = &_PyRuntime;
+ PyInterpreterState *interp = _PyRuntimeState_GetThreadState(runtime)->interp;
/* Although the GIL is held, a few C API functions can be called
* without the GIL held, and in particular some that create and
@@ -989,9 +988,8 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
* list of thread states we're traversing, so to prevent that we lock
* head_mutex for the duration.
*/
- _PyRuntimeState *runtime = &_PyRuntime;
HEAD_LOCK(runtime);
- for (p = interp->tstate_head; p != NULL; p = p->next) {
+ for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) {
if (p->thread_id == id) {
/* Tricky: we need to decref the current value
* (if any) in p->async_exc, but that can in turn
@@ -1005,7 +1003,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
p->async_exc = exc;
HEAD_UNLOCK(runtime);
Py_XDECREF(old_exc);
- _PyEval_SignalAsyncExc();
+ _PyEval_SignalAsyncExc(&runtime->ceval);
return 1;
}
}
From 960bb883769e5c64a63b014590d75654db87ffb0 Mon Sep 17 00:00:00 2001
From: Pablo Galindo
Date: Fri, 10 May 2019 22:58:17 +0100
Subject: [PATCH 006/199] Fix sphinx deprecation warning about
env.note_versionchange() (GH-13236)
---
Doc/tools/extensions/pyspecific.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py
index 66317430881..e097c13eab5 100644
--- a/Doc/tools/extensions/pyspecific.py
+++ b/Doc/tools/extensions/pyspecific.py
@@ -271,7 +271,7 @@ def run(self):
translatable=False)
node.append(para)
env = self.state.document.settings.env
- env.note_versionchange('deprecated', version[0], node, self.lineno)
+ env.get_domain('changeset').note_changeset(node)
return [node] + messages
From 4ebcd7e2980d650c711d21b93447af39a8604554 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Sat, 11 May 2019 04:10:03 +0200
Subject: [PATCH 007/199] bpo-21536: Update What's New in Python 3.8 entry
(GH-13242)
Android still links to libpython.
---
Doc/whatsnew/3.8.rst | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 6bb03422c6b..58b23211cc6 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -138,7 +138,8 @@ environment variable, can be set using the new ``./configure --with-trace-refs``
build option.
(Contributed by Victor Stinner in :issue:`36465`.)
-On Unix, C extensions are no longer linked to libpython. It is now possible
+On Unix, C extensions are no longer linked to libpython except on Android.
+It is now possible
for a statically linked Python to load a C extension built using a shared
library Python.
(Contributed by Victor Stinner in :issue:`21536`.)
From f6e17ddffd3ba52a08e977bd9c6c0d6f2fffa905 Mon Sep 17 00:00:00 2001
From: Aurelio Jargas
Date: Sat, 11 May 2019 04:51:45 +0200
Subject: [PATCH 008/199] Hide module name from local (anchor) links in shutil
docs (GH-6695)
---
Doc/library/shutil.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst
index 2dc872fd077..4af5a168060 100644
--- a/Doc/library/shutil.rst
+++ b/Doc/library/shutil.rst
@@ -54,7 +54,7 @@ Directory and files operations
*dst* and return *dst* in the most efficient way possible.
*src* and *dst* are path names given as strings.
- *dst* must be the complete target file name; look at :func:`shutil.copy`
+ *dst* must be the complete target file name; look at :func:`~shutil.copy`
for a copy that accepts a target directory path. If *src* and *dst*
specify the same file, :exc:`SameFileError` is raised.
@@ -218,7 +218,7 @@ Directory and files operations
already exists.
Permissions and times of directories are copied with :func:`copystat`,
- individual files are copied using :func:`shutil.copy2`.
+ individual files are copied using :func:`~shutil.copy2`.
If *symlinks* is true, symbolic links in the source tree are represented as
symbolic links in the new tree and the metadata of the original links will
@@ -246,8 +246,8 @@ Directory and files operations
If *copy_function* is given, it must be a callable that will be used to copy
each file. It will be called with the source path and the destination path
- as arguments. By default, :func:`shutil.copy2` is used, but any function
- that supports the same signature (like :func:`shutil.copy`) can be used.
+ Â as arguments. By default, :func:`~shutil.copy2` is used, but any function
+ Â that supports the same signature (like :func:`~shutil.copy`) can be used.
.. versionchanged:: 3.3
Copy metadata when *symlinks* is false.
From 79972f1fad5247ade34ef98ad987162a9a78401d Mon Sep 17 00:00:00 2001
From: Xtreak
Date: Sat, 11 May 2019 14:15:17 +0530
Subject: [PATCH 009/199] bpo-36884: Fix DeprecationWarning in test_asyncio
StreamReader instantiation (GH-13243)
https://bugs.python.org/issue36884
---
Lib/test/test_asyncio/test_pep492.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py
index 95ed7918586..558e268415c 100644
--- a/Lib/test/test_asyncio/test_pep492.py
+++ b/Lib/test/test_asyncio/test_pep492.py
@@ -94,7 +94,7 @@ class StreamReaderTests(BaseTest):
def test_readline(self):
DATA = b'line1\nline2\nline3'
- stream = asyncio.StreamReader(loop=self.loop)
+ stream = asyncio.StreamReader(loop=self.loop, _asyncio_internal=True)
stream.feed_data(DATA)
stream.feed_eof()
From 6236c9823ef3e8e2229b0598d3d8189adf5e00f2 Mon Sep 17 00:00:00 2001
From: Xi Ruoyao
Date: Sun, 12 May 2019 01:13:23 +0800
Subject: [PATCH 010/199] bpo-36856: Handle possible overflow in
faulthandler_stack_overflow (GH-13205)
---
Modules/faulthandler.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index d45b8660ee6..63a9b91ac46 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -1121,13 +1121,26 @@ faulthandler_stack_overflow(PyObject *self, PyObject *Py_UNUSED(ignored))
{
size_t depth, size;
uintptr_t sp = (uintptr_t)&depth;
- uintptr_t stop;
+ uintptr_t stop, lower_limit, upper_limit;
faulthandler_suppress_crash_report();
depth = 0;
- stop = stack_overflow(sp - STACK_OVERFLOW_MAX_SIZE,
- sp + STACK_OVERFLOW_MAX_SIZE,
- &depth);
+
+ if (STACK_OVERFLOW_MAX_SIZE <= sp) {
+ lower_limit = sp - STACK_OVERFLOW_MAX_SIZE;
+ }
+ else {
+ lower_limit = 0;
+ }
+
+ if (UINTPTR_MAX - STACK_OVERFLOW_MAX_SIZE >= sp) {
+ upper_limit = sp + STACK_OVERFLOW_MAX_SIZE;
+ }
+ else {
+ upper_limit = UINTPTR_MAX;
+ }
+
+ stop = stack_overflow(lower_limit, upper_limit, &depth);
if (sp < stop)
size = stop - sp;
else
From d8320ecb86da8df7c13d8bf8582507f736aa2924 Mon Sep 17 00:00:00 2001
From: "Michael J. Sullivan"
Date: Sat, 11 May 2019 11:17:24 -0700
Subject: [PATCH 011/199] bpo-36878: Allow extra text after `# type: ignore`
comments (GH-13238)
In the parser, when using the type_comments=True option, recognize
a TYPE_IGNORE as anything containing `# type: ignore` followed by
a non-alphanumeric character. This is to allow ignores such as
`# type: ignore[E1000]`.
---
Lib/test/test_type_comments.py | 9 ++++++++-
.../2019-05-10-22-00-06.bpo-36878.iigeqk.rst | 4 ++++
Parser/tokenizer.c | 13 +++++--------
3 files changed, 17 insertions(+), 9 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-10-22-00-06.bpo-36878.iigeqk.rst
diff --git a/Lib/test/test_type_comments.py b/Lib/test/test_type_comments.py
index 69a48a10403..b4318902ee3 100644
--- a/Lib/test/test_type_comments.py
+++ b/Lib/test/test_type_comments.py
@@ -76,6 +76,12 @@ def foo():
def bar():
x = 1 # type: ignore
+
+def baz():
+ pass # type: ignore[excuse]
+ pass # type: ignore=excuse
+ pass # type: ignore [excuse]
+ x = 1 # type: ignore whatever
"""
# Test for long-form type-comments in arguments. A test function
@@ -266,7 +272,7 @@ def test_vardecl(self):
def test_ignores(self):
for tree in self.parse_all(ignores):
- self.assertEqual([ti.lineno for ti in tree.type_ignores], [2, 5])
+ self.assertEqual([ti.lineno for ti in tree.type_ignores], [2, 5, 8, 9, 10, 11])
tree = self.classic_parse(ignores)
self.assertEqual(tree.type_ignores, [])
@@ -318,6 +324,7 @@ def check_both_ways(source):
check_both_ways("while True:\n continue # type: int\n")
check_both_ways("try: # type: int\n pass\nfinally:\n pass\n")
check_both_ways("try:\n pass\nfinally: # type: int\n pass\n")
+ check_both_ways("pass # type: ignorewhatever\n")
def test_func_type_input(self):
diff --git a/Misc/NEWS.d/next/Library/2019-05-10-22-00-06.bpo-36878.iigeqk.rst b/Misc/NEWS.d/next/Library/2019-05-10-22-00-06.bpo-36878.iigeqk.rst
new file mode 100644
index 00000000000..20b44dcbf13
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-10-22-00-06.bpo-36878.iigeqk.rst
@@ -0,0 +1,4 @@
+When using `type_comments=True` in `ast.parse`, treat `# type: ignore` followed by
+a non-alphanumeric character and then arbitrary text as a type ignore, instead of
+requiring nothing but whitespace or another comment. This is to permit formations
+such as `# type: ignore[E1000]`.
\ No newline at end of file
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index e8068f26807..5dc2ae65c42 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -1272,14 +1272,11 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
type_start = p;
- is_type_ignore = tok->cur >= p + 6 && memcmp(p, "ignore", 6) == 0;
- p += 6;
- while (is_type_ignore && p < tok->cur) {
- if (*p == '#')
- break;
- is_type_ignore = is_type_ignore && (*p == ' ' || *p == '\t');
- p++;
- }
+ /* A TYPE_IGNORE is "type: ignore" followed by the end of the token
+ * or anything non-alphanumeric. */
+ is_type_ignore = (
+ tok->cur >= p + 6 && memcmp(p, "ignore", 6) == 0
+ && !(tok->cur > p + 6 && isalnum(p[6])));
if (is_type_ignore) {
/* If this type ignore is the only thing on the line, consume the newline also. */
From 90fb04c1e23c0fddd438bd0f73e7c018cacef4bc Mon Sep 17 00:00:00 2001
From: Sanyam Khurana <8039608+CuriousLearner@users.noreply.github.com>
Date: Sat, 11 May 2019 15:04:10 -0400
Subject: [PATCH 012/199] bpo-36822: Fix minor grammatical error in
glossary.rst (GH-13145)
---
Doc/glossary.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Doc/glossary.rst b/Doc/glossary.rst
index 5810a6b7997..9c64e488631 100644
--- a/Doc/glossary.rst
+++ b/Doc/glossary.rst
@@ -15,10 +15,10 @@ Glossary
``...``
Can refer to:
- * The default Python prompt of the interactive shell when entering code for
- an indented code block, when within a pair of matching left and right
- delimiters (parentheses, square brackets, curly braces or triple quotes),
- or after specifying a decorator.
+ * The default Python prompt of the interactive shell when entering the
+ code for an indented code block, when within a pair of matching left and
+ right delimiters (parentheses, square brackets, curly braces or triple
+ quotes), or after specifying a decorator.
* The :const:`Ellipsis` built-in constant.
From 5833e94d8615ea18b14e4830ecdb868aec81b378 Mon Sep 17 00:00:00 2001
From: Pablo Galindo
Date: Sat, 11 May 2019 20:54:37 +0100
Subject: [PATCH 013/199] bpo-36817: Fix reference leak for expr_text in
f-string = parsing (GH-13249)
---
Python/ast.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/Python/ast.c b/Python/ast.c
index 21abd7e88d8..585f8b3fba4 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -5228,10 +5228,15 @@ fstring_find_expr(const char **str, const char *end, int raw, int recurse_lvl,
}
if (equal_flag) {
- Py_ssize_t len = expr_text_end-expr_start;
+ Py_ssize_t len = expr_text_end - expr_start;
expr_text = PyUnicode_FromStringAndSize(expr_start, len);
- if (!expr_text)
+ if (!expr_text) {
goto error;
+ }
+ if (PyArena_AddPyObject(c->c_arena, expr_text) < 0) {
+ Py_DECREF(expr_text);
+ goto error;
+ }
}
/* Check for the format spec, if present. */
From 26f55c29f2316648939ad12a9d3730a2118da2ea Mon Sep 17 00:00:00 2001
From: Pablo Galindo
Date: Sun, 12 May 2019 01:43:04 +0100
Subject: [PATCH 014/199] bpo-36817: Do not decrement reference for expr_text
on fstring = parsing failure (GH-13256)
---
Lib/test/test_fstring.py | 2 ++
Python/ast.c | 1 -
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py
index a0fae50d172..3484fcecf1c 100644
--- a/Lib/test/test_fstring.py
+++ b/Lib/test/test_fstring.py
@@ -1148,6 +1148,8 @@ def __repr__(self):
self.assertEqual(f'{C()=:x}', 'C()=FORMAT-x')
self.assertEqual(f'{C()=!r:*^20}', 'C()=********REPR********')
+ self.assertRaises(SyntaxError, eval, "f'{C=]'")
+
def test_walrus(self):
x = 20
# This isn't an assignment expression, it's 'x', with a format
diff --git a/Python/ast.c b/Python/ast.c
index 585f8b3fba4..03da4e7f7f9 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -5283,7 +5283,6 @@ fstring_find_expr(const char **str, const char *end, int raw, int recurse_lvl,
/* Falls through to error. */
error:
- Py_XDECREF(expr_text);
return -1;
}
From 87068ed00927bdeaa2ae556e4241c16cf8a845eb Mon Sep 17 00:00:00 2001
From: "Gordon P. Hemsley"
Date: Sat, 11 May 2019 23:33:35 -0400
Subject: [PATCH 015/199] bpo-36684: Split out gcc and test coverage builds
(GH-13146)
The combined Python and C coverage test runs now exceed Travis's
50-minute time limit. Splitting them into separate runs gives more
leeway.
Also, adding branch coverage to Python testing and ensure that
coverage is reported even if tests fail. (The primary builds are
for tracking test failures.)
---
.travis.yml | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 6d57ebb1d2f..207649730c2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -86,22 +86,36 @@ matrix:
addons:
apt:
packages:
- - lcov
- xvfb
before_script:
- ./configure
- - make coverage -s -j4
+ - make -j4
# Need a venv that can parse covered code.
- ./python -m venv venv
- ./venv/bin/python -m pip install -U coverage
- ./venv/bin/python -m test.pythoninfo
script:
# Skip tests that re-run the entire test suite.
- - xvfb-run ./venv/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures
+ - xvfb-run ./venv/bin/python -m coverage run --branch --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures || true
after_script: # Probably should be after_success once test suite updated to run under coverage.py.
# Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files.
- source ./venv/bin/activate
- - make coverage-lcov
+ - bash <(curl -s https://codecov.io/bash)
+ - os: linux
+ language: c
+ compiler: gcc
+ env: OPTIONAL=true
+ addons:
+ apt:
+ packages:
+ - lcov
+ - xvfb
+ before_script:
+ - ./configure
+ script:
+ - xvfb-run make -j4 coverage-report
+ after_script: # Probably should be after_success once test suite updated to run under coverage.py.
+ - make pythoninfo
- bash <(curl -s https://codecov.io/bash)
From 4959c33d2555b89b494c678d99be81a65ee864b0 Mon Sep 17 00:00:00 2001
From: Jake Tesler
Date: Sun, 12 May 2019 10:08:24 -0700
Subject: [PATCH 016/199] bpo-36084: Add native thread ID to threading.Thread
objects (GH-11993)
---
Doc/library/_thread.rst | 12 +++++++
Doc/library/threading.rst | 31 +++++++++++++++++++
Include/pythread.h | 1 +
Lib/_dummy_thread.py | 4 +++
Lib/test/test_threading.py | 4 +++
Lib/threading.py | 23 ++++++++++++--
.../2019-02-22-23-03-20.bpo-36084.86Eh4X.rst | 1 +
Modules/_threadmodule.c | 16 ++++++++++
Python/thread_nt.h | 16 ++++++++++
Python/thread_pthread.h | 27 ++++++++++++++++
10 files changed, 133 insertions(+), 2 deletions(-)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-02-22-23-03-20.bpo-36084.86Eh4X.rst
diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst
index acffabf24ba..d7814f218b5 100644
--- a/Doc/library/_thread.rst
+++ b/Doc/library/_thread.rst
@@ -85,6 +85,18 @@ This module defines the following constants and functions:
may be recycled when a thread exits and another thread is created.
+.. function:: get_native_id()
+
+ Return the native integral Thread ID of the current thread assigned by the kernel.
+ This is a non-negative integer.
+ Its value may be used to uniquely identify this particular thread system-wide
+ (until the thread terminates, after which the value may be recycled by the OS).
+
+ .. availability:: Windows, FreeBSD, Linux, macOS.
+
+ .. versionadded:: 3.8
+
+
.. function:: stack_size([size])
Return the thread stack size used when creating new threads. The optional
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
index c58a6ad75d0..99dd7fff0d2 100644
--- a/Doc/library/threading.rst
+++ b/Doc/library/threading.rst
@@ -49,6 +49,18 @@ This module defines the following functions:
.. versionadded:: 3.3
+.. function:: get_native_id()
+
+ Return the native integral Thread ID of the current thread assigned by the kernel.
+ This is a non-negative integer.
+ Its value may be used to uniquely identify this particular thread system-wide
+ (until the thread terminates, after which the value may be recycled by the OS).
+
+ .. availability:: Windows, FreeBSD, Linux, macOS.
+
+ .. versionadded:: 3.8
+
+
.. function:: enumerate()
Return a list of all :class:`Thread` objects currently alive. The list
@@ -297,6 +309,25 @@ since it is impossible to detect the termination of alien threads.
another thread is created. The identifier is available even after the
thread has exited.
+ .. attribute:: native_id
+
+ The native integral thread ID of this thread or ``0`` if the thread has not
+ been started. This is a non-negative integer. See the
+ :func:`get_native_id` function.
+ This represents the Thread ID (``TID``) as assigned to the
+ thread by the OS (kernel). Its value may be used to uniquely identify
+ this particular thread system-wide.
+
+ .. note::
+
+ Similar to Process IDs, Thread IDs are only valid (guaranteed unique
+ system-wide) from the time the thread is created until the thread
+ has been terminated.
+
+ .. availability:: Windows, FreeBSD, Linux, macOS.
+
+ .. versionadded:: 3.8
+
.. method:: is_alive()
Return whether the thread is alive.
diff --git a/Include/pythread.h b/Include/pythread.h
index bc1d92cd1ff..e083383af80 100644
--- a/Include/pythread.h
+++ b/Include/pythread.h
@@ -25,6 +25,7 @@ PyAPI_FUNC(void) PyThread_init_thread(void);
PyAPI_FUNC(unsigned long) PyThread_start_new_thread(void (*)(void *), void *);
PyAPI_FUNC(void) _Py_NO_RETURN PyThread_exit_thread(void);
PyAPI_FUNC(unsigned long) PyThread_get_thread_ident(void);
+PyAPI_FUNC(unsigned long) PyThread_get_thread_native_id(void);
PyAPI_FUNC(PyThread_type_lock) PyThread_allocate_lock(void);
PyAPI_FUNC(void) PyThread_free_lock(PyThread_type_lock);
diff --git a/Lib/_dummy_thread.py b/Lib/_dummy_thread.py
index a2cae54b058..0a877e1fa16 100644
--- a/Lib/_dummy_thread.py
+++ b/Lib/_dummy_thread.py
@@ -71,6 +71,10 @@ def get_ident():
"""
return 1
+def get_native_id():
+ """Dummy implementation of _thread.get_native_id()."""
+ return 0
+
def allocate_lock():
"""Dummy implementation of _thread.allocate_lock()."""
return LockType()
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index 2ddc77b266b..6ac6e9de7a5 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -104,6 +104,10 @@ def test_various_ops(self):
self.assertRegex(repr(t), r'^$')
t.start()
+ native_ids = set(t.native_id for t in threads) | {threading.get_native_id()}
+ self.assertNotIn(None, native_ids)
+ self.assertEqual(len(native_ids), NUMTASKS + 1)
+
if verbose:
print('waiting for all tasks to complete')
for t in threads:
diff --git a/Lib/threading.py b/Lib/threading.py
index 0ebbd6776ef..3137e495b25 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -23,8 +23,8 @@
# with the multiprocessing module, which doesn't provide the old
# Java inspired names.
-__all__ = ['get_ident', 'active_count', 'Condition', 'current_thread',
- 'enumerate', 'main_thread', 'TIMEOUT_MAX',
+__all__ = ['get_ident', 'get_native_id', 'active_count', 'Condition',
+ 'current_thread', 'enumerate', 'main_thread', 'TIMEOUT_MAX',
'Event', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Thread',
'Barrier', 'BrokenBarrierError', 'Timer', 'ThreadError',
'setprofile', 'settrace', 'local', 'stack_size']
@@ -34,6 +34,7 @@
_allocate_lock = _thread.allocate_lock
_set_sentinel = _thread._set_sentinel
get_ident = _thread.get_ident
+get_native_id = _thread.get_native_id
ThreadError = _thread.error
try:
_CRLock = _thread.RLock
@@ -790,6 +791,7 @@ class is implemented.
else:
self._daemonic = current_thread().daemon
self._ident = None
+ self._native_id = 0
self._tstate_lock = None
self._started = Event()
self._is_stopped = False
@@ -891,6 +893,9 @@ def _bootstrap(self):
def _set_ident(self):
self._ident = get_ident()
+ def _set_native_id(self):
+ self._native_id = get_native_id()
+
def _set_tstate_lock(self):
"""
Set a lock object which will be released by the interpreter when
@@ -903,6 +908,7 @@ def _bootstrap_inner(self):
try:
self._set_ident()
self._set_tstate_lock()
+ self._set_native_id()
self._started.set()
with _active_limbo_lock:
_active[self._ident] = self
@@ -1077,6 +1083,17 @@ def ident(self):
assert self._initialized, "Thread.__init__() not called"
return self._ident
+ @property
+ def native_id(self):
+ """Native integral thread ID of this thread or 0 if it has not been started.
+
+ This is a non-negative integer. See the get_native_id() function.
+ This represents the Thread ID as reported by the kernel.
+
+ """
+ assert self._initialized, "Thread.__init__() not called"
+ return self._native_id
+
def is_alive(self):
"""Return whether the thread is alive.
@@ -1176,6 +1193,7 @@ def __init__(self):
self._set_tstate_lock()
self._started.set()
self._set_ident()
+ self._set_native_id()
with _active_limbo_lock:
_active[self._ident] = self
@@ -1195,6 +1213,7 @@ def __init__(self):
self._started.set()
self._set_ident()
+ self._set_native_id()
with _active_limbo_lock:
_active[self._ident] = self
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-02-22-23-03-20.bpo-36084.86Eh4X.rst b/Misc/NEWS.d/next/Core and Builtins/2019-02-22-23-03-20.bpo-36084.86Eh4X.rst
new file mode 100644
index 00000000000..4a612964de0
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-02-22-23-03-20.bpo-36084.86Eh4X.rst
@@ -0,0 +1 @@
+Add native thread ID (TID) to threading.Thread objects
\ No newline at end of file
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index 3c02d8dd514..a123cd0efd6 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -1159,6 +1159,20 @@ allocated consecutive numbers starting at 1, this behavior should not\n\
be relied upon, and the number should be seen purely as a magic cookie.\n\
A thread's identity may be reused for another thread after it exits.");
+static PyObject *
+thread_get_native_id(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ unsigned long native_id = PyThread_get_thread_native_id();
+ return PyLong_FromUnsignedLong(native_id);
+}
+
+PyDoc_STRVAR(get_native_id_doc,
+"get_native_id() -> integer\n\
+\n\
+Return a non-negative integer identifying the thread as reported\n\
+by the OS (kernel). This may be used to uniquely identify a\n\
+particular thread within a system.");
+
static PyObject *
thread__count(PyObject *self, PyObject *Py_UNUSED(ignored))
{
@@ -1310,6 +1324,8 @@ static PyMethodDef thread_methods[] = {
METH_NOARGS, interrupt_doc},
{"get_ident", thread_get_ident,
METH_NOARGS, get_ident_doc},
+ {"get_native_id", thread_get_native_id,
+ METH_NOARGS, get_native_id_doc},
{"_count", thread__count,
METH_NOARGS, _count_doc},
{"stack_size", (PyCFunction)thread_stack_size,
diff --git a/Python/thread_nt.h b/Python/thread_nt.h
index 5e00c351146..d3dc2bec6ff 100644
--- a/Python/thread_nt.h
+++ b/Python/thread_nt.h
@@ -143,6 +143,8 @@ LeaveNonRecursiveMutex(PNRMUTEX mutex)
unsigned long PyThread_get_thread_ident(void);
+unsigned long PyThread_get_thread_native_id(void);
+
/*
* Initialization of the C package, should not be needed.
*/
@@ -227,6 +229,20 @@ PyThread_get_thread_ident(void)
return GetCurrentThreadId();
}
+/*
+ * Return the native Thread ID (TID) of the calling thread.
+ * The native ID of a thread is valid and guaranteed to be unique system-wide
+ * from the time the thread is created until the thread has been terminated.
+ */
+unsigned long
+PyThread_get_thread_native_id(void)
+{
+ if (!initialized)
+ PyThread_init_thread();
+
+ return GetCurrentThreadId();
+}
+
void _Py_NO_RETURN
PyThread_exit_thread(void)
{
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h
index 4c106d9959c..87c98d3e93c 100644
--- a/Python/thread_pthread.h
+++ b/Python/thread_pthread.h
@@ -12,6 +12,12 @@
#endif
#include
+#if defined(__linux__)
+#include
+#elif defined(__FreeBSD__)
+#include
+#endif
+
/* The POSIX spec requires that use of pthread_attr_setstacksize
be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
@@ -302,6 +308,27 @@ PyThread_get_thread_ident(void)
return (unsigned long) threadid;
}
+unsigned long
+PyThread_get_thread_native_id(void)
+{
+ if (!initialized)
+ PyThread_init_thread();
+#ifdef __APPLE__
+ uint64_t native_id;
+ pthread_threadid_np(NULL, &native_id);
+#elif defined(__linux__)
+ pid_t native_id;
+ native_id = syscall(__NR_gettid);
+#elif defined(__FreeBSD__)
+ pid_t native_id;
+ native_id = pthread_getthreadid_np();
+#else
+ unsigned long native_id;
+ native_id = 0;
+#endif
+ return (unsigned long) native_id;
+}
+
void _Py_NO_RETURN
PyThread_exit_thread(void)
{
From 5d23e282af69d404a3430bb95aefe371112817b3 Mon Sep 17 00:00:00 2001
From: Pablo Galindo
Date: Sun, 12 May 2019 22:45:52 +0100
Subject: [PATCH 017/199] bpo-36886: Document changes in code object in What's
new section (GH-13255)
---
Doc/whatsnew/3.8.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 58b23211cc6..2cfb110b3d5 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -977,6 +977,10 @@ Changes in the Python API
replacement by a pure Python implementation. (Contributed by Pablo Galindo
in :issue:`36623`.)
+* :class:`types.CodeType` has a new parameter in the second position of the
+ constructor (*posonlyargcount*) to support positional-only arguments defined
+ in :pep:`570`.
+
Changes in the C API
--------------------
From e2500610c62673f42371b54fb0e4de83e4b33146 Mon Sep 17 00:00:00 2001
From: Matthias Bussonnier
Date: Sun, 12 May 2019 18:34:44 -0700
Subject: [PATCH 018/199] bpo-36895: remove time.clock() as per removal notice.
(GH-13270)
`time.clock()` was deprecated in 3.3, and marked for removal removal in
3.8; this thus remove it from the time module.
---
Doc/library/time.rst | 2 +-
Lib/test/test_time.py | 19 +------
.../2019-05-12-14-49-13.bpo-36895.ZZuuY7.rst | 2 +
Modules/timemodule.c | 50 -------------------
4 files changed, 4 insertions(+), 69 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-12-14-49-13.bpo-36895.ZZuuY7.rst
diff --git a/Doc/library/time.rst b/Doc/library/time.rst
index 170f8dc629b..cad4afda38b 100644
--- a/Doc/library/time.rst
+++ b/Doc/library/time.rst
@@ -155,7 +155,7 @@ Functions
.. availability:: Windows, Unix. Not available on VxWorks.
- .. deprecated:: 3.3
+ .. deprecated-removed:: 3.3 3.8
The behaviour of this function depends on the platform: use
:func:`perf_counter` or :func:`process_time` instead, depending on your
requirements, to have a well defined behaviour.
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
index 42799b2a21c..f790d43b6f4 100644
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -88,17 +88,6 @@ def check_ns(sec, ns):
check_ns(time.clock_gettime(time.CLOCK_REALTIME),
time.clock_gettime_ns(time.CLOCK_REALTIME))
- @unittest.skipUnless(hasattr(time, 'clock'),
- 'need time.clock()')
- def test_clock(self):
- with self.assertWarns(DeprecationWarning):
- time.clock()
-
- with self.assertWarns(DeprecationWarning):
- info = time.get_clock_info('clock')
- self.assertTrue(info.monotonic)
- self.assertFalse(info.adjustable)
-
@unittest.skipUnless(hasattr(time, 'clock_gettime'),
'need time.clock_gettime()')
def test_clock_realtime(self):
@@ -553,15 +542,9 @@ def test_localtime_failure(self):
def test_get_clock_info(self):
clocks = ['monotonic', 'perf_counter', 'process_time', 'time']
- if hasattr(time, 'clock'):
- clocks.append('clock')
for name in clocks:
- if name == 'clock':
- with self.assertWarns(DeprecationWarning):
- info = time.get_clock_info('clock')
- else:
- info = time.get_clock_info(name)
+ info = time.get_clock_info(name)
#self.assertIsInstance(info, dict)
self.assertIsInstance(info.implementation, str)
diff --git a/Misc/NEWS.d/next/Library/2019-05-12-14-49-13.bpo-36895.ZZuuY7.rst b/Misc/NEWS.d/next/Library/2019-05-12-14-49-13.bpo-36895.ZZuuY7.rst
new file mode 100644
index 00000000000..f6708abfc86
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-12-14-49-13.bpo-36895.ZZuuY7.rst
@@ -0,0 +1,2 @@
+The function ``time.clock()`` was deprecated in 3.3 in favor of
+``time.perf_counter()`` and marked for removal in 3.8, it has removed.
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index 3df17ac4fb6..f991f31ee15 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -145,44 +145,6 @@ perf_counter(_Py_clock_info_t *info)
return _PyFloat_FromPyTime(t);
}
-#if (defined(MS_WINDOWS) || defined(HAVE_CLOCK)) && !defined(__VXWORKS__)
-#define PYCLOCK
-static PyObject*
-pyclock(_Py_clock_info_t *info)
-{
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "time.clock has been deprecated in Python 3.3 and will "
- "be removed from Python 3.8: "
- "use time.perf_counter or time.process_time "
- "instead", 1) < 0) {
- return NULL;
- }
-
-#ifdef MS_WINDOWS
- return perf_counter(info);
-#else
- _PyTime_t t;
- if (_PyTime_GetClockWithInfo(&t, info) < 0) {
- return NULL;
- }
- return _PyFloat_FromPyTime(t);
-#endif
-}
-
-static PyObject *
-time_clock(PyObject *self, PyObject *unused)
-{
- return pyclock(NULL);
-}
-
-PyDoc_STRVAR(clock_doc,
-"clock() -> floating point number\n\
-\n\
-Return the CPU time or real time since the start of the process or since\n\
-the first call to clock(). This has as much precision as the system\n\
-records.");
-#endif
-
#ifdef HAVE_CLOCK_GETTIME
static PyObject *
time_clock_gettime(PyObject *self, PyObject *args)
@@ -1477,15 +1439,6 @@ time_get_clock_info(PyObject *self, PyObject *args)
return NULL;
}
}
-#ifdef PYCLOCK
- else if (strcmp(name, "clock") == 0) {
- obj = pyclock(&info);
- if (obj == NULL) {
- return NULL;
- }
- Py_DECREF(obj);
- }
-#endif
else if (strcmp(name, "monotonic") == 0) {
if (_PyTime_GetMonotonicClockWithInfo(&t, &info) < 0) {
return NULL;
@@ -1700,9 +1653,6 @@ init_timezone(PyObject *m)
static PyMethodDef time_methods[] = {
{"time", time_time, METH_NOARGS, time_doc},
{"time_ns", time_time_ns, METH_NOARGS, time_ns_doc},
-#ifdef PYCLOCK
- {"clock", time_clock, METH_NOARGS, clock_doc},
-#endif
#ifdef HAVE_CLOCK_GETTIME
{"clock_gettime", time_clock_gettime, METH_VARARGS, clock_gettime_doc},
{"clock_gettime_ns",time_clock_gettime_ns, METH_VARARGS, clock_gettime_ns_doc},
From 4ef9b8e5054d8bf9e1fcd4c3ba245a16265dc298 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johnny=20G=C3=A9rard?=
<36079566+johnnygerard@users.noreply.github.com>
Date: Mon, 13 May 2019 05:39:32 +0200
Subject: [PATCH 019/199] Correct misspelling (GH-11470)
---
Doc/reference/expressions.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst
index cf7d05eef67..79ba4568a54 100644
--- a/Doc/reference/expressions.rst
+++ b/Doc/reference/expressions.rst
@@ -196,7 +196,7 @@ the comprehension is executed in a separate implicitly nested scope. This ensure
that names assigned to in the target list don't "leak" into the enclosing scope.
The iterable expression in the leftmost :keyword:`!for` clause is evaluated
-directly in the enclosing scope and then passed as an argument to the implictly
+directly in the enclosing scope and then passed as an argument to the implicitly
nested scope. Subsequent :keyword:`!for` clauses and any filter condition in the
leftmost :keyword:`!for` clause cannot be evaluated in the enclosing scope as
they may depend on the values obtained from the leftmost iterable. For example:
From af070c12970db34f004adf2e20306a285f06f3a9 Mon Sep 17 00:00:00 2001
From: "Gordon P. Hemsley"
Date: Mon, 13 May 2019 00:18:20 -0400
Subject: [PATCH 020/199] Name individual Travis CI jobs (GH-13268)
---
.travis.yml | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 207649730c2..c1efe24b646 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,7 +32,8 @@ matrix:
allow_failures:
- env: OPTIONAL=true
include:
- - os: linux
+ - name: "CPython tests"
+ os: linux
language: c
compiler: clang
# gcc also works, but to keep the # of concurrent builds down, we use one C
@@ -43,7 +44,8 @@ matrix:
apt:
packages:
- xvfb
- - os: linux
+ - name: "Documentation build"
+ os: linux
language: python
# Build the docs against a stable version of Python so code bugs don't hold up doc-related PRs.
python: 3.6
@@ -56,7 +58,8 @@ matrix:
- python -m pip install sphinx==1.8.2 blurb python-docs-theme
script:
- make check suspicious html SPHINXOPTS="-q -W -j4"
- - os: linux
+ - name: "Documentation tests"
+ os: linux
language: c
compiler: clang
env: TESTING=doctest
@@ -70,7 +73,8 @@ matrix:
- make -C Doc/ PYTHON=../python venv
script:
xvfb-run make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W -j4" doctest
- - os: osx
+ - name: "Mac OS X tests"
+ os: osx
language: c
compiler: clang
# Testing under macOS is optional until testing stability has been demonstrated.
@@ -79,7 +83,8 @@ matrix:
# Python 3 is needed for Argument Clinic and multissl
- HOMEBREW_NO_AUTO_UPDATE=1 brew install xz python3
- export PATH=$(brew --prefix)/bin:$(brew --prefix)/sbin:$PATH
- - os: linux
+ - name: "Test code coverage (Python)"
+ os: linux
language: c
compiler: gcc
env: OPTIONAL=true
@@ -101,7 +106,8 @@ matrix:
# Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files.
- source ./venv/bin/activate
- bash <(curl -s https://codecov.io/bash)
- - os: linux
+ - name: "Test code coverage (C)"
+ os: linux
language: c
compiler: gcc
env: OPTIONAL=true
From d28772ab6967fea136c0707f0207673ebad66f61 Mon Sep 17 00:00:00 2001
From: Edison A <20975616+SimiCode@users.noreply.github.com>
Date: Mon, 13 May 2019 00:23:38 -0700
Subject: [PATCH 021/199] bpo-36783: Add new references for C API Documentation
changes (GH-13204)
---
Doc/c-api/datetime.rst | 12 ++++++------
Doc/data/refcounts.dat | 17 +++++++++++++++++
2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/Doc/c-api/datetime.rst b/Doc/c-api/datetime.rst
index b7949e23500..77b1b216744 100644
--- a/Doc/c-api/datetime.rst
+++ b/Doc/c-api/datetime.rst
@@ -106,6 +106,12 @@ Macros to create objects:
.. versionadded:: 3.6
+.. c:function:: PyObject* PyTime_FromTime(int hour, int minute, int second, int usecond)
+
+ Return a :class:`datetime.time` object with the specified hour, minute, second and
+ microsecond.
+
+
.. c:function:: PyObject* PyTime_FromTimeAndFold(int hour, int minute, int second, int usecond, int fold)
Return a :class:`datetime.time` object with the specified hour, minute, second,
@@ -114,12 +120,6 @@ Macros to create objects:
.. versionadded:: 3.6
-.. c:function:: PyObject* PyTime_FromTime(int hour, int minute, int second, int usecond)
-
- Return a :class:`datetime.time` object with the specified hour, minute, second and
- microsecond.
-
-
.. c:function:: PyObject* PyDelta_FromDSU(int days, int seconds, int useconds)
Return a :class:`datetime.timedelta` object representing the given number
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
index 35527c179f3..213ddcb61fa 100644
--- a/Doc/data/refcounts.dat
+++ b/Doc/data/refcounts.dat
@@ -413,6 +413,16 @@ PyDateTime_FromDateAndTime:int:minute::
PyDateTime_FromDateAndTime:int:second::
PyDateTime_FromDateAndTime:int:usecond::
+PyDateTime_FromDateAndTimeAndFold:PyObject*::+1:
+PyDateTime_FromDateAndTimeAndFold:int:year::
+PyDateTime_FromDateAndTimeAndFold:int:month::
+PyDateTime_FromDateAndTimeAndFold:int:day::
+PyDateTime_FromDateAndTimeAndFold:int:hour::
+PyDateTime_FromDateAndTimeAndFold:int:minute::
+PyDateTime_FromDateAndTimeAndFold:int:second::
+PyDateTime_FromDateAndTimeAndFold:int:usecond::
+PyDateTime_FromDateAndTimeAndFold:int:fold::
+
PyDateTime_FromTimestamp:PyObject*::+1:
PyDateTime_FromTimestamp:PyObject*:args:0:
@@ -2210,6 +2220,13 @@ PyTime_FromTime:int:minute::
PyTime_FromTime:int:second::
PyTime_FromTime:int:usecond::
+PyTime_FromTimeAndFold:PyObject*::+1:
+PyTime_FromTimeAndFold:int:hour::
+PyTime_FromTimeAndFold:int:minute::
+PyTime_FromTimeAndFold:int:second::
+PyTime_FromTimeAndFold:int:usecond::
+PyTime_FromTimeAndFold:int:fold::
+
PyTraceMalloc_Track:int:::
PyTraceMalloc_Track:unsigned int:domain::
PyTraceMalloc_Track:uintptr_t:ptr::
From cf599f6f6f1c392d8f12936982a370d533782195 Mon Sep 17 00:00:00 2001
From: Zackery Spytz
Date: Mon, 13 May 2019 01:50:52 -0600
Subject: [PATCH 022/199] bpo-6584: Add a BadGzipFile exception to the gzip
module. (GH-13022)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-Authored-By: Filip Gruszczyński
Co-Authored-By: Michele Orrù
---
Doc/library/gzip.rst | 8 ++++++++
Doc/whatsnew/3.8.rst | 5 +++++
Lib/gzip.py | 17 +++++++++++------
Lib/test/test_gzip.py | 9 +++++++++
.../2019-04-30-04-34-53.bpo-6584.Hzp9-P.rst | 1 +
5 files changed, 34 insertions(+), 6 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-04-30-04-34-53.bpo-6584.Hzp9-P.rst
diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst
index 8850a33f4ab..3349a94446d 100644
--- a/Doc/library/gzip.rst
+++ b/Doc/library/gzip.rst
@@ -59,6 +59,14 @@ The module defines the following items:
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
+.. exception:: BadGzipFile
+
+ An exception raised for invalid gzip files. It inherits :exc:`OSError`.
+ :exc:`EOFError` and :exc:`zlib.error` can also be raised for invalid gzip
+ files.
+
+ .. versionadded:: 3.8
+
.. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None)
Constructor for the :class:`GzipFile` class, which simulates most of the
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 2cfb110b3d5..684656fc2a5 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -304,6 +304,11 @@ gzip
Added the *mtime* parameter to :func:`gzip.compress` for reproducible output.
(Contributed by Guo Ci Teo in :issue:`34898`.)
+A :exc:`~gzip.BadGzipFile` exception is now raised instead of :exc:`OSError`
+for certain types of invalid or corrupt gzip files.
+(Contributed by Filip Gruszczyński, Michele Orrù, and Zackery Spytz in
+:issue:`6584`.)
+
idlelib and IDLE
----------------
diff --git a/Lib/gzip.py b/Lib/gzip.py
index 7c861874198..2968f475efa 100644
--- a/Lib/gzip.py
+++ b/Lib/gzip.py
@@ -11,7 +11,7 @@
import io
import _compression
-__all__ = ["GzipFile", "open", "compress", "decompress"]
+__all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"]
FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
@@ -112,6 +112,11 @@ def seek(self, off):
def seekable(self):
return True # Allows fast-forwarding even in unseekable streams
+
+class BadGzipFile(OSError):
+ """Exception raised in some cases for invalid gzip files."""
+
+
class GzipFile(_compression.BaseStream):
"""The GzipFile class simulates most of the methods of a file object with
the exception of the truncate() method.
@@ -413,12 +418,12 @@ def _read_gzip_header(self):
return False
if magic != b'\037\213':
- raise OSError('Not a gzipped file (%r)' % magic)
+ raise BadGzipFile('Not a gzipped file (%r)' % magic)
(method, flag,
self._last_mtime) = struct.unpack("
Date: Mon, 13 May 2019 10:42:31 +0200
Subject: [PATCH 023/199] bpo-36778: Update cp65001 codec documentation
(GH-13240)
Remove cp65001 from the codecs table, list it as an alias of utf_8
and add a versionchanged markup.
---
Doc/library/codecs.rst | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst
index 8d3daa35d15..2e9314e0fab 100644
--- a/Doc/library/codecs.rst
+++ b/Doc/library/codecs.rst
@@ -1106,10 +1106,6 @@ particular, the following variants typically exist:
+-----------------+--------------------------------+--------------------------------+
| cp1258 | windows-1258 | Vietnamese |
+-----------------+--------------------------------+--------------------------------+
-| cp65001 | | Alias to ``utf_8`` encoding |
-| | | |
-| | | .. versionadded:: 3.3 |
-+-----------------+--------------------------------+--------------------------------+
| euc_jp | eucjp, ujis, u-jis | Japanese |
+-----------------+--------------------------------+--------------------------------+
| euc_jis_2004 | jisx0213, eucjis2004 | Japanese |
@@ -1234,7 +1230,7 @@ particular, the following variants typically exist:
+-----------------+--------------------------------+--------------------------------+
| utf_7 | U7, unicode-1-1-utf-7 | all languages |
+-----------------+--------------------------------+--------------------------------+
-| utf_8 | U8, UTF, utf8 | all languages |
+| utf_8 | U8, UTF, utf8, cp65001 | all languages |
+-----------------+--------------------------------+--------------------------------+
| utf_8_sig | | all languages |
+-----------------+--------------------------------+--------------------------------+
@@ -1245,6 +1241,9 @@ particular, the following variants typically exist:
The utf-32\* decoders no longer decode
byte sequences that correspond to surrogate code points.
+.. versionchanged:: 3.8
+ ``cp65001`` is now an alias to ``utf_8``.
+
Python Specific Encodings
-------------------------
From d5d9e81ce9a7efc5bc14a5c21398d1ef6f626884 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Mon, 13 May 2019 12:35:37 +0200
Subject: [PATCH 024/199] bpo-36728: Remove PyEval_ReInitThreads() from C API
(GH-13241)
Remove the PyEval_ReInitThreads() function from the Python C API.
It should not be called explicitly: use PyOS_AfterFork_Child()
instead.
Rename PyEval_ReInitThreads() to _PyEval_ReInitThreads() and add a
'runtime' parameter.
---
Doc/whatsnew/3.8.rst | 5 +++++
Include/ceval.h | 1 -
Include/internal/pycore_ceval.h | 2 ++
.../2019-05-11-03-56-23.bpo-36728.FR-dMP.rst | 2 ++
Modules/posixmodule.c | 19 +++++++++++++++----
Python/ceval.c | 3 +--
6 files changed, 25 insertions(+), 7 deletions(-)
create mode 100644 Misc/NEWS.d/next/C API/2019-05-11-03-56-23.bpo-36728.FR-dMP.rst
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 684656fc2a5..ac253059f32 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -990,6 +990,11 @@ Changes in the Python API
Changes in the C API
--------------------
+* The :c:func:`PyEval_ReInitThreads` function has been removed from the C API.
+ It should not be called explicitly: use :c:func:`PyOS_AfterFork_Child`
+ instead.
+ (Contributed by Victor Stinner in :issue:`36728`.)
+
* On Unix, C extensions are no longer linked to libpython except on
Android. When Python is embedded, ``libpython`` must not be loaded with
``RTLD_LOCAL``, but ``RTLD_GLOBAL`` instead. Previously, using
diff --git a/Include/ceval.h b/Include/ceval.h
index 2d4b67d092b..8cdf353b05f 100644
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -195,7 +195,6 @@ PyAPI_FUNC(void) PyEval_AcquireLock(void) Py_DEPRECATED(3.2);
PyAPI_FUNC(void) PyEval_ReleaseLock(void) /* Py_DEPRECATED(3.2) */;
PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate);
PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate);
-PyAPI_FUNC(void) PyEval_ReInitThreads(void);
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds);
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index cdc73a36e5b..7a3166e86da 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -24,6 +24,8 @@ PyAPI_FUNC(int) _PyEval_AddPendingCall(
void *arg);
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(
struct _ceval_runtime_state *ceval);
+PyAPI_FUNC(void) _PyEval_ReInitThreads(
+ _PyRuntimeState *runtime);
#ifdef __cplusplus
}
diff --git a/Misc/NEWS.d/next/C API/2019-05-11-03-56-23.bpo-36728.FR-dMP.rst b/Misc/NEWS.d/next/C API/2019-05-11-03-56-23.bpo-36728.FR-dMP.rst
new file mode 100644
index 00000000000..c691cc412c2
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2019-05-11-03-56-23.bpo-36728.FR-dMP.rst
@@ -0,0 +1,2 @@
+The :c:func:`PyEval_ReInitThreads` function has been removed from the C API.
+It should not be called explicitly: use :c:func:`PyOS_AfterFork_Child` instead.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index aa77094da06..aca64efeb1e 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -25,14 +25,25 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
+#ifdef MS_WINDOWS
+ /* include early to avoid conflict with pycore_condvar.h:
+
+ #define WIN32_LEAN_AND_MEAN
+ #include
+
+ FSCTL_GET_REPARSE_POINT is not exported with WIN32_LEAN_AND_MEAN. */
+# include
+#endif
+
+#include "pycore_ceval.h" /* _PyEval_ReInitThreads() */
+#include "pycore_pystate.h" /* _PyRuntime */
#include "pythread.h"
#include "structmember.h"
#ifndef MS_WINDOWS
-#include "posixmodule.h"
+# include "posixmodule.h"
#else
-#include "winreparse.h"
+# include "winreparse.h"
#endif
-#include "pycore_pystate.h"
/* On android API level 21, 'AT_EACCESS' is not declared although
* HAVE_FACCESSAT is defined. */
@@ -424,7 +435,7 @@ PyOS_AfterFork_Child(void)
_PyRuntimeState *runtime = &_PyRuntime;
_PyGILState_Reinit(runtime);
_PyInterpreterState_DeleteExceptMain(runtime);
- PyEval_ReInitThreads();
+ _PyEval_ReInitThreads(runtime);
_PyImport_ReInitLock();
_PySignal_AfterFork();
_PyRuntimeState_ReInitThreads(runtime);
diff --git a/Python/ceval.c b/Python/ceval.c
index 17439533a3f..1bb4704572b 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -289,9 +289,8 @@ PyEval_ReleaseThread(PyThreadState *tstate)
*/
void
-PyEval_ReInitThreads(void)
+_PyEval_ReInitThreads(_PyRuntimeState *runtime)
{
- _PyRuntimeState *runtime = &_PyRuntime;
struct _ceval_runtime_state *ceval = &runtime->ceval;
if (!gil_created(&ceval->gil)) {
return;
From 32d1458b2e2e00eeb29022179eeb04b83fb7f3c4 Mon Sep 17 00:00:00 2001
From: Kexuan Sun
Date: Mon, 13 May 2019 04:38:20 -0700
Subject: [PATCH 025/199] Changes to the documentation of normcase (GH-4725)
---
Doc/library/os.path.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst
index a167e3b885f..8e7ee8bfe78 100644
--- a/Doc/library/os.path.rst
+++ b/Doc/library/os.path.rst
@@ -87,7 +87,7 @@ the :mod:`glob` module.)
.. function:: commonpath(paths)
Return the longest common sub-path of each pathname in the sequence
- *paths*. Raise ValueError if *paths* contains both absolute and relative
+ *paths*. Raise :exc:`ValueError` if *paths* contains both absolute and relative
pathnames, or if *paths* is empty. Unlike :func:`commonprefix`, this
returns a valid path.
@@ -324,9 +324,9 @@ the :mod:`glob` module.)
.. function:: normcase(path)
- Normalize the case of a pathname. On Unix and Mac OS X, this returns the
- path unchanged; on case-insensitive filesystems, it converts the path to
- lowercase. On Windows, it also converts forward slashes to backward slashes.
+ Normalize the case of a pathname. On Windows, convert all characters in the
+ pathname to lowercase, and also convert forward slashes to backward slashes.
+ On other operating systems, return the path unchanged.
Raise a :exc:`TypeError` if the type of *path* is not ``str`` or ``bytes`` (directly
or indirectly through the :class:`os.PathLike` interface).
From 3e2afd78babe5bd270e7f3b9df8796eeabc79865 Mon Sep 17 00:00:00 2001
From: Utkarsh Gupta
Date: Mon, 13 May 2019 12:29:39 +0000
Subject: [PATCH 026/199] bpo-36008: Doc update for 3.8 migration (GH-12887)
---
Doc/tutorial/interpreter.rst | 4 ++--
Doc/using/cmdline.rst | 4 ++--
Doc/using/windows.rst | 12 ++++++------
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/Doc/tutorial/interpreter.rst b/Doc/tutorial/interpreter.rst
index ab92af044e7..dddfd850cd2 100644
--- a/Doc/tutorial/interpreter.rst
+++ b/Doc/tutorial/interpreter.rst
@@ -24,11 +24,11 @@ Python guru or system administrator. (E.g., :file:`/usr/local/python` is a
popular alternative location.)
On Windows machines, the Python installation is usually placed in
-:file:`C:\\Python36`, though you can change this when you're running the
+:file:`C:\\Python38`, though you can change this when you're running the
installer. To add this directory to your path, you can type the following
command into :ref:`a command prompt window `::
- set path=%path%;C:\python36
+ set path=%path%;C:\python38
Typing an end-of-file character (:kbd:`Control-D` on Unix, :kbd:`Control-Z` on
Windows) at the primary prompt causes the interpreter to exit with a zero exit
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index fd47ce2ab53..5ae3cc808b3 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -182,13 +182,13 @@ Generic options
.. code-block:: none
- Python 3.6.0b2+
+ Python 3.8.0b2+
When given twice, print more information about the build, like:
.. code-block:: none
- Python 3.6.0b2+ (3.6:84a3c5003510+, Oct 26 2016, 02:33:55)
+ Python 3.8.0b2+ (3.8:0c076caaa8, Apr 20 2019, 21:55:00)
[GCC 6.2.0 20161005]
.. versionadded:: 3.6
diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst
index 2f3eb0ea3f0..1f8eb16e505 100644
--- a/Doc/using/windows.rst
+++ b/Doc/using/windows.rst
@@ -214,13 +214,13 @@ of available options is shown below.
For example, to silently install a default, system-wide Python installation,
you could use the following command (from an elevated command prompt)::
- python-3.6.0.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0
+ python-3.8.0.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0
To allow users to easily install a personal copy of Python without the test
suite, you could provide a shortcut with the following command. This will
display a simplified initial page and disallow customization::
- python-3.6.0.exe InstallAllUsers=0 Include_launcher=0 Include_test=0
+ python-3.8.0.exe InstallAllUsers=0 Include_launcher=0 Include_test=0
SimpleInstall=1 SimpleInstallDescription="Just for me, no test suite."
(Note that omitting the launcher also omits file associations, and is only
@@ -257,13 +257,13 @@ where a large number of installations are going to be performed it is very
useful to have a locally cached copy.
Execute the following command from Command Prompt to download all possible
-required files. Remember to substitute ``python-3.6.0.exe`` for the actual
+required files. Remember to substitute ``python-3.8.0.exe`` for the actual
name of your installer, and to create layouts in their own directories to
avoid collisions between files with the same name.
::
- python-3.6.0.exe /layout [optional target directory]
+ python-3.8.0.exe /layout [optional target directory]
You may also specify the ``/quiet`` option to hide the progress display.
@@ -530,7 +530,7 @@ To temporarily set environment variables, open Command Prompt and use the
.. code-block:: doscon
- C:\>set PATH=C:\Program Files\Python 3.6;%PATH%
+ C:\>set PATH=C:\Program Files\Python 3.8;%PATH%
C:\>set PYTHONPATH=%PYTHONPATH%;C:\My_python_lib
C:\>python
@@ -603,7 +603,7 @@ of your Python installation, delimited by a semicolon from other entries. An
example variable could look like this (assuming the first two entries already
existed)::
- C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files\Python 3.6
+ C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files\Python 3.8
.. _launcher:
From 4f098b35f58e911639f8e9adc393d5cf5c792e7f Mon Sep 17 00:00:00 2001
From: Guido van Rossum
Date: Mon, 13 May 2019 05:31:30 -0700
Subject: [PATCH 027/199] bpo-36807: When saving a file in IDLE, call flush and
fsync (#13102)
---
Lib/idlelib/iomenu.py | 2 ++
Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst | 1 +
2 files changed, 3 insertions(+)
create mode 100644 Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst
diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py
index f5bced597aa..b9e813be063 100644
--- a/Lib/idlelib/iomenu.py
+++ b/Lib/idlelib/iomenu.py
@@ -384,6 +384,8 @@ def writefile(self, filename):
try:
with open(filename, "wb") as f:
f.write(chars)
+ f.flush()
+ os.fsync(f.fileno())
return True
except OSError as msg:
tkMessageBox.showerror("I/O Error", str(msg),
diff --git a/Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst b/Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst
new file mode 100644
index 00000000000..18b31b1fe50
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst
@@ -0,0 +1 @@
+When saving a file, call os.flush() so bits are flushed to e.g. USB drive.
From 778a9107586e29421af3a08209cf0b557c1fe5bc Mon Sep 17 00:00:00 2001
From: divyag9
Date: Mon, 13 May 2019 08:05:20 -0500
Subject: [PATCH 028/199] bpo-34682: Wording and grammatical changes to the
doc(https://docs.python.org/3) (GH-13120)
https://bugs.python.org/issue34682
---
Doc/reference/executionmodel.rst | 2 +-
Doc/reference/expressions.rst | 22 +++++++++++-----------
Doc/reference/lexical_analysis.rst | 2 +-
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/Doc/reference/executionmodel.rst b/Doc/reference/executionmodel.rst
index ba7130d6362..49cb86b5608 100644
--- a/Doc/reference/executionmodel.rst
+++ b/Doc/reference/executionmodel.rst
@@ -243,7 +243,7 @@ re-entering the offending piece of code from the top).
When an exception is not handled at all, the interpreter terminates execution of
the program, or returns to its interactive main loop. In either case, it prints
-a stack backtrace, except when the exception is :exc:`SystemExit`.
+a stack traceback, except when the exception is :exc:`SystemExit`.
Exceptions are identified by class instances. The :keyword:`except` clause is
selected depending on the class of the instance: it must reference the class of
diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst
index 79ba4568a54..52b41929d7b 100644
--- a/Doc/reference/expressions.rst
+++ b/Doc/reference/expressions.rst
@@ -144,7 +144,7 @@ the single expression that makes up the expression list.
.. index:: pair: empty; tuple
An empty pair of parentheses yields an empty tuple object. Since tuples are
-immutable, the rules for literals apply (i.e., two occurrences of the empty
+immutable, the same rules as for literals apply (i.e., two occurrences of the empty
tuple may or may not yield the same object).
.. index::
@@ -479,8 +479,8 @@ will raise :exc:`AttributeError` or :exc:`TypeError`, while
When the underlying iterator is complete, the :attr:`~StopIteration.value`
attribute of the raised :exc:`StopIteration` instance becomes the value of
the yield expression. It can be either set explicitly when raising
-:exc:`StopIteration`, or automatically when the sub-iterator is a generator
-(by returning a value from the sub-generator).
+:exc:`StopIteration`, or automatically when the subiterator is a generator
+(by returning a value from the subgenerator).
.. versionchanged:: 3.3
Added ``yield from `` to delegate control flow to a subiterator.
@@ -499,7 +499,7 @@ on the right hand side of an assignment statement.
:pep:`380` - Syntax for Delegating to a Subgenerator
The proposal to introduce the :token:`yield_from` syntax, making delegation
- to sub-generators easy.
+ to subgenerators easy.
:pep:`525` - Asynchronous Generators
The proposal that expanded on :pep:`492` by adding generator capabilities to
@@ -608,7 +608,7 @@ Asynchronous generator functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The presence of a yield expression in a function or method defined using
-:keyword:`async def` further defines the function as a
+:keyword:`async def` further defines the function as an
:term:`asynchronous generator` function.
When an asynchronous generator function is called, it returns an
@@ -673,13 +673,13 @@ which are used to control the execution of a generator function.
Returns an awaitable which when run starts to execute the asynchronous
generator or resumes it at the last executed yield expression. When an
- asynchronous generator function is resumed with a :meth:`~agen.__anext__`
+ asynchronous generator function is resumed with an :meth:`~agen.__anext__`
method, the current yield expression always evaluates to :const:`None` in
the returned awaitable, which when run will continue to the next yield
expression. The value of the :token:`expression_list` of the yield
expression is the value of the :exc:`StopIteration` exception raised by
the completing coroutine. If the asynchronous generator exits without
- yielding another value, the awaitable instead raises an
+ yielding another value, the awaitable instead raises a
:exc:`StopAsyncIteration` exception, signalling that the asynchronous
iteration has completed.
@@ -707,7 +707,7 @@ which are used to control the execution of a generator function.
where the asynchronous generator was paused, and returns the next value
yielded by the generator function as the value of the raised
:exc:`StopIteration` exception. If the asynchronous generator exits
- without yielding another value, an :exc:`StopAsyncIteration` exception is
+ without yielding another value, a :exc:`StopAsyncIteration` exception is
raised by the awaitable.
If the generator function does not catch the passed-in exception, or
raises a different exception, then when the awaitable is run that exception
@@ -1579,7 +1579,7 @@ if :keyword:`in` raised that exception).
pair: membership; test
object: sequence
-The operator :keyword:`not in` is defined to have the inverse true value of
+The operator :keyword:`not in` is defined to have the inverse truth value of
:keyword:`in`.
.. index::
@@ -1594,8 +1594,8 @@ The operator :keyword:`not in` is defined to have the inverse true value of
Identity comparisons
--------------------
-The operators :keyword:`is` and :keyword:`is not` test for object identity: ``x
-is y`` is true if and only if *x* and *y* are the same object. Object identity
+The operators :keyword:`is` and :keyword:`is not` test for an object's identity: ``x
+is y`` is true if and only if *x* and *y* are the same object. An Object's identity
is determined using the :meth:`id` function. ``x is not y`` yields the inverse
truth value. [#]_
diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst
index 1cbe421ded9..cc1b2f57a70 100644
--- a/Doc/reference/lexical_analysis.rst
+++ b/Doc/reference/lexical_analysis.rst
@@ -70,7 +70,7 @@ Comments
A comment starts with a hash character (``#``) that is not part of a string
literal, and ends at the end of the physical line. A comment signifies the end
of the logical line unless the implicit line joining rules are invoked. Comments
-are ignored by the syntax; they are not tokens.
+are ignored by the syntax.
.. _encodings:
From c1f7262f7013074613805347db2276f8b5e0e3a4 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Mon, 13 May 2019 16:22:51 +0200
Subject: [PATCH 029/199] bpo-36728: Remove PyEval_ReInitThreads documentation
(GH-13282)
---
Doc/c-api/init.rst | 7 -------
1 file changed, 7 deletions(-)
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 367c069a7ff..b30649498a9 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -877,13 +877,6 @@ code, or when embedding the Python interpreter:
and is not released.
-.. c:function:: void PyEval_ReInitThreads()
-
- This function is called from :c:func:`PyOS_AfterFork_Child` to ensure
- that newly created child processes don't hold locks referring to threads
- which are not running in the child process.
-
-
The following functions use thread-local storage, and are not compatible
with sub-interpreters:
From 2c10538d11fa9be9a1a9f21605861e10ec4fa207 Mon Sep 17 00:00:00 2001
From: Xtreak
Date: Mon, 13 May 2019 20:18:52 +0530
Subject: [PATCH 030/199] bpo-36903: Fix ResourceWarning in test_logging
(GH-13283)
---
Lib/test/test_logging.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index bc99c3adbe3..b884753ad39 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -684,6 +684,7 @@ def emit(self, record):
self.assertEqual(len(logging._handlers), 0)
refed_h = _OurHandler()
+ self.addCleanup(refed_h.sub_handler.stream.close)
refed_h.name = 'because we need at least one for this test'
self.assertGreater(len(logging._handlers), 0)
self.assertGreater(len(logging._at_fork_reinit_lock_weakset), 1)
From 410b85a7f701be280eb15b0ca4fe116e86f1d008 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Mon, 13 May 2019 17:12:45 +0200
Subject: [PATCH 031/199] bpo-36900: import.c uses
PyInterpreterState.core_config (GH-13278)
Move _PyImportZip_Init() to the internal C API and add an 'interp'
parameter.
---
Include/import.h | 2 -
Include/internal/pycore_pylifecycle.h | 2 +
Python/import.c | 71 +++++++++++++++++----------
Python/pylifecycle.c | 2 +-
4 files changed, 48 insertions(+), 29 deletions(-)
diff --git a/Include/import.h b/Include/import.h
index c664803478a..13c614933c7 100644
--- a/Include/import.h
+++ b/Include/import.h
@@ -8,8 +8,6 @@ extern "C" {
#endif
#ifndef Py_LIMITED_API
-PyAPI_FUNC(_PyInitError) _PyImportZip_Init(void);
-
PyMODINIT_FUNC PyInit__imp(void);
#endif /* !Py_LIMITED_API */
PyAPI_FUNC(long) PyImport_GetMagicNumber(void);
diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h
index 7144bbcda7c..0d83acdf28a 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -54,6 +54,8 @@ extern int _PyFloat_Init(void);
extern _PyInitError _Py_HashRandomization_Init(const _PyCoreConfig *);
extern _PyInitError _PyTypes_Init(void);
+extern _PyInitError _PyImportZip_Init(PyInterpreterState *interp);
+
/* Various internal finalizers */
diff --git a/Python/import.c b/Python/import.c
index 9290f39c0ae..c634edb4c7f 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -91,7 +91,7 @@ _PyImportHooks_Init(void)
}
_PyInitError
-_PyImportZip_Init(void)
+_PyImportZip_Init(PyInterpreterState *interp)
{
PyObject *path_hooks, *zipimport;
int err = 0;
@@ -102,14 +102,17 @@ _PyImportZip_Init(void)
goto error;
}
- if (Py_VerboseFlag)
+ int verbose = interp->core_config.verbose;
+ if (verbose) {
PySys_WriteStderr("# installing zipimport hook\n");
+ }
zipimport = PyImport_ImportModule("zipimport");
if (zipimport == NULL) {
PyErr_Clear(); /* No zip import module -- okay */
- if (Py_VerboseFlag)
+ if (verbose) {
PySys_WriteStderr("# can't import zipimport\n");
+ }
}
else {
_Py_IDENTIFIER(zipimporter);
@@ -118,9 +121,9 @@ _PyImportZip_Init(void)
Py_DECREF(zipimport);
if (zipimporter == NULL) {
PyErr_Clear(); /* No zipimporter object -- okay */
- if (Py_VerboseFlag)
- PySys_WriteStderr(
- "# can't import zipimport.zipimporter\n");
+ if (verbose) {
+ PySys_WriteStderr("# can't import zipimport.zipimporter\n");
+ }
}
else {
/* sys.path_hooks.insert(0, zipimporter) */
@@ -129,9 +132,9 @@ _PyImportZip_Init(void)
if (err < 0) {
goto error;
}
- if (Py_VerboseFlag)
- PySys_WriteStderr(
- "# installed zipimport hook\n");
+ if (verbose) {
+ PySys_WriteStderr("# installed zipimport hook\n");
+ }
}
}
@@ -415,22 +418,26 @@ PyImport_Cleanup(void)
/* XXX Perhaps these precautions are obsolete. Who knows? */
- if (Py_VerboseFlag)
+ int verbose = interp->core_config.verbose;
+ if (verbose) {
PySys_WriteStderr("# clear builtins._\n");
+ }
if (PyDict_SetItemString(interp->builtins, "_", Py_None) < 0) {
PyErr_WriteUnraisable(NULL);
}
for (p = sys_deletes; *p != NULL; p++) {
- if (Py_VerboseFlag)
+ if (verbose) {
PySys_WriteStderr("# clear sys.%s\n", *p);
+ }
if (PyDict_SetItemString(interp->sysdict, *p, Py_None) < 0) {
PyErr_WriteUnraisable(NULL);
}
}
for (p = sys_files; *p != NULL; p+=2) {
- if (Py_VerboseFlag)
+ if (verbose) {
PySys_WriteStderr("# restore sys.%s\n", *p);
+ }
value = _PyDict_GetItemStringWithError(interp->sysdict, *(p+1));
if (value == NULL) {
if (PyErr_Occurred()) {
@@ -469,8 +476,9 @@ PyImport_Cleanup(void)
}
#define CLEAR_MODULE(name, mod) \
if (PyModule_Check(mod)) { \
- if (Py_VerboseFlag && PyUnicode_Check(name)) \
+ if (verbose && PyUnicode_Check(name)) { \
PySys_FormatStderr("# cleanup[2] removing %U\n", name); \
+ } \
STORE_MODULE_WEAKREF(name, mod); \
if (PyObject_SetItem(modules, name, Py_None) < 0) { \
PyErr_WriteUnraisable(NULL); \
@@ -563,8 +571,9 @@ PyImport_Cleanup(void)
if (dict == interp->builtins || dict == interp->sysdict)
continue;
Py_INCREF(mod);
- if (Py_VerboseFlag && PyUnicode_Check(name))
+ if (verbose && PyUnicode_Check(name)) {
PySys_FormatStderr("# cleanup[3] wiping %U\n", name);
+ }
_PyModule_Clear(mod);
Py_DECREF(mod);
}
@@ -572,11 +581,13 @@ PyImport_Cleanup(void)
}
/* Next, delete sys and builtins (in that order) */
- if (Py_VerboseFlag)
+ if (verbose) {
PySys_FormatStderr("# cleanup[3] wiping sys\n");
+ }
_PyModule_ClearDict(interp->sysdict);
- if (Py_VerboseFlag)
+ if (verbose) {
PySys_FormatStderr("# cleanup[3] wiping builtins\n");
+ }
_PyModule_ClearDict(interp->builtins);
/* Clear and delete the modules directory. Actual modules will
@@ -755,9 +766,11 @@ _PyImport_FindExtensionObjectEx(PyObject *name, PyObject *filename,
PyMapping_DelItem(modules, name);
return NULL;
}
- if (Py_VerboseFlag)
+ int verbose = _PyInterpreterState_Get()->core_config.verbose;
+ if (verbose) {
PySys_FormatStderr("import %U # previously loaded (%R)\n",
- name, filename);
+ name, filename);
+ }
return mod;
}
@@ -1427,7 +1440,7 @@ PyImport_ImportModuleNoBlock(const char *name)
/* Remove importlib frames from the traceback,
* except in Verbose mode. */
static void
-remove_importlib_frames(void)
+remove_importlib_frames(PyInterpreterState *interp)
{
const char *importlib_filename = "";
const char *external_filename = "";
@@ -1442,8 +1455,10 @@ remove_importlib_frames(void)
which end with a call to "_call_with_frames_removed". */
PyErr_Fetch(&exception, &value, &base_tb);
- if (!exception || Py_VerboseFlag)
+ if (!exception || interp->core_config.verbose) {
goto done;
+ }
+
if (PyType_IsSubtype((PyTypeObject *) exception,
(PyTypeObject *) PyExc_ImportError))
always_trim = 1;
@@ -1853,8 +1868,9 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
Py_XDECREF(abs_name);
Py_XDECREF(mod);
Py_XDECREF(package);
- if (final_mod == NULL)
- remove_importlib_frames();
+ if (final_mod == NULL) {
+ remove_importlib_frames(interp);
+ }
return final_mod;
}
@@ -2303,13 +2319,16 @@ PyInit__imp(void)
PyObject *m, *d;
m = PyModule_Create(&impmodule);
- if (m == NULL)
+ if (m == NULL) {
goto failure;
+ }
d = PyModule_GetDict(m);
- if (d == NULL)
+ if (d == NULL) {
goto failure;
- _PyCoreConfig *config = &_PyInterpreterState_Get()->core_config;
- PyObject *pyc_mode = PyUnicode_FromWideChar(config->check_hash_pycs_mode, -1);
+ }
+
+ const wchar_t *mode = _PyInterpreterState_Get()->core_config.check_hash_pycs_mode;
+ PyObject *pyc_mode = PyUnicode_FromWideChar(mode, -1);
if (pyc_mode == NULL) {
goto failure;
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index de8595ccb58..014b19aa8aa 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -205,7 +205,7 @@ init_importlib_external(PyInterpreterState *interp)
return _Py_INIT_ERR("external importer setup failed");
}
Py_DECREF(value);
- return _PyImportZip_Init();
+ return _PyImportZip_Init(interp);
}
/* Helper functions to better handle the legacy C locale
From 85c69d5c4c5682a70201612128e838d438c01499 Mon Sep 17 00:00:00 2001
From: Guido van Rossum
Date: Mon, 13 May 2019 09:00:53 -0700
Subject: [PATCH 032/199] Fix typo in NEWS item about IDLE (os.flush() should
be os.fsync()) (#13284)
---
Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst b/Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst
index 18b31b1fe50..2a905bf0eec 100644
--- a/Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst
+++ b/Misc/NEWS.d/next/IDLE/2019-05-05-16-27-53.bpo-13102.AGNWYJ.rst
@@ -1 +1 @@
-When saving a file, call os.flush() so bits are flushed to e.g. USB drive.
+When saving a file, call os.fsync() so bits are flushed to e.g. USB drive.
From b0917df329ba14b7bc6fa782c1b61e7a2163af0b Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Mon, 13 May 2019 19:17:54 +0200
Subject: [PATCH 033/199] bpo-36719: regrtest -jN no longer stops on crash
(GH-13231)
"python3 -m test -jN ..." now continues the execution of next tests
when a worker process crash (CHILD_ERROR state). Previously, the test
suite stopped immediately. Use --failfast to stop at the first error.
Moreover, --forever now also implies --failfast.
---
Lib/test/libregrtest/cmdline.py | 5 ++-
Lib/test/libregrtest/main.py | 7 +++-
Lib/test/libregrtest/runtest.py | 11 ++++-
Lib/test/libregrtest/runtest_mp.py | 41 ++++++++++++-------
.../2019-05-10-01-50-30.bpo-36719.O84ZWv.rst | 3 ++
5 files changed, 49 insertions(+), 18 deletions(-)
create mode 100644 Misc/NEWS.d/next/Tests/2019-05-10-01-50-30.bpo-36719.O84ZWv.rst
diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py
index cb09ee0e03b..dc0d8807194 100644
--- a/Lib/test/libregrtest/cmdline.py
+++ b/Lib/test/libregrtest/cmdline.py
@@ -256,7 +256,7 @@ def _create_parser():
help='suppress error message boxes on Windows')
group.add_argument('-F', '--forever', action='store_true',
help='run the specified tests in a loop, until an '
- 'error happens')
+ 'error happens; imply --failfast')
group.add_argument('--list-tests', action='store_true',
help="only write the name of tests that will be run, "
"don't execute them")
@@ -389,5 +389,8 @@ def _parse_args(args, **kwargs):
with open(ns.match_filename) as fp:
for line in fp:
ns.match_tests.append(line.strip())
+ if ns.forever:
+ # --forever implies --failfast
+ ns.failfast = True
return ns
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index c19ea44db9b..02717d8c7b1 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -16,7 +16,7 @@
findtests, runtest, get_abs_module,
STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED,
INTERRUPTED, CHILD_ERROR, TEST_DID_NOT_RUN,
- PROGRESS_MIN_TIME, format_test_result)
+ PROGRESS_MIN_TIME, format_test_result, is_failed)
from test.libregrtest.setup import setup_tests
from test.libregrtest.utils import removepy, count, format_duration, printlist
from test import support
@@ -404,7 +404,7 @@ def run_tests_sequential(self):
test_time = time.monotonic() - start_time
if test_time >= PROGRESS_MIN_TIME:
previous_test = "%s in %s" % (previous_test, format_duration(test_time))
- elif result[0] == PASSED:
+ elif result.result == PASSED:
# be quiet: say nothing if the test passed shortly
previous_test = None
@@ -413,6 +413,9 @@ def run_tests_sequential(self):
if module not in save_modules and module.startswith("test."):
support.unload(module)
+ if self.ns.failfast and is_failed(result, self.ns):
+ break
+
if previous_test:
print(previous_test)
diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py
index a9574929a4c..a43b7666cd1 100644
--- a/Lib/test/libregrtest/runtest.py
+++ b/Lib/test/libregrtest/runtest.py
@@ -24,7 +24,7 @@
RESOURCE_DENIED = -3
INTERRUPTED = -4
CHILD_ERROR = -5 # error in a child process
-TEST_DID_NOT_RUN = -6 # error in a child process
+TEST_DID_NOT_RUN = -6
_FORMAT_TEST_RESULT = {
PASSED: '%s passed',
@@ -64,6 +64,15 @@
FOUND_GARBAGE = []
+def is_failed(result, ns):
+ ok = result.result
+ if ok in (PASSED, RESOURCE_DENIED, SKIPPED, TEST_DID_NOT_RUN):
+ return False
+ if ok == ENV_CHANGED:
+ return ns.fail_env_changed
+ return True
+
+
def format_test_result(result):
fmt = _FORMAT_TEST_RESULT.get(result.result, "%s")
return fmt % result.test_name
diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py
index dbab6954de8..ced7f866a89 100644
--- a/Lib/test/libregrtest/runtest_mp.py
+++ b/Lib/test/libregrtest/runtest_mp.py
@@ -13,7 +13,7 @@
from test.libregrtest.runtest import (
runtest, INTERRUPTED, CHILD_ERROR, PROGRESS_MIN_TIME,
- format_test_result, TestResult)
+ format_test_result, TestResult, is_failed)
from test.libregrtest.setup import setup_tests
from test.libregrtest.utils import format_duration
@@ -22,8 +22,12 @@
PROGRESS_UPDATE = 30.0 # seconds
-def must_stop(result):
- return result.result in (INTERRUPTED, CHILD_ERROR)
+def must_stop(result, ns):
+ if result.result == INTERRUPTED:
+ return True
+ if ns.failfast and is_failed(result, ns):
+ return True
+ return False
def run_test_in_subprocess(testname, ns):
@@ -66,16 +70,22 @@ class MultiprocessIterator:
"""A thread-safe iterator over tests for multiprocess mode."""
- def __init__(self, tests):
+ def __init__(self, tests_iter):
self.lock = threading.Lock()
- self.tests = tests
+ self.tests_iter = tests_iter
def __iter__(self):
return self
def __next__(self):
with self.lock:
- return next(self.tests)
+ if self.tests_iter is None:
+ raise StopIteration
+ return next(self.tests_iter)
+
+ def stop(self):
+ with self.lock:
+ self.tests_iter = None
MultiprocessResult = collections.namedtuple('MultiprocessResult',
@@ -92,23 +102,24 @@ def __init__(self, pending, output, ns):
self._popen = None
def kill(self):
- if not self.is_alive():
+ popen = self._popen
+ if popen is None:
return
- if self._popen is not None:
- self._popen.kill()
+ print("Kill regrtest worker process %s" % popen.pid)
+ popen.kill()
def _runtest(self, test_name):
try:
self.start_time = time.monotonic()
self.current_test_name = test_name
- popen = run_test_in_subprocess(test_name, self.ns)
- self._popen = popen
+ self._popen = run_test_in_subprocess(test_name, self.ns)
+ popen = self._popen
with popen:
try:
stdout, stderr = popen.communicate()
except:
- popen.kill()
+ self.kill()
popen.wait()
raise
@@ -153,7 +164,7 @@ def run(self):
mp_result = self._runtest(test_name)
self.output.put((False, mp_result))
- if must_stop(mp_result.result):
+ if must_stop(mp_result.result, self.ns):
break
except BaseException:
self.output.put((True, traceback.format_exc()))
@@ -255,7 +266,7 @@ def _process_result(self, item):
if mp_result.stderr and not self.ns.pgo:
print(mp_result.stderr, file=sys.stderr, flush=True)
- if must_stop(mp_result.result):
+ if must_stop(mp_result.result, self.ns):
return True
return False
@@ -280,6 +291,8 @@ def run_tests(self):
if self.test_timeout is not None:
faulthandler.cancel_dump_traceback_later()
+ # a test failed (and --failfast is set) or all tests completed
+ self.pending.stop()
self.wait_workers()
diff --git a/Misc/NEWS.d/next/Tests/2019-05-10-01-50-30.bpo-36719.O84ZWv.rst b/Misc/NEWS.d/next/Tests/2019-05-10-01-50-30.bpo-36719.O84ZWv.rst
new file mode 100644
index 00000000000..9f60145975f
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2019-05-10-01-50-30.bpo-36719.O84ZWv.rst
@@ -0,0 +1,3 @@
+"python3 -m test -jN ..." now continues the execution of next tests when a
+worker process crash (CHILD_ERROR state). Previously, the test suite stopped
+immediately. Use --failfast to stop at the first error.
From 50466c66509de556a8579172f82d1abb1560d8e4 Mon Sep 17 00:00:00 2001
From: Pierre Glaser
Date: Mon, 13 May 2019 19:20:48 +0200
Subject: [PATCH 034/199] bpo-36867: DOC update multiprocessing.rst (GH-13289)
Followup to bpo-36867.
---
Doc/library/multiprocessing.rst | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst
index a5ecfa6cc1c..c6ffb00819c 100644
--- a/Doc/library/multiprocessing.rst
+++ b/Doc/library/multiprocessing.rst
@@ -131,13 +131,17 @@ to start a process. These *start methods* are
handles on Windows.
On Unix using the *spawn* or *forkserver* start methods will also
-start a *semaphore tracker* process which tracks the unlinked named
-semaphores created by processes of the program. When all processes
-have exited the semaphore tracker unlinks any remaining semaphores.
+start a *resource tracker* process which tracks the unlinked named
+system resources (such as named semaphores or
+:class:`~multiprocessing.shared_memory.SharedMemory` objects) created
+by processes of the program. When all processes
+have exited the resource tracker unlinks any remaining tracked object.
Usually there should be none, but if a process was killed by a signal
-there may be some "leaked" semaphores. (Unlinking the named semaphores
-is a serious matter since the system allows only a limited number, and
-they will not be automatically unlinked until the next reboot.)
+there may be some "leaked" resources. (Neither leaked semaphores nor shared
+memory segments will be automatically unlinked until the next reboot. This is
+problematic for both objects because the system allows only a limited number of
+named semaphores, and shared memory segments occupy some space in the main
+memory.)
To select a start method you use the :func:`set_start_method` in
the ``if __name__ == '__main__'`` clause of the main module. For
From 95da83d9bac698d420cc308e8699ef6e4fae2aca Mon Sep 17 00:00:00 2001
From: Antoine Pitrou
Date: Mon, 13 May 2019 20:02:46 +0200
Subject: [PATCH 035/199] bpo-36894: Fix regression in
test_multiprocessing_spawn (no tests run on Windows) (GH-13290)
---
Lib/multiprocessing/resource_tracker.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/Lib/multiprocessing/resource_tracker.py b/Lib/multiprocessing/resource_tracker.py
index e67e0b213eb..61a6dd66e72 100644
--- a/Lib/multiprocessing/resource_tracker.py
+++ b/Lib/multiprocessing/resource_tracker.py
@@ -20,8 +20,6 @@
import sys
import threading
import warnings
-import _multiprocessing
-import _posixshmem
from . import spawn
from . import util
@@ -33,10 +31,17 @@
_CLEANUP_FUNCS = {
'noop': lambda: None,
- 'semaphore': _multiprocessing.sem_unlink,
- 'shared_memory': _posixshmem.shm_unlink
}
+if os.name == 'posix':
+ import _multiprocessing
+ import _posixshmem
+
+ _CLEANUP_FUNCS.update({
+ 'semaphore': _multiprocessing.sem_unlink,
+ 'shared_memory': _posixshmem.shm_unlink,
+ })
+
class ResourceTracker(object):
From be6939fb02e65b56c45377940b339d150b124d05 Mon Sep 17 00:00:00 2001
From: Brad
Date: Mon, 13 May 2019 14:09:49 -0400
Subject: [PATCH 036/199] Docs: Add bz2 usage examples (GH-13258)
* Docs: Add bz2 usage examples
- Adds an "Examples of usage" section inspired by the one
found in the gzip docs
- Corrects the descriptions for ``compresslevel`` and ``data``:
- ``compresslevel`` must be an `int`, not any number. For
instance, passing a float will raise ``TypeError``
- Notes that `data` must be bytes-like
---
Doc/library/bz2.rst | 84 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 79 insertions(+), 5 deletions(-)
diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst
index 946cc67dd30..277de601cb7 100644
--- a/Doc/library/bz2.rst
+++ b/Doc/library/bz2.rst
@@ -83,7 +83,7 @@ All of the classes in this module may safely be accessed from multiple threads.
The *buffering* argument is ignored. Its use is deprecated since Python 3.0.
- If *mode* is ``'w'`` or ``'a'``, *compresslevel* can be a number between
+ If *mode* is ``'w'`` or ``'a'``, *compresslevel* can be an integer between
``1`` and ``9`` specifying the level of compression: ``1`` produces the
least compression, and ``9`` (default) produces the most compression.
@@ -148,7 +148,7 @@ Incremental (de)compression
incrementally. For one-shot compression, use the :func:`compress` function
instead.
- *compresslevel*, if given, must be a number between ``1`` and ``9``. The
+ *compresslevel*, if given, must be an integer between ``1`` and ``9``. The
default is ``9``.
.. method:: compress(data)
@@ -234,9 +234,9 @@ One-shot (de)compression
.. function:: compress(data, compresslevel=9)
- Compress *data*.
+ Compress *data*, a :term:`bytes-like object `.
- *compresslevel*, if given, must be a number between ``1`` and ``9``. The
+ *compresslevel*, if given, must be an integer between ``1`` and ``9``. The
default is ``9``.
For incremental compression, use a :class:`BZ2Compressor` instead.
@@ -244,7 +244,7 @@ One-shot (de)compression
.. function:: decompress(data)
- Decompress *data*.
+ Decompress *data*, a :term:`bytes-like object `.
If *data* is the concatenation of multiple compressed streams, decompress
all of the streams.
@@ -254,3 +254,77 @@ One-shot (de)compression
.. versionchanged:: 3.3
Support for multi-stream inputs was added.
+.. _bz2-usage-examples:
+
+Examples of usage
+-----------------
+
+Below are some examples of typical usage of the :mod:`bz2` module.
+
+Using :func:`compress` and :func:`decompress` to demonstrate round-trip compression:
+
+ >>> import bz2
+
+ >>> data = b"""\
+ ... Donec rhoncus quis sapien sit amet molestie. Fusce scelerisque vel augue
+ ... nec ullamcorper. Nam rutrum pretium placerat. Aliquam vel tristique lorem,
+ ... sit amet cursus ante. In interdum laoreet mi, sit amet ultrices purus
+ ... pulvinar a. Nam gravida euismod magna, non varius justo tincidunt feugiat.
+ ... Aliquam pharetra lacus non risus vehicula rutrum. Maecenas aliquam leo
+ ... felis. Pellentesque semper nunc sit amet nibh ullamcorper, ac elementum
+ ... dolor luctus. Curabitur lacinia mi ornare consectetur vestibulum."""
+
+ >>> c = bz2.compress(data)
+ >>> len(data) / len(c) # Data compression ratio
+ 1.513595166163142
+
+ >>> d = bz2.decompress(c)
+ >>> data == d # Check equality to original object after round-trip
+ True
+
+Using :class:`BZ2Compressor` for incremental compression:
+
+ >>> import bz2
+
+ >>> def gen_data(chunks=10, chunksize=1000):
+ ... """Yield incremental blocks of chunksize bytes."""
+ ... for _ in range(chunks):
+ ... yield b"z" * chunksize
+ ...
+ >>> comp = bz2.BZ2Compressor()
+ >>> out = b""
+ >>> for chunk in gen_data():
+ ... # Provide data to the compressor object
+ ... out = out + comp.compress(chunk)
+ ...
+ >>> # Finish the compression process. Call this once you have
+ >>> # finished providing data to the compressor.
+ >>> out = out + comp.flush()
+
+The example above uses a very "nonrandom" stream of data
+(a stream of `b"z"` chunks). Random data tends to compress poorly,
+while ordered, repetitive data usually yields a high compression ratio.
+
+Writing and reading a bzip2-compressed file in binary mode:
+
+ >>> import bz2
+
+ >>> data = b"""\
+ ... Donec rhoncus quis sapien sit amet molestie. Fusce scelerisque vel augue
+ ... nec ullamcorper. Nam rutrum pretium placerat. Aliquam vel tristique lorem,
+ ... sit amet cursus ante. In interdum laoreet mi, sit amet ultrices purus
+ ... pulvinar a. Nam gravida euismod magna, non varius justo tincidunt feugiat.
+ ... Aliquam pharetra lacus non risus vehicula rutrum. Maecenas aliquam leo
+ ... felis. Pellentesque semper nunc sit amet nibh ullamcorper, ac elementum
+ ... dolor luctus. Curabitur lacinia mi ornare consectetur vestibulum."""
+
+ >>> with bz2.open("myfile.bz2", "wb") as f:
+ ... # Write compressed data to file
+ ... unused = f.write(data)
+
+ >>> with bz2.open("myfile.bz2", "rb") as f:
+ ... # Decompress data from file
+ ... content = f.read()
+
+ >>> content == data # Check equality to original object after round-trip
+ True
From b1dfcad6f0d3a52c9ac31fb9763fc7962a84b27c Mon Sep 17 00:00:00 2001
From: Pierre Glaser
Date: Mon, 13 May 2019 21:15:32 +0200
Subject: [PATCH 037/199] bpo-36867: Create the resource_tracker before
launching SharedMemoryManagers (GH-13276)
---
Lib/multiprocessing/managers.py | 9 +++
Lib/test/_test_multiprocessing.py | 58 ++++++++++++++-----
.../2019-05-13-13-02-43.bpo-36867.Qh-6mX.rst | 1 +
3 files changed, 54 insertions(+), 14 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-13-13-02-43.bpo-36867.Qh-6mX.rst
diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py
index 2bad636855f..514152298b0 100644
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -21,6 +21,7 @@
import array
import queue
import time
+import os
from os import getpid
from traceback import format_exc
@@ -1349,6 +1350,14 @@ class SharedMemoryManager(BaseManager):
_Server = SharedMemoryServer
def __init__(self, *args, **kwargs):
+ if os.name == "posix":
+ # bpo-36867: Ensure the resource_tracker is running before
+ # launching the manager process, so that concurrent
+ # shared_memory manipulation both in the manager and in the
+ # current process does not create two resource_tracker
+ # processes.
+ from . import resource_tracker
+ resource_tracker.ensure_running()
BaseManager.__init__(self, *args, **kwargs)
util.debug(f"{self.__class__.__name__} created by pid {getpid()}")
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index a50293c7616..772c9638337 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -17,6 +17,7 @@
import socket
import random
import logging
+import subprocess
import struct
import operator
import pickle
@@ -3765,6 +3766,27 @@ def test_shared_memory_SharedMemoryServer_ignores_sigint(self):
smm.shutdown()
+ @unittest.skipIf(os.name != "posix", "resource_tracker is posix only")
+ def test_shared_memory_SharedMemoryManager_reuses_resource_tracker(self):
+ # bpo-36867: test that a SharedMemoryManager uses the
+ # same resource_tracker process as its parent.
+ cmd = '''if 1:
+ from multiprocessing.managers import SharedMemoryManager
+
+
+ smm = SharedMemoryManager()
+ smm.start()
+ sl = smm.ShareableList(range(10))
+ smm.shutdown()
+ '''
+ rc, out, err = test.support.script_helper.assert_python_ok('-c', cmd)
+
+ # Before bpo-36867 was fixed, a SharedMemoryManager not using the same
+ # resource_tracker process as its parent would make the parent's
+ # tracker complain about sl being leaked even though smm.shutdown()
+ # properly released sl.
+ self.assertFalse(err)
+
def test_shared_memory_SharedMemoryManager_basics(self):
smm1 = multiprocessing.managers.SharedMemoryManager()
with self.assertRaises(ValueError):
@@ -3904,8 +3926,6 @@ def test_shared_memory_ShareableList_pickling(self):
sl.shm.close()
def test_shared_memory_cleaned_after_process_termination(self):
- import subprocess
- from multiprocessing import shared_memory
cmd = '''if 1:
import os, time, sys
from multiprocessing import shared_memory
@@ -3916,18 +3936,29 @@ def test_shared_memory_cleaned_after_process_termination(self):
sys.stdout.flush()
time.sleep(100)
'''
- p = subprocess.Popen([sys.executable, '-E', '-c', cmd],
- stdout=subprocess.PIPE)
- name = p.stdout.readline().strip().decode()
+ with subprocess.Popen([sys.executable, '-E', '-c', cmd],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE) as p:
+ name = p.stdout.readline().strip().decode()
- # killing abruptly processes holding reference to a shared memory
- # segment should not leak the given memory segment.
- p.terminate()
- p.wait()
- time.sleep(1.0) # wait for the OS to collect the segment
+ # killing abruptly processes holding reference to a shared memory
+ # segment should not leak the given memory segment.
+ p.terminate()
+ p.wait()
+ time.sleep(1.0) # wait for the OS to collect the segment
- with self.assertRaises(FileNotFoundError):
- smm = shared_memory.SharedMemory(name, create=False)
+ # The shared memory file was deleted.
+ with self.assertRaises(FileNotFoundError):
+ smm = shared_memory.SharedMemory(name, create=False)
+
+ if os.name == 'posix':
+ # A warning was emitted by the subprocess' own
+ # resource_tracker (on Windows, shared memory segments
+ # are released automatically by the OS).
+ err = p.stderr.read().decode()
+ self.assertIn(
+ "resource_tracker: There appear to be 1 leaked "
+ "shared_memory objects to clean up at shutdown", err)
#
#
@@ -4560,7 +4591,7 @@ def run_in_child(cls):
print(json.dumps(flags))
def test_flags(self):
- import json, subprocess
+ import json
# start child process using unusual flags
prog = ('from test._test_multiprocessing import TestFlags; ' +
'TestFlags.run_in_child()')
@@ -4866,7 +4897,6 @@ def test_resource_tracker(self):
#
# Check that killing process does not leak named semaphores
#
- import subprocess
cmd = '''if 1:
import time, os, tempfile
import multiprocessing as mp
diff --git a/Misc/NEWS.d/next/Library/2019-05-13-13-02-43.bpo-36867.Qh-6mX.rst b/Misc/NEWS.d/next/Library/2019-05-13-13-02-43.bpo-36867.Qh-6mX.rst
new file mode 100644
index 00000000000..ce925d0594b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-13-13-02-43.bpo-36867.Qh-6mX.rst
@@ -0,0 +1 @@
+Fix a bug making a SharedMemoryManager instance and its parent process use two separate resource_tracker processes.
\ No newline at end of file
From b6a09ae287e253e4146a5a224b75d4dbfd38cb63 Mon Sep 17 00:00:00 2001
From: Matthias Bussonnier
Date: Mon, 13 May 2019 12:23:07 -0700
Subject: [PATCH 038/199] bpo-36895: Undocument removed time.clock (GH-13286)
---
Doc/library/time.rst | 24 ------------------------
Doc/whatsnew/3.8.rst | 4 ++++
2 files changed, 4 insertions(+), 24 deletions(-)
diff --git a/Doc/library/time.rst b/Doc/library/time.rst
index cad4afda38b..6d0ceafa522 100644
--- a/Doc/library/time.rst
+++ b/Doc/library/time.rst
@@ -136,30 +136,6 @@ Functions
Unlike the C function of the same name, :func:`asctime` does not add a
trailing newline.
-
-.. function:: clock()
-
- .. index::
- single: CPU time
- single: processor time
- single: benchmarking
-
- On Unix, return the current processor time as a floating point number expressed
- in seconds. The precision, and in fact the very definition of the meaning of
- "processor time", depends on that of the C function of the same name.
-
- On Windows, this function returns wall-clock seconds elapsed since the first
- call to this function, as a floating point number, based on the Win32 function
- :c:func:`QueryPerformanceCounter`. The resolution is typically better than one
- microsecond.
-
- .. availability:: Windows, Unix. Not available on VxWorks.
-
- .. deprecated-removed:: 3.3 3.8
- The behaviour of this function depends on the platform: use
- :func:`perf_counter` or :func:`process_time` instead, depending on your
- requirements, to have a well defined behaviour.
-
.. function:: pthread_getcpuclockid(thread_id)
Return the *clk_id* of the thread-specific CPU-time clock for the specified *thread_id*.
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index ac253059f32..a2af201215c 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -788,6 +788,10 @@ The following features and APIs have been removed from Python 3.8:
* The function :func:`platform.popen` has been removed, it was deprecated since
Python 3.3: use :func:`os.popen` instead.
+* The function :func:`time.clock` has been removed, it was deprecated since Python
+ 3.3: use :func:`time.perf_counter` or :func:`time.process_time` instead, depending
+ on your requirements, to have a well defined behavior.
+
* The ``pyvenv`` script has been removed in favor of ``python3.8 -m venv``
to help eliminate confusion as to what Python interpreter the ``pyvenv``
script is tied to. (Contributed by Brett Cannon in :issue:`25427`.)
From 8da5ebe11e0cb6599af682b22f7c2b2b7b9debd8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Anders=20Hovm=C3=B6ller?=
Date: Mon, 13 May 2019 21:27:17 +0200
Subject: [PATCH 039/199] bpo-35138: Added an example for timeit.timeit with
callable arguments (GH-9787)
* Update timeit.rst
---
Doc/library/timeit.rst | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst
index 8ca37034f79..ef7a4e40be6 100644
--- a/Doc/library/timeit.rst
+++ b/Doc/library/timeit.rst
@@ -44,8 +44,12 @@ This can be achieved from the :ref:`python-interface` with::
>>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)
0.23702679807320237
+A callable can also be passed from the :ref:`python-interface`::
-Note however that :mod:`timeit` will automatically determine the number of
+ >>> timeit.timeit(lambda: "-".join(map(str, range(100))), number=10000)
+ 0.19665591977536678
+
+Note however that :func:`.timeit` will automatically determine the number of
repetitions only when the command-line interface is used. In the
:ref:`timeit-examples` section you can find more advanced examples.
From 45b2f8893c1b7ab3b3981a966f82e42beea82106 Mon Sep 17 00:00:00 2001
From: Jens Troeger
Date: Tue, 14 May 2019 11:07:39 +1000
Subject: [PATCH 040/199] bpo-34424: Handle different policy.linesep lengths
correctly. (#8803)
---
Lib/email/_header_value_parser.py | 2 +-
Lib/test/test_email/test_generator.py | 22 +++++++++++++++++++
.../2018-08-18-14-47-00.bpo-34424.wAlRuS.rst | 2 ++
3 files changed, 25 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Library/2018-08-18-14-47-00.bpo-34424.wAlRuS.rst
diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py
index 922daa2560f..bb26d5a556d 100644
--- a/Lib/email/_header_value_parser.py
+++ b/Lib/email/_header_value_parser.py
@@ -2625,7 +2625,7 @@ def _refold_parse_tree(parse_tree, *, policy):
want_encoding = False
last_ew = None
if part.syntactic_break:
- encoded_part = part.fold(policy=policy)[:-1] # strip nl
+ encoded_part = part.fold(policy=policy)[:-len(policy.linesep)]
if policy.linesep not in encoded_part:
# It fits on a single line
if len(encoded_part) > maxlen - len(lines[-1]):
diff --git a/Lib/test/test_email/test_generator.py b/Lib/test/test_email/test_generator.py
index c1aeaefab77..89e7edeb63a 100644
--- a/Lib/test/test_email/test_generator.py
+++ b/Lib/test/test_email/test_generator.py
@@ -4,6 +4,7 @@
from email import message_from_string, message_from_bytes
from email.message import EmailMessage
from email.generator import Generator, BytesGenerator
+from email.headerregistry import Address
from email import policy
from test.test_email import TestEmailBase, parameterize
@@ -291,6 +292,27 @@ def test_smtputf8_policy(self):
g.flatten(msg)
self.assertEqual(s.getvalue(), expected)
+ def test_smtp_policy(self):
+ msg = EmailMessage()
+ msg["From"] = Address(addr_spec="foo@bar.com", display_name="Páolo")
+ msg["To"] = Address(addr_spec="bar@foo.com", display_name="Dinsdale")
+ msg["Subject"] = "Nudge nudge, wink, wink"
+ msg.set_content("oh boy, know what I mean, know what I mean?")
+ expected = textwrap.dedent("""\
+ From: =?utf-8?q?P=C3=A1olo?=
+ To: Dinsdale
+ Subject: Nudge nudge, wink, wink
+ Content-Type: text/plain; charset="utf-8"
+ Content-Transfer-Encoding: 7bit
+ MIME-Version: 1.0
+
+ oh boy, know what I mean, know what I mean?
+ """).encode().replace(b"\n", b"\r\n")
+ s = io.BytesIO()
+ g = BytesGenerator(s, policy=policy.SMTP)
+ g.flatten(msg)
+ self.assertEqual(s.getvalue(), expected)
+
if __name__ == '__main__':
unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2018-08-18-14-47-00.bpo-34424.wAlRuS.rst b/Misc/NEWS.d/next/Library/2018-08-18-14-47-00.bpo-34424.wAlRuS.rst
new file mode 100644
index 00000000000..2b384cd5513
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-08-18-14-47-00.bpo-34424.wAlRuS.rst
@@ -0,0 +1,2 @@
+Fix serialization of messages containing encoded strings when the
+policy.linesep is set to a multi-character string. Patch by Jens Troeger.
From 1a10a6b980dbddb59a054f273dbd97ea5e7ccda4 Mon Sep 17 00:00:00 2001
From: wim glenn
Date: Mon, 13 May 2019 20:10:14 -0500
Subject: [PATCH 041/199] Simplify the ``LastUpdatedOrderedDict`` example
recipe (GH-13296)
---
Doc/library/collections.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index 64de970fec9..e0469c20810 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -1141,7 +1141,7 @@ original insertion position is changed and moved to the end::
def __setitem__(self, key, value):
super().__setitem__(key, value)
- super().move_to_end(key)
+ self.move_to_end(key)
An :class:`OrderedDict` would also be useful for implementing
variants of :func:`functools.lru_cache`::
From c923c3449f825021b13521b2380e67ba35a36f55 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Tue, 14 May 2019 03:47:32 +0200
Subject: [PATCH 042/199] bpo-36719: Fix regrtest MultiprocessThread (GH-13301)
MultiprocessThread.kill() now closes stdout and stderr to prevent
popen.communicate() to hang.
---
Lib/test/libregrtest/runtest_mp.py | 59 ++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 4 deletions(-)
diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py
index ced7f866a89..42178471ef1 100644
--- a/Lib/test/libregrtest/runtest_mp.py
+++ b/Lib/test/libregrtest/runtest_mp.py
@@ -21,6 +21,9 @@
# Display the running tests if nothing happened last N seconds
PROGRESS_UPDATE = 30.0 # seconds
+# Time to wait until a worker completes: should be immediate
+JOIN_TIMEOUT = 30.0 # seconds
+
def must_stop(result, ns):
if result.result == INTERRUPTED:
@@ -91,6 +94,10 @@ def stop(self):
MultiprocessResult = collections.namedtuple('MultiprocessResult',
'result stdout stderr error_msg')
+class ExitThread(Exception):
+ pass
+
+
class MultiprocessThread(threading.Thread):
def __init__(self, pending, output, ns):
super().__init__()
@@ -100,13 +107,31 @@ def __init__(self, pending, output, ns):
self.current_test_name = None
self.start_time = None
self._popen = None
+ self._killed = False
+
+ def __repr__(self):
+ info = ['MultiprocessThread']
+ test = self.current_test_name
+ if self.is_alive():
+ info.append('alive')
+ if test:
+ info.append(f'test={test}')
+ popen = self._popen
+ if popen:
+ info.append(f'pid={popen.pid}')
+ return '<%s>' % ' '.join(info)
def kill(self):
+ self._killed = True
+
popen = self._popen
if popen is None:
return
- print("Kill regrtest worker process %s" % popen.pid)
popen.kill()
+ # stdout and stderr must be closed to ensure that communicate()
+ # does not hang
+ popen.stdout.close()
+ popen.stderr.close()
def _runtest(self, test_name):
try:
@@ -117,7 +142,21 @@ def _runtest(self, test_name):
popen = self._popen
with popen:
try:
- stdout, stderr = popen.communicate()
+ if self._killed:
+ # If kill() has been called before self._popen is set,
+ # self._popen is still running. Call again kill()
+ # to ensure that the process is killed.
+ self.kill()
+ raise ExitThread
+
+ try:
+ stdout, stderr = popen.communicate()
+ except OSError:
+ if self._killed:
+ # kill() has been called: communicate() fails
+ # on reading closed stdout/stderr
+ raise ExitThread
+ raise
except:
self.kill()
popen.wait()
@@ -154,7 +193,7 @@ def _runtest(self, test_name):
return MultiprocessResult(result, stdout, stderr, err_msg)
def run(self):
- while True:
+ while not self._killed:
try:
try:
test_name = next(self.pending)
@@ -166,6 +205,8 @@ def run(self):
if must_stop(mp_result.result, self.ns):
break
+ except ExitThread:
+ break
except BaseException:
self.output.put((True, traceback.format_exc()))
break
@@ -205,10 +246,20 @@ def start_workers(self):
worker.start()
def wait_workers(self):
+ start_time = time.monotonic()
for worker in self.workers:
worker.kill()
for worker in self.workers:
- worker.join()
+ while True:
+ worker.join(1.0)
+ if not worker.is_alive():
+ break
+ dt = time.monotonic() - start_time
+ print("Wait for regrtest worker %r for %.1f sec" % (worker, dt))
+ if dt > JOIN_TIMEOUT:
+ print("Warning -- failed to join a regrtest worker %s"
+ % worker)
+ break
def _get_result(self):
if not any(worker.is_alive() for worker in self.workers):
From f0be4bbb9b3cee876249c23f2ae6f38f43fa7495 Mon Sep 17 00:00:00 2001
From: Inada Naoki
Date: Tue, 14 May 2019 18:51:15 +0900
Subject: [PATCH 043/199] bpo-27987: pymalloc: align by 16bytes on 64bit
platform (GH-12850)
---
.../2019-04-16-11-52-21.bpo-27987.n2_DcQ.rst | 3 +++
Objects/obmalloc.c | 6 ++++++
2 files changed, 9 insertions(+)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-04-16-11-52-21.bpo-27987.n2_DcQ.rst
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-04-16-11-52-21.bpo-27987.n2_DcQ.rst b/Misc/NEWS.d/next/Core and Builtins/2019-04-16-11-52-21.bpo-27987.n2_DcQ.rst
new file mode 100644
index 00000000000..b0f32a5c6c3
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-04-16-11-52-21.bpo-27987.n2_DcQ.rst
@@ -0,0 +1,3 @@
+pymalloc returns memory blocks aligned by 16 bytes, instead of 8 bytes, on
+64-bit platforms to conform x86-64 ABI. Recent compilers assume this alignment
+more often. Patch by Inada Naoki.
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index 7cfd2896596..bd15bcf1363 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -795,8 +795,14 @@ static int running_on_valgrind = -1;
*
* You shouldn't change this unless you know what you are doing.
*/
+
+#if SIZEOF_VOID_P > 4
+#define ALIGNMENT 16 /* must be 2^N */
+#define ALIGNMENT_SHIFT 4
+#else
#define ALIGNMENT 8 /* must be 2^N */
#define ALIGNMENT_SHIFT 3
+#endif
/* Return the number of bytes in size class I, as a uint. */
#define INDEX2SIZE(I) (((uint)(I) + 1) << ALIGNMENT_SHIFT)
From 5e48e3db6f5a937023e99d89cef8884d22bd8533 Mon Sep 17 00:00:00 2001
From: Nicolai Moore
Date: Tue, 14 May 2019 20:32:59 +1000
Subject: [PATCH 044/199] bpo-36845: validate integer network prefix when
constructing IP networks (GH-13298)
---
Lib/ipaddress.py | 4 ++++
Lib/test/test_ipaddress.py | 16 ++++++++++++++++
Misc/ACKS | 1 +
.../2019-05-14-07-57-02.bpo-36845._GtFFf.rst | 2 ++
4 files changed, 23 insertions(+)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-14-07-57-02.bpo-36845._GtFFf.rst
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index 662d7373890..873c7644081 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1108,6 +1108,8 @@ def _make_netmask(cls, arg):
if arg not in cls._netmask_cache:
if isinstance(arg, int):
prefixlen = arg
+ if not (0 <= prefixlen <= cls._max_prefixlen):
+ cls._report_invalid_netmask(prefixlen)
else:
try:
# Check for a netmask in prefix length form
@@ -1538,6 +1540,8 @@ def _make_netmask(cls, arg):
if arg not in cls._netmask_cache:
if isinstance(arg, int):
prefixlen = arg
+ if not (0 <= prefixlen <= cls._max_prefixlen):
+ cls._report_invalid_netmask(prefixlen)
else:
prefixlen = cls._prefix_from_prefix_string(arg)
netmask = IPv6Address(cls._ip_int_from_prefix(prefixlen))
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
index 20316f15f8c..9e17ea0c7aa 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -466,6 +466,14 @@ def assertBadNetmask(addr, netmask):
assertBadNetmask("1.1.1.1", "pudding")
assertBadNetmask("1.1.1.1", "::")
+ def test_netmask_in_tuple_errors(self):
+ def assertBadNetmask(addr, netmask):
+ msg = "%r is not a valid netmask" % netmask
+ with self.assertNetmaskError(re.escape(msg)):
+ self.factory((addr, netmask))
+ assertBadNetmask("1.1.1.1", -1)
+ assertBadNetmask("1.1.1.1", 33)
+
def test_pickle(self):
self.pickle_test('192.0.2.0/27')
self.pickle_test('192.0.2.0/31') # IPV4LENGTH - 1
@@ -588,6 +596,14 @@ def assertBadNetmask(addr, netmask):
assertBadNetmask("::1", "pudding")
assertBadNetmask("::", "::")
+ def test_netmask_in_tuple_errors(self):
+ def assertBadNetmask(addr, netmask):
+ msg = "%r is not a valid netmask" % netmask
+ with self.assertNetmaskError(re.escape(msg)):
+ self.factory((addr, netmask))
+ assertBadNetmask("::1", -1)
+ assertBadNetmask("::1", 129)
+
def test_pickle(self):
self.pickle_test('2001:db8::1000/124')
self.pickle_test('2001:db8::1000/127') # IPV6LENGTH - 1
diff --git a/Misc/ACKS b/Misc/ACKS
index dfb96375360..ec5b017d515 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1108,6 +1108,7 @@ Bastien Montagne
Skip Montanaro
Peter Moody
Alan D. Moore
+Nicolai Moore
Paul Moore
Ross Moore
Ben Morgan
diff --git a/Misc/NEWS.d/next/Library/2019-05-14-07-57-02.bpo-36845._GtFFf.rst b/Misc/NEWS.d/next/Library/2019-05-14-07-57-02.bpo-36845._GtFFf.rst
new file mode 100644
index 00000000000..c819dce3a57
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-14-07-57-02.bpo-36845._GtFFf.rst
@@ -0,0 +1,2 @@
+Added validation of integer prefixes to the construction of IP networks and
+interfaces in the ipaddress module.
From 0a52d73ddeeac23f73c919d636e7008ddde5c72b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Wirtel?=
Date: Tue, 14 May 2019 13:49:49 +0200
Subject: [PATCH 045/199] Doc: Update pip and setuptools when creating the
virtual environment (GH-13307)
Add a new pip install before `sphinx` etc.. because we should use the last version of `pip` and `setuptools`
---
Doc/Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/Doc/Makefile b/Doc/Makefile
index cf1bb88b0b8..6f86728ea83 100644
--- a/Doc/Makefile
+++ b/Doc/Makefile
@@ -132,6 +132,7 @@ clean:
venv:
$(PYTHON) -m venv $(VENVDIR)
+ $(VENVDIR)/bin/python3 -m pip install -U pip setuptools
$(VENVDIR)/bin/python3 -m pip install -U Sphinx blurb python-docs-theme
@echo "The venv has been created in the $(VENVDIR) directory"
From dae1229729920e3aa2be015453b7f702dff9b375 Mon Sep 17 00:00:00 2001
From: Nick Coghlan
Date: Tue, 14 May 2019 22:04:30 +1000
Subject: [PATCH 046/199] bpo-36797: Prune more legacy distutils documentation
(GH-13092)
Removes more legacy distutils documentation, and more clearly
marks what is left as potentially outdated, with references to
setuptools as a replacement.
---
Doc/distutils/_setuptools_disclaimer.rst | 5 ++
Doc/distutils/apiref.rst | 10 +++
Doc/distutils/builtdist.rst | 2 +
Doc/distutils/commandref.rst | 2 +
Doc/distutils/configfile.rst | 2 +
Doc/distutils/examples.rst | 2 +
Doc/distutils/extending.rst | 2 +
Doc/distutils/index.rst | 10 ++-
Doc/distutils/introduction.rst | 2 +
Doc/distutils/setupscript.rst | 2 +
Doc/distutils/sourcedist.rst | 2 +
Doc/install/index.rst | 80 ++++---------------
Doc/tools/susp-ignored.csv | 2 +-
.../2019-05-05-07-58-50.bpo-36797.W1X4On.rst | 3 +
14 files changed, 58 insertions(+), 68 deletions(-)
create mode 100644 Doc/distutils/_setuptools_disclaimer.rst
create mode 100644 Misc/NEWS.d/next/Documentation/2019-05-05-07-58-50.bpo-36797.W1X4On.rst
diff --git a/Doc/distutils/_setuptools_disclaimer.rst b/Doc/distutils/_setuptools_disclaimer.rst
new file mode 100644
index 00000000000..cc75858326d
--- /dev/null
+++ b/Doc/distutils/_setuptools_disclaimer.rst
@@ -0,0 +1,5 @@
+.. note::
+
+ This document is being retained solely until the ``setuptools`` documentation
+ at https://setuptools.readthedocs.io/en/latest/setuptools.html
+ independently covers all of the relevant information currently included here.
diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst
index 1facc0408d5..cbeedab5bb1 100644
--- a/Doc/distutils/apiref.rst
+++ b/Doc/distutils/apiref.rst
@@ -4,6 +4,16 @@
API Reference
*************
+.. seealso::
+
+ `New and changed setup.py arguments in setuptools `_
+ The ``setuptools`` project adds new capabilities to the ``setup`` function
+ and other APIs, makes the API consistent across different Python versions,
+ and is hence recommended over using ``distutils`` directly.
+
+.. _setuptools-setup-py: https://setuptools.readthedocs.io/en/latest/setuptools.html#new-and-changed-setup-keywords
+
+.. include:: ./_setuptools_disclaimer.rst
:mod:`distutils.core` --- Core Distutils functionality
======================================================
diff --git a/Doc/distutils/builtdist.rst b/Doc/distutils/builtdist.rst
index f1f34712616..f44d0d039f4 100644
--- a/Doc/distutils/builtdist.rst
+++ b/Doc/distutils/builtdist.rst
@@ -4,6 +4,8 @@
Creating Built Distributions
****************************
+.. include:: ./_setuptools_disclaimer.rst
+
A "built distribution" is what you're probably used to thinking of either as a
"binary package" or an "installer" (depending on your background). It's not
necessarily binary, though, because it might contain only Python source code
diff --git a/Doc/distutils/commandref.rst b/Doc/distutils/commandref.rst
index 6a2ac960f1e..0f6fe2aba86 100644
--- a/Doc/distutils/commandref.rst
+++ b/Doc/distutils/commandref.rst
@@ -4,6 +4,8 @@
Command Reference
*****************
+.. include:: ./_setuptools_disclaimer.rst
+
.. % \section{Building modules: the \protect\command{build} command family}
.. % \label{build-cmds}
.. % \subsubsection{\protect\command{build}}
diff --git a/Doc/distutils/configfile.rst b/Doc/distutils/configfile.rst
index 0874d05fe70..2a5c8329e31 100644
--- a/Doc/distutils/configfile.rst
+++ b/Doc/distutils/configfile.rst
@@ -4,6 +4,8 @@
Writing the Setup Configuration File
************************************
+.. include:: ./_setuptools_disclaimer.rst
+
Often, it's not possible to write down everything needed to build a distribution
*a priori*: you may need to get some information from the user, or from the
user's system, in order to proceed. As long as that information is fairly
diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst
index f81e06b5e60..4ac552c7c69 100644
--- a/Doc/distutils/examples.rst
+++ b/Doc/distutils/examples.rst
@@ -4,6 +4,8 @@
Examples
********
+.. include:: ./_setuptools_disclaimer.rst
+
This chapter provides a number of basic examples to help get started with
distutils. Additional information about using distutils can be found in the
Distutils Cookbook.
diff --git a/Doc/distutils/extending.rst b/Doc/distutils/extending.rst
index 501fd7c564c..1075e81779a 100644
--- a/Doc/distutils/extending.rst
+++ b/Doc/distutils/extending.rst
@@ -4,6 +4,8 @@
Extending Distutils
*******************
+.. include:: ./_setuptools_disclaimer.rst
+
Distutils can be extended in various ways. Most extensions take the form of new
commands or replacements for existing commands. New commands may be written to
support new types of platform-specific packaging, for example, while
diff --git a/Doc/distutils/index.rst b/Doc/distutils/index.rst
index d6f7640fcb6..c56fafd68d8 100644
--- a/Doc/distutils/index.rst
+++ b/Doc/distutils/index.rst
@@ -12,10 +12,7 @@
:ref:`distributing-index`
The up to date module distribution documentations
-This document describes the Python Distribution Utilities ("Distutils") from
-the module developer's point of view, describing how to use the Distutils to
-make Python modules and extensions easily available to a wider audience with
-very little overhead for build/release/install mechanics.
+.. include:: ./_setuptools_disclaimer.rst
.. note::
@@ -25,6 +22,11 @@ very little overhead for build/release/install mechanics.
recommendations section `__
in the Python Packaging User Guide for more information.
+This document describes the Python Distribution Utilities ("Distutils") from
+the module developer's point of view, describing the underlying capabilities
+that ``setuptools`` builds on to allow Python developers to make Python modules
+and extensions readily available to a wider audience.
+
.. toctree::
:maxdepth: 2
:numbered:
diff --git a/Doc/distutils/introduction.rst b/Doc/distutils/introduction.rst
index 7721484fe73..1f8a560e138 100644
--- a/Doc/distutils/introduction.rst
+++ b/Doc/distutils/introduction.rst
@@ -4,6 +4,8 @@
An Introduction to Distutils
****************************
+.. include:: ./_setuptools_disclaimer.rst
+
This document covers using the Distutils to distribute your Python modules,
concentrating on the role of developer/distributor: if you're looking for
information on installing Python modules, you should refer to the
diff --git a/Doc/distutils/setupscript.rst b/Doc/distutils/setupscript.rst
index 1f99f62f6af..4386a60b664 100644
--- a/Doc/distutils/setupscript.rst
+++ b/Doc/distutils/setupscript.rst
@@ -4,6 +4,8 @@
Writing the Setup Script
************************
+.. include:: ./_setuptools_disclaimer.rst
+
The setup script is the centre of all activity in building, distributing, and
installing modules using the Distutils. The main purpose of the setup script is
to describe your module distribution to the Distutils, so that the various
diff --git a/Doc/distutils/sourcedist.rst b/Doc/distutils/sourcedist.rst
index 0ac8ef41ddc..0600663d00e 100644
--- a/Doc/distutils/sourcedist.rst
+++ b/Doc/distutils/sourcedist.rst
@@ -4,6 +4,8 @@
Creating a Source Distribution
******************************
+.. include:: ./_setuptools_disclaimer.rst
+
As shown in section :ref:`distutils-simple-example`, you use the :command:`sdist` command
to create a source distribution. In the simplest case, ::
diff --git a/Doc/install/index.rst b/Doc/install/index.rst
index f6a8cd6833a..e14232415be 100644
--- a/Doc/install/index.rst
+++ b/Doc/install/index.rst
@@ -13,23 +13,10 @@
.. seealso::
:ref:`installing-index`
- The up to date module installation documentations
-
-.. The audience for this document includes people who don't know anything
- about Python and aren't about to learn the language just in order to
- install and maintain it for their users, i.e. system administrators.
- Thus, I have to be sure to explain the basics at some point:
- sys.path and PYTHONPATH at least. Should probably give pointers to
- other docs on "import site", PYTHONSTARTUP, PYTHONHOME, etc.
-
- Finally, it might be useful to include all the material from my "Care
- and Feeding of a Python Installation" talk in here somewhere. Yow!
-
-This document describes the Python Distribution Utilities ("Distutils") from the
-end-user's point-of-view, describing how to extend the capabilities of a
-standard Python installation by building and installing third-party Python
-modules and extensions.
+ The up to date module installation documentation. For regular Python
+ usage, you almost certainly want that document rather than this one.
+.. include:: ../distutils/_setuptools_disclaimer.rst
.. note::
@@ -46,59 +33,26 @@ modules and extensions.
Introduction
============
-Although Python's extensive standard library covers many programming needs,
-there often comes a time when you need to add some new functionality to your
-Python installation in the form of third-party modules. This might be necessary
-to support your own programming, or to support an application that you want to
-use and that happens to be written in Python.
+In Python 2.0, the ``distutils`` API was first added to the standard library.
+This provided Linux distro maintainers with a standard way of converting
+Python projects into Linux distro packages, and system administrators with a
+standard way of installing them directly onto target systems.
-In the past, there has been little support for adding third-party modules to an
-existing Python installation. With the introduction of the Python Distribution
-Utilities (Distutils for short) in Python 2.0, this changed.
+In the many years since Python 2.0 was released, tightly coupling the build
+system and package installer to the language runtime release cycle has turned
+out to be problematic, and it is now recommended that projects use the
+``pip`` package installer and the ``setuptools`` build system, rather than
+using ``distutils`` directly.
-This document is aimed primarily at the people who need to install third-party
-Python modules: end-users and system administrators who just need to get some
-Python application running, and existing Python programmers who want to add some
-new goodies to their toolbox. You don't need to know Python to read this
-document; there will be some brief forays into using Python's interactive mode
-to explore your installation, but that's it. If you're looking for information
-on how to distribute your own Python modules so that others may use them, see
-the :ref:`distutils-index` manual. :ref:`debug-setup-script` may also be of
-interest.
-
-
-.. _inst-trivial-install:
-
-Best case: trivial installation
--------------------------------
-
-In the best case, someone will have prepared a special version of the module
-distribution you want to install that is targeted specifically at your platform
-and is installed just like any other software on your platform. For example,
-the module developer might make an executable installer available for Windows
-users, an RPM package for users of RPM-based Linux systems (Red Hat, SuSE,
-Mandrake, and many others), a Debian package for users of Debian-based Linux
-systems, and so forth.
-
-In that case, you would download the installer appropriate to your platform and
-do the obvious thing with it: run it if it's an executable installer, ``rpm
---install`` it if it's an RPM, etc. You don't need to run Python or a setup
-script, you don't need to compile anything---you might not even need to read any
-instructions (although it's always a good idea to do so anyway).
-
-Of course, things will not always be that easy. You might be interested in a
-module distribution that doesn't have an easy-to-use installer for your
-platform. In that case, you'll have to start with the source distribution
-released by the module's author/maintainer. Installing from a source
-distribution is not too hard, as long as the modules are packaged in the
-standard way. The bulk of this document is about building and installing
-modules from standard source distributions.
+See :ref:`installing-index` and :ref:`distributing-index` for more details.
+This legacy documentation is being retained only until we're confident that the
+``setuptools`` documentation covers everything needed.
.. _inst-new-standard:
-The new standard: Distutils
----------------------------
+Distutils based source distributions
+------------------------------------
If you download a module source distribution, you can tell pretty quickly if it
was packaged and distributed in the standard way, i.e. using the Distutils.
diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv
index 3672955bf55..31b22665eca 100644
--- a/Doc/tools/susp-ignored.csv
+++ b/Doc/tools/susp-ignored.csv
@@ -4,7 +4,7 @@ c-api/sequence,,:i2,del o[i1:i2]
c-api/sequence,,:i2,o[i1:i2]
c-api/unicode,,:end,str[start:end]
c-api/unicode,,:start,unicode[start:start+length]
-distutils/examples,267,`,This is the description of the ``foobar`` package.
+distutils/examples,274,`,This is the description of the ``foobar`` package.
distutils/setupscript,,::,
extending/embedding,,:numargs,"if(!PyArg_ParseTuple(args, "":numargs""))"
extending/extending,,:myfunction,"PyArg_ParseTuple(args, ""D:myfunction"", &c);"
diff --git a/Misc/NEWS.d/next/Documentation/2019-05-05-07-58-50.bpo-36797.W1X4On.rst b/Misc/NEWS.d/next/Documentation/2019-05-05-07-58-50.bpo-36797.W1X4On.rst
new file mode 100644
index 00000000000..5ca55556c88
--- /dev/null
+++ b/Misc/NEWS.d/next/Documentation/2019-05-05-07-58-50.bpo-36797.W1X4On.rst
@@ -0,0 +1,3 @@
+More of the legacy distutils documentation has been either pruned, or else
+more clearly marked as being retained solely until the setuptools
+documentation covers it independently.
From c0a1a07c7e9814cad79cce3580c16284b2df7f52 Mon Sep 17 00:00:00 2001
From: Vinodhini Balusamy
Date: Tue, 14 May 2019 22:11:41 +1000
Subject: [PATCH 047/199] bpo-32995 - Added context variable in glossary
(GH-9741)
---
Doc/glossary.rst | 9 +++++++++
.../2018-10-07-03-04-57.bpo-32995.TXN9ur.rst | 1 +
2 files changed, 10 insertions(+)
create mode 100644 Misc/NEWS.d/next/Documentation/2018-10-07-03-04-57.bpo-32995.TXN9ur.rst
diff --git a/Doc/glossary.rst b/Doc/glossary.rst
index 9c64e488631..d3ce3652551 100644
--- a/Doc/glossary.rst
+++ b/Doc/glossary.rst
@@ -225,6 +225,15 @@ Glossary
statement by defining :meth:`__enter__` and :meth:`__exit__` methods.
See :pep:`343`.
+ context variable
+ A variable which can have different values depending on its context.
+ This is similar to Thread-Local Storage in which each execution
+ thread may have a different value for a variable. However, with context
+ variables, there may be several contexts in one execution thread and the
+ main usage for context variables is to keep track of variables in
+ concurrent asynchronous tasks.
+ See :mod:`contextvars`.
+
contiguous
.. index:: C-contiguous, Fortran contiguous
diff --git a/Misc/NEWS.d/next/Documentation/2018-10-07-03-04-57.bpo-32995.TXN9ur.rst b/Misc/NEWS.d/next/Documentation/2018-10-07-03-04-57.bpo-32995.TXN9ur.rst
new file mode 100644
index 00000000000..1df5eeaa965
--- /dev/null
+++ b/Misc/NEWS.d/next/Documentation/2018-10-07-03-04-57.bpo-32995.TXN9ur.rst
@@ -0,0 +1 @@
+Added the context variable in glossary.
From 2bc158fefe89db8dfdd6d03ae6b3f2caa2f0cd6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?=
Date: Tue, 14 May 2019 15:45:14 +0200
Subject: [PATCH 048/199] Change WriterObj.writeline to WriterObj.write
(GH-12344)
This cleans the csv module a bit, I don't think it requires a bpo issue or a news entry.
---
Modules/_csv.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/Modules/_csv.c b/Modules/_csv.c
index d86f63ef597..e31b158c601 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -111,7 +111,7 @@ static PyTypeObject Reader_Type;
typedef struct {
PyObject_HEAD
- PyObject *writeline; /* write output lines to this file */
+ PyObject *write; /* write output lines to this file */
DialectObj *dialect; /* parsing dialect */
@@ -1231,14 +1231,16 @@ csv_writerow(WriterObj *self, PyObject *seq)
/* Add line terminator.
*/
- if (!join_append_lineterminator(self))
+ if (!join_append_lineterminator(self)) {
return NULL;
+ }
line = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND,
(void *) self->rec, self->rec_len);
- if (line == NULL)
+ if (line == NULL) {
return NULL;
- result = PyObject_CallFunctionObjArgs(self->writeline, line, NULL);
+ }
+ result = PyObject_CallFunctionObjArgs(self->write, line, NULL);
Py_DECREF(line);
return result;
}
@@ -1294,7 +1296,7 @@ Writer_dealloc(WriterObj *self)
{
PyObject_GC_UnTrack(self);
Py_XDECREF(self->dialect);
- Py_XDECREF(self->writeline);
+ Py_XDECREF(self->write);
if (self->rec != NULL)
PyMem_Free(self->rec);
PyObject_GC_Del(self);
@@ -1304,7 +1306,7 @@ static int
Writer_traverse(WriterObj *self, visitproc visit, void *arg)
{
Py_VISIT(self->dialect);
- Py_VISIT(self->writeline);
+ Py_VISIT(self->write);
return 0;
}
@@ -1312,7 +1314,7 @@ static int
Writer_clear(WriterObj *self)
{
Py_CLEAR(self->dialect);
- Py_CLEAR(self->writeline);
+ Py_CLEAR(self->write);
return 0;
}
@@ -1369,7 +1371,7 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
return NULL;
self->dialect = NULL;
- self->writeline = NULL;
+ self->write = NULL;
self->rec = NULL;
self->rec_size = 0;
@@ -1380,8 +1382,8 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
Py_DECREF(self);
return NULL;
}
- self->writeline = _PyObject_GetAttrId(output_file, &PyId_write);
- if (self->writeline == NULL || !PyCallable_Check(self->writeline)) {
+ self->write = _PyObject_GetAttrId(output_file, &PyId_write);
+ if (self->write == NULL || !PyCallable_Check(self->write)) {
PyErr_SetString(PyExc_TypeError,
"argument 1 must have a \"write\" method");
Py_DECREF(self);
From 3c93153f7db5dd9b06f229e61978fd9199b3c097 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Tue, 14 May 2019 15:49:16 +0200
Subject: [PATCH 049/199] bpo-36915: regrtest always remove tempdir of worker
processes (GH-13312)
When using multiprocessing (-jN option), worker processes now create
their temporary directory inside the temporary directory of the
main process. So the main process is able to remove temporary
directories of worker processes even if they crash or when they are
killed by regrtest on KeyboardInterrupt (CTRL+c).
Rework also how multiprocessing arguments are parsed in main.py.
---
Lib/test/libregrtest/main.py | 90 +++++++++++--------
Lib/test/libregrtest/runtest_mp.py | 20 +++--
.../2019-05-14-14-12-24.bpo-36915.58b7pH.rst | 3 +
3 files changed, 69 insertions(+), 44 deletions(-)
create mode 100644 Misc/NEWS.d/next/Tests/2019-05-14-14-12-24.bpo-36915.58b7pH.rst
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index 02717d8c7b1..a9b2b352d12 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -1,6 +1,5 @@
import datetime
import faulthandler
-import json
import locale
import os
import platform
@@ -22,22 +21,6 @@
from test import support
-# When tests are run from the Python build directory, it is best practice
-# to keep the test files in a subfolder. This eases the cleanup of leftover
-# files using the "make distclean" command.
-if sysconfig.is_python_build():
- TEMPDIR = sysconfig.get_config_var('abs_builddir')
- if TEMPDIR is None:
- # bpo-30284: On Windows, only srcdir is available. Using abs_builddir
- # mostly matters on UNIX when building Python out of the source tree,
- # especially when the source tree is read only.
- TEMPDIR = sysconfig.get_config_var('srcdir')
- TEMPDIR = os.path.join(TEMPDIR, 'build')
-else:
- TEMPDIR = tempfile.gettempdir()
-TEMPDIR = os.path.abspath(TEMPDIR)
-
-
class Regrtest:
"""Execute a test suite.
@@ -98,7 +81,10 @@ def __init__(self):
# used by --junit-xml
self.testsuite_xml = None
+ # misc
self.win_load_tracker = None
+ self.tmp_dir = None
+ self.worker_test_name = None
def get_executed(self):
return (set(self.good) | set(self.bad) | set(self.skipped)
@@ -177,6 +163,13 @@ def parse_args(self, kwargs):
if ns.xmlpath:
support.junit_xml_list = self.testsuite_xml = []
+ worker_args = ns.worker_args
+ if worker_args is not None:
+ from test.libregrtest.runtest_mp import parse_worker_args
+ ns, test_name = parse_worker_args(ns.worker_args)
+ ns.worker_args = worker_args
+ self.worker_test_name = test_name
+
# Strip .py extensions.
removepy(ns.args)
@@ -186,7 +179,7 @@ def find_tests(self, tests):
self.tests = tests
if self.ns.single:
- self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
+ self.next_single_filename = os.path.join(self.tmp_dir, 'pynexttest')
try:
with open(self.next_single_filename, 'r') as fp:
next_test = fp.read().strip()
@@ -544,29 +537,54 @@ def save_xml_result(self):
for s in ET.tostringlist(root):
f.write(s)
- def main(self, tests=None, **kwargs):
- global TEMPDIR
- self.ns = self.parse_args(kwargs)
-
+ def create_temp_dir(self):
if self.ns.tempdir:
- TEMPDIR = self.ns.tempdir
- elif self.ns.worker_args:
- ns_dict, _ = json.loads(self.ns.worker_args)
- TEMPDIR = ns_dict.get("tempdir") or TEMPDIR
+ self.tmp_dir = self.ns.tempdir
- os.makedirs(TEMPDIR, exist_ok=True)
+ if not self.tmp_dir:
+ # When tests are run from the Python build directory, it is best practice
+ # to keep the test files in a subfolder. This eases the cleanup of leftover
+ # files using the "make distclean" command.
+ if sysconfig.is_python_build():
+ self.tmp_dir = sysconfig.get_config_var('abs_builddir')
+ if self.tmp_dir is None:
+ # bpo-30284: On Windows, only srcdir is available. Using
+ # abs_builddir mostly matters on UNIX when building Python
+ # out of the source tree, especially when the source tree
+ # is read only.
+ self.tmp_dir = sysconfig.get_config_var('srcdir')
+ self.tmp_dir = os.path.join(self.tmp_dir, 'build')
+ else:
+ self.tmp_dir = tempfile.gettempdir()
+
+ self.tmp_dir = os.path.abspath(self.tmp_dir)
+ os.makedirs(self.tmp_dir, exist_ok=True)
# Define a writable temp dir that will be used as cwd while running
# the tests. The name of the dir includes the pid to allow parallel
# testing (see the -j option).
- test_cwd = 'test_python_{}'.format(os.getpid())
- test_cwd = os.path.join(TEMPDIR, test_cwd)
+ pid = os.getpid()
+ if self.worker_test_name is not None:
+ test_cwd = 'worker_{}'.format(pid)
+ else:
+ test_cwd = 'test_python_{}'.format(pid)
+ test_cwd = os.path.join(self.tmp_dir, test_cwd)
+ return test_cwd
- # Run the tests in a context manager that temporarily changes the CWD to a
- # temporary and writable directory. If it's not possible to create or
- # change the CWD, the original CWD will be used. The original CWD is
- # available from support.SAVEDCWD.
+ def main(self, tests=None, **kwargs):
+ self.ns = self.parse_args(kwargs)
+
+ test_cwd = self.create_temp_dir()
+
+ # Run the tests in a context manager that temporarily changes the CWD
+ # to a temporary and writable directory. If it's not possible to
+ # create or change the CWD, the original CWD will be used.
+ # The original CWD is available from support.SAVEDCWD.
with support.temp_cwd(test_cwd, quiet=True):
+ # When using multiprocessing, worker processes will use test_cwd
+ # as their parent temporary directory. So when the main process
+ # exit, it removes also subdirectories of worker processes.
+ self.ns.tempdir = test_cwd
self._main(tests, kwargs)
def getloadavg(self):
@@ -588,9 +606,9 @@ def _main(self, tests, kwargs):
print(msg, file=sys.stderr, flush=True)
sys.exit(2)
- if self.ns.worker_args is not None:
+ if self.worker_test_name is not None:
from test.libregrtest.runtest_mp import run_tests_worker
- run_tests_worker(self.ns.worker_args)
+ run_tests_worker(self.ns, self.worker_test_name)
if self.ns.wait:
input("Press any key to continue...")
@@ -611,7 +629,7 @@ def _main(self, tests, kwargs):
# If we're on windows and this is the parent runner (not a worker),
# track the load average.
- if sys.platform == 'win32' and (self.ns.worker_args is None):
+ if sys.platform == 'win32' and self.worker_test_name is None:
from test.libregrtest.win_utils import WindowsLoadTracker
try:
diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py
index 42178471ef1..aa2409b4ef7 100644
--- a/Lib/test/libregrtest/runtest_mp.py
+++ b/Lib/test/libregrtest/runtest_mp.py
@@ -33,6 +33,12 @@ def must_stop(result, ns):
return False
+def parse_worker_args(worker_args):
+ ns_dict, test_name = json.loads(worker_args)
+ ns = types.SimpleNamespace(**ns_dict)
+ return (ns, test_name)
+
+
def run_test_in_subprocess(testname, ns):
ns_dict = vars(ns)
worker_args = (ns_dict, testname)
@@ -42,8 +48,6 @@ def run_test_in_subprocess(testname, ns):
'-u', # Unbuffered stdout and stderr
'-m', 'test.regrtest',
'--worker-args', worker_args]
- if ns.pgo:
- cmd += ['--pgo']
# Running the child from the same working directory as regrtest's original
# invocation ensures that TEMPDIR for the child is the same when
@@ -56,15 +60,15 @@ def run_test_in_subprocess(testname, ns):
cwd=support.SAVEDCWD)
-def run_tests_worker(worker_args):
- ns_dict, testname = json.loads(worker_args)
- ns = types.SimpleNamespace(**ns_dict)
-
+def run_tests_worker(ns, test_name):
setup_tests(ns)
- result = runtest(ns, testname)
+ result = runtest(ns, test_name)
+
print() # Force a newline (just in case)
- print(json.dumps(result), flush=True)
+
+ # Serialize TestResult as list in JSON
+ print(json.dumps(list(result)), flush=True)
sys.exit(0)
diff --git a/Misc/NEWS.d/next/Tests/2019-05-14-14-12-24.bpo-36915.58b7pH.rst b/Misc/NEWS.d/next/Tests/2019-05-14-14-12-24.bpo-36915.58b7pH.rst
new file mode 100644
index 00000000000..4eebfb48325
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2019-05-14-14-12-24.bpo-36915.58b7pH.rst
@@ -0,0 +1,3 @@
+The main regrtest process now always removes all temporary directories of
+worker processes even if they crash or if they are killed on
+KeyboardInterrupt (CTRL+c).
From c96be811fa7da8ddcea18cc7abcae94e0f5ff966 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Tue, 14 May 2019 17:34:56 +0200
Subject: [PATCH 050/199] bpo-36900: Replace global conf vars with config
(GH-13299)
Replace global configuration variables with core_config read from the
current interpreter.
Cleanup dynload_hpux.c.
---
Modules/_io/_iomodule.c | 4 +++-
Modules/main.c | 10 +++++-----
Objects/bytearrayobject.c | 6 ++++--
Objects/bytesobject.c | 6 ++++--
Objects/moduleobject.c | 10 +++++++---
Python/compile.c | 4 +++-
Python/dynload_hpux.c | 39 +++++++++++++++++++--------------------
Python/pylifecycle.c | 5 +++--
Python/pythonrun.c | 4 +++-
9 files changed, 51 insertions(+), 37 deletions(-)
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
index d482142d080..590d6ce9f1e 100644
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/_iomodule.c
@@ -9,6 +9,7 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
+#include "pycore_pystate.h" /* _PyInterpreterState_GET_UNSAFE() */
#include "structmember.h"
#include "_iomodule.h"
@@ -376,7 +377,8 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode,
{
PyObject *RawIO_class = (PyObject *)&PyFileIO_Type;
#ifdef MS_WINDOWS
- if (!Py_LegacyWindowsStdioFlag && _PyIO_get_console_type(path_or_fd) != '\0') {
+ _PyCoreConfig *config = &_PyInterpreterState_GET_UNSAFE()->core_config;
+ if (!config->legacy_windows_stdio && _PyIO_get_console_type(path_or_fd) != '\0') {
RawIO_class = (PyObject *)&PyWindowsConsoleIO_Type;
encoding = "utf-8";
}
diff --git a/Modules/main.c b/Modules/main.c
index e117ef29e54..0f99e2af5db 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -403,8 +403,8 @@ static int
pymain_run_stdin(_PyCoreConfig *config, PyCompilerFlags *cf)
{
if (stdin_is_interactive(config)) {
- Py_InspectFlag = 0; /* do exit on SystemExit */
config->inspect = 0;
+ Py_InspectFlag = 0; /* do exit on SystemExit */
pymain_run_startup(config, cf);
pymain_run_interactive_hook();
}
@@ -425,17 +425,17 @@ pymain_repl(_PyCoreConfig *config, PyCompilerFlags *cf, int *exitcode)
{
/* Check this environment variable at the end, to give programs the
opportunity to set it from Python. */
- if (!Py_InspectFlag && _Py_GetEnv(config->use_environment, "PYTHONINSPECT")) {
- Py_InspectFlag = 1;
+ if (!config->inspect && _Py_GetEnv(config->use_environment, "PYTHONINSPECT")) {
config->inspect = 1;
+ Py_InspectFlag = 1;
}
- if (!(Py_InspectFlag && stdin_is_interactive(config) && RUN_CODE(config))) {
+ if (!(config->inspect && stdin_is_interactive(config) && RUN_CODE(config))) {
return;
}
- Py_InspectFlag = 0;
config->inspect = 0;
+ Py_InspectFlag = 0;
pymain_run_interactive_hook();
int res = PyRun_AnyFileFlags(stdin, "", cf);
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c
index 66721361934..eaf5dceb03a 100644
--- a/Objects/bytearrayobject.c
+++ b/Objects/bytearrayobject.c
@@ -998,7 +998,8 @@ bytearray_repr(PyByteArrayObject *self)
static PyObject *
bytearray_str(PyObject *op)
{
- if (Py_BytesWarningFlag) {
+ _PyCoreConfig *config = &_PyInterpreterState_GET_UNSAFE()->core_config;
+ if (config->bytes_warning) {
if (PyErr_WarnEx(PyExc_BytesWarning,
"str() on a bytearray instance", 1)) {
return NULL;
@@ -1023,7 +1024,8 @@ bytearray_richcompare(PyObject *self, PyObject *other, int op)
if (rc < 0)
return NULL;
if (rc) {
- if (Py_BytesWarningFlag && (op == Py_EQ || op == Py_NE)) {
+ _PyCoreConfig *config = &_PyInterpreterState_GET_UNSAFE()->core_config;
+ if (config->bytes_warning && (op == Py_EQ || op == Py_NE)) {
if (PyErr_WarnEx(PyExc_BytesWarning,
"Comparison between bytearray and string", 1))
return NULL;
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index 0b46ceedf00..b7c5b75283e 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -1421,7 +1421,8 @@ bytes_repr(PyObject *op)
static PyObject *
bytes_str(PyObject *op)
{
- if (Py_BytesWarningFlag) {
+ _PyCoreConfig *config = &_PyInterpreterState_GET_UNSAFE()->core_config;
+ if (config->bytes_warning) {
if (PyErr_WarnEx(PyExc_BytesWarning,
"str() on a bytes instance", 1)) {
return NULL;
@@ -1578,7 +1579,8 @@ bytes_richcompare(PyBytesObject *a, PyBytesObject *b, int op)
/* Make sure both arguments are strings. */
if (!(PyBytes_Check(a) && PyBytes_Check(b))) {
- if (Py_BytesWarningFlag && (op == Py_EQ || op == Py_NE)) {
+ _PyCoreConfig *config = &_PyInterpreterState_GET_UNSAFE()->core_config;
+ if (config->bytes_warning && (op == Py_EQ || op == Py_NE)) {
rc = PyObject_IsInstance((PyObject*)a,
(PyObject*)&PyUnicode_Type);
if (!rc)
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index 9d6533257bb..e570107cedf 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -590,13 +590,15 @@ _PyModule_ClearDict(PyObject *d)
Py_ssize_t pos;
PyObject *key, *value;
+ int verbose = _PyInterpreterState_GET_UNSAFE()->core_config.verbose;
+
/* First, clear only names starting with a single underscore */
pos = 0;
while (PyDict_Next(d, &pos, &key, &value)) {
if (value != Py_None && PyUnicode_Check(key)) {
if (PyUnicode_READ_CHAR(key, 0) == '_' &&
PyUnicode_READ_CHAR(key, 1) != '_') {
- if (Py_VerboseFlag > 1) {
+ if (verbose > 1) {
const char *s = PyUnicode_AsUTF8(key);
if (s != NULL)
PySys_WriteStderr("# clear[1] %s\n", s);
@@ -617,7 +619,7 @@ _PyModule_ClearDict(PyObject *d)
if (PyUnicode_READ_CHAR(key, 0) != '_' ||
!_PyUnicode_EqualToASCIIString(key, "__builtins__"))
{
- if (Py_VerboseFlag > 1) {
+ if (verbose > 1) {
const char *s = PyUnicode_AsUTF8(key);
if (s != NULL)
PySys_WriteStderr("# clear[2] %s\n", s);
@@ -675,8 +677,10 @@ module___init___impl(PyModuleObject *self, PyObject *name, PyObject *doc)
static void
module_dealloc(PyModuleObject *m)
{
+ int verbose = _PyInterpreterState_GET_UNSAFE()->core_config.verbose;
+
PyObject_GC_UnTrack(m);
- if (Py_VerboseFlag && m->md_name) {
+ if (verbose && m->md_name) {
PySys_FormatStderr("# destroy %S\n", m->md_name);
}
if (m->md_weaklist != NULL)
diff --git a/Python/compile.c b/Python/compile.c
index dd27ba840f7..91ce04b02e5 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -24,6 +24,7 @@
#include "Python.h"
#include "Python-ast.h"
+#include "pycore_pystate.h" /* _PyInterpreterState_GET_UNSAFE() */
#include "ast.h"
#include "code.h"
#include "symtable.h"
@@ -310,6 +311,7 @@ PyAST_CompileObject(mod_ty mod, PyObject *filename, PyCompilerFlags *flags,
PyCodeObject *co = NULL;
PyCompilerFlags local_flags;
int merged;
+ _PyCoreConfig *config = &_PyInterpreterState_GET_UNSAFE()->core_config;
if (!__doc__) {
__doc__ = PyUnicode_InternFromString("__doc__");
@@ -338,7 +340,7 @@ PyAST_CompileObject(mod_ty mod, PyObject *filename, PyCompilerFlags *flags,
c.c_future->ff_features = merged;
flags->cf_flags = merged;
c.c_flags = flags;
- c.c_optimize = (optimize == -1) ? Py_OptimizeFlag : optimize;
+ c.c_optimize = (optimize == -1) ? config->optimization_level : optimize;
c.c_nestlevel = 0;
if (!_PyAST_Optimize(mod, arena, c.c_optimize)) {
diff --git a/Python/dynload_hpux.c b/Python/dynload_hpux.c
index 4967afc39c1..f275e534588 100644
--- a/Python/dynload_hpux.c
+++ b/Python/dynload_hpux.c
@@ -19,48 +19,47 @@ dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix,
const char *shortname,
const char *pathname, FILE *fp)
{
- dl_funcptr p;
- shl_t lib;
- int flags;
- char funcname[258];
-
- flags = BIND_FIRST | BIND_DEFERRED;
- if (Py_VerboseFlag) {
+ int flags = BIND_FIRST | BIND_DEFERRED;
+ int verbose = _PyInterpreterState_GET_UNSAFE()->core_config.verbose;
+ if (verbose) {
flags = BIND_FIRST | BIND_IMMEDIATE |
BIND_NONFATAL | BIND_VERBOSE;
printf("shl_load %s\n",pathname);
}
- lib = shl_load(pathname, flags, 0);
+
+ shl_t lib = shl_load(pathname, flags, 0);
/* XXX Chuck Blake once wrote that 0 should be BIND_NOSTART? */
if (lib == NULL) {
- char buf[256];
- PyObject *pathname_ob = NULL;
- PyObject *buf_ob = NULL;
- PyObject *shortname_ob = NULL;
-
- if (Py_VerboseFlag)
+ if (verbose) {
perror(pathname);
+ }
+ char buf[256];
PyOS_snprintf(buf, sizeof(buf), "Failed to load %.200s",
pathname);
- buf_ob = PyUnicode_FromString(buf);
- shortname_ob = PyUnicode_FromString(shortname);
- pathname_ob = PyUnicode_FromString(pathname);
+ PyObject *buf_ob = PyUnicode_FromString(buf);
+ PyObject *shortname_ob = PyUnicode_FromString(shortname);
+ PyObject *pathname_ob = PyUnicode_FromString(pathname);
PyErr_SetImportError(buf_ob, shortname_ob, pathname_ob);
Py_DECREF(buf_ob);
Py_DECREF(shortname_ob);
Py_DECREF(pathname_ob);
return NULL;
}
+
+ char funcname[258];
PyOS_snprintf(funcname, sizeof(funcname), FUNCNAME_PATTERN,
prefix, shortname);
- if (Py_VerboseFlag)
+ if (verbose) {
printf("shl_findsym %s\n", funcname);
+ }
+
+ dl_funcptr p;
if (shl_findsym(&lib, funcname, TYPE_UNDEFINED, (void *) &p) == -1) {
shl_unload(lib);
p = NULL;
}
- if (p == NULL && Py_VerboseFlag)
+ if (p == NULL && verbose) {
perror(funcname);
-
+ }
return p;
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 014b19aa8aa..4e74e0b80c8 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -150,12 +150,13 @@ init_importlib(PyInterpreterState *interp, PyObject *sysmod)
PyObject *importlib;
PyObject *impmod;
PyObject *value;
+ int verbose = interp->core_config.verbose;
/* Import _importlib through its frozen version, _frozen_importlib. */
if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) {
return _Py_INIT_ERR("can't import _frozen_importlib");
}
- else if (Py_VerboseFlag) {
+ else if (verbose) {
PySys_FormatStderr("import _frozen_importlib # frozen\n");
}
importlib = PyImport_AddModule("_frozen_importlib");
@@ -175,7 +176,7 @@ init_importlib(PyInterpreterState *interp, PyObject *sysmod)
if (impmod == NULL) {
return _Py_INIT_ERR("can't import _imp");
}
- else if (Py_VerboseFlag) {
+ else if (verbose) {
PySys_FormatStderr("import _imp # builtin\n");
}
if (_PyImport_SetModuleString("_imp", impmod) < 0) {
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 199ea82434e..3d83044af9a 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -591,10 +591,12 @@ handle_system_exit(void)
PyObject *exception, *value, *tb;
int exitcode = 0;
- if (Py_InspectFlag)
+ int inspect = _PyInterpreterState_GET_UNSAFE()->core_config.inspect;
+ if (inspect) {
/* Don't exit if -i flag was given. This flag is set to 0
* when entering interactive mode for inspecting. */
return;
+ }
PyErr_Fetch(&exception, &value, &tb);
fflush(stdout);
From f12ba7cd0a7370631214ac0b337ab5455ce717b2 Mon Sep 17 00:00:00 2001
From: Andrew Svetlov
Date: Tue, 14 May 2019 19:09:44 +0300
Subject: [PATCH 051/199] bpo-36916: asyncio: Swallow unhandled write()
exception (GH-13313)
---
Lib/asyncio/streams.py | 11 ++++++++++-
Lib/test/test_asyncio/test_streams.py | 3 +++
.../Library/2019-05-14-15-39-34.bpo-36916._GPsTt.rst | 2 ++
3 files changed, 15 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-14-15-39-34.bpo-36916._GPsTt.rst
diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py
index d9a9f5e72d3..146a33818d9 100644
--- a/Lib/asyncio/streams.py
+++ b/Lib/asyncio/streams.py
@@ -329,6 +329,13 @@ def __del__(self):
closed.exception()
+def _swallow_unhandled_exception(task):
+ # Do a trick to suppress unhandled exception
+ # if stream.write() was used without await and
+ # stream.drain() was paused and resumed with an exception
+ task.exception()
+
+
class StreamWriter:
"""Wraps a Transport.
@@ -393,7 +400,9 @@ def _fast_drain(self):
# fast path, the stream is not paused
# no need to wait for resume signal
return self._complete_fut
- return self._loop.create_task(self.drain())
+ ret = self._loop.create_task(self.drain())
+ ret.add_done_callback(_swallow_unhandled_exception)
+ return ret
def write_eof(self):
return self._transport.write_eof()
diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py
index bf93f30e1aa..8d6a1d26ac1 100644
--- a/Lib/test/test_asyncio/test_streams.py
+++ b/Lib/test/test_asyncio/test_streams.py
@@ -851,6 +851,8 @@ def test_drain_raises(self):
# where it never gives up the event loop but the socket is
# closed on the server side.
+ messages = []
+ self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))
q = queue.Queue()
def server():
@@ -883,6 +885,7 @@ async def client(host, port):
# Clean up the thread. (Only on success; on failure, it may
# be stuck in accept().)
thread.join()
+ self.assertEqual([], messages)
def test___repr__(self):
stream = asyncio.StreamReader(loop=self.loop,
diff --git a/Misc/NEWS.d/next/Library/2019-05-14-15-39-34.bpo-36916._GPsTt.rst b/Misc/NEWS.d/next/Library/2019-05-14-15-39-34.bpo-36916._GPsTt.rst
new file mode 100644
index 00000000000..8726bb241f2
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-14-15-39-34.bpo-36916._GPsTt.rst
@@ -0,0 +1,2 @@
+Remove a message about an unhandled exception in a task when writer.write()
+is used without await and writer.drain() fails with an exception.
From 4d45a3b1107977baba9dce868e80d1d95bce4085 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Herv=C3=A9=20Beraud?=
Date: Tue, 14 May 2019 18:52:42 +0200
Subject: [PATCH 052/199] json.tool: use stdin and stdout in default cmdlne
arguments (GH-11992)
Argparse can handle default value as stdin and stdout for parameters
as file type (infile, outfile).
---
Lib/json/tool.py | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/Lib/json/tool.py b/Lib/json/tool.py
index 1d82bc82423..b3ef9923e31 100644
--- a/Lib/json/tool.py
+++ b/Lib/json/tool.py
@@ -21,17 +21,19 @@ def main():
'to validate and pretty-print JSON objects.')
parser = argparse.ArgumentParser(prog=prog, description=description)
parser.add_argument('infile', nargs='?', type=argparse.FileType(),
- help='a JSON file to be validated or pretty-printed')
+ help='a JSON file to be validated or pretty-printed',
+ default=sys.stdin)
parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
- help='write the output of infile to outfile')
+ help='write the output of infile to outfile',
+ default=sys.stdout)
parser.add_argument('--sort-keys', action='store_true', default=False,
help='sort the output of dictionaries alphabetically by key')
parser.add_argument('--json-lines', action='store_true', default=False,
help='parse input using the jsonlines format')
options = parser.parse_args()
- infile = options.infile or sys.stdin
- outfile = options.outfile or sys.stdout
+ infile = options.infile
+ outfile = options.outfile
sort_keys = options.sort_keys
json_lines = options.json_lines
with infile, outfile:
From c1f5667be1e3ec5871560c677402c1252c6018a6 Mon Sep 17 00:00:00 2001
From: Krzysztof Wojcik
Date: Tue, 14 May 2019 18:55:23 +0200
Subject: [PATCH 053/199] bpo-33529, email: Fix infinite loop in email header
encoding (GH-12020)
---
Lib/email/_header_value_parser.py | 23 +++++++++++--------
Lib/test/test_email/test_headerregistry.py | 8 +++----
Lib/test/test_email/test_policy.py | 8 +++++++
.../2019-02-24-18-48-16.bpo-33529.wpNNBD.rst | 2 ++
4 files changed, 27 insertions(+), 14 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2019-02-24-18-48-16.bpo-33529.wpNNBD.rst
diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py
index bb26d5a556d..60d0d32059f 100644
--- a/Lib/email/_header_value_parser.py
+++ b/Lib/email/_header_value_parser.py
@@ -2723,16 +2723,19 @@ def _fold_as_ew(to_encode, lines, maxlen, last_ew, ew_combine_allowed, charset):
lines.append(' ')
# XXX We'll get an infinite loop here if maxlen is <= 7
continue
- first_part = to_encode[:text_space]
- ew = _ew.encode(first_part, charset=encode_as)
- excess = len(ew) - remaining_space
- if excess > 0:
- # encode always chooses the shortest encoding, so this
- # is guaranteed to fit at this point.
- first_part = first_part[:-excess]
- ew = _ew.encode(first_part)
- lines[-1] += ew
- to_encode = to_encode[len(first_part):]
+
+ to_encode_word = to_encode[:text_space]
+ encoded_word = _ew.encode(to_encode_word, charset=encode_as)
+ excess = len(encoded_word) - remaining_space
+ while excess > 0:
+ # Since the chunk to encode is guaranteed to fit into less than 100 characters,
+ # shrinking it by one at a time shouldn't take long.
+ to_encode_word = to_encode_word[:-1]
+ encoded_word = _ew.encode(to_encode_word, charset=encode_as)
+ excess = len(encoded_word) - remaining_space
+ lines[-1] += encoded_word
+ to_encode = to_encode[len(to_encode_word):]
+
if to_encode:
lines.append(' ')
new_last_ew = len(lines[-1])
diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py
index 30ce0ba54e4..d1007099f66 100644
--- a/Lib/test/test_email/test_headerregistry.py
+++ b/Lib/test/test_email/test_headerregistry.py
@@ -1643,10 +1643,10 @@ def test_fold_overlong_words_using_RFC2047(self):
self.assertEqual(
h.fold(policy=policy.default),
'X-Report-Abuse: =?utf-8?q?=3Chttps=3A//www=2Emailitapp=2E'
- 'com/report=5F?=\n'
- ' =?utf-8?q?abuse=2Ephp=3Fmid=3Dxxx-xxx-xxxx'
- 'xxxxxxxxxxxxxxxxxxxx=3D=3D-xxx-?=\n'
- ' =?utf-8?q?xx-xx=3E?=\n')
+ 'com/report=5Fabuse?=\n'
+ ' =?utf-8?q?=2Ephp=3Fmid=3Dxxx-xxx-xxxx'
+ 'xxxxxxxxxxxxxxxxxxxx=3D=3D-xxx-xx-xx?=\n'
+ ' =?utf-8?q?=3E?=\n')
if __name__ == '__main__':
diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py
index 8fecb8a5fcd..c2c437e6ac2 100644
--- a/Lib/test/test_email/test_policy.py
+++ b/Lib/test/test_email/test_policy.py
@@ -237,6 +237,14 @@ def test_adding_default_policies_preserves_default_factory(self):
email.policy.EmailPolicy.header_factory)
self.assertEqual(newpolicy.__dict__, {'raise_on_defect': True})
+ def test_non_ascii_chars_do_not_cause_inf_loop(self):
+ policy = email.policy.default.clone(max_line_length=20)
+ actual = policy.fold('Subject', 'Ä…' * 12)
+ self.assertEqual(
+ actual,
+ 'Subject: \n' +
+ 12 * ' =?utf-8?q?=C4=85?=\n')
+
# XXX: Need subclassing tests.
# For adding subclassed objects, make sure the usual rules apply (subclass
# wins), but that the order still works (right overrides left).
diff --git a/Misc/NEWS.d/next/Security/2019-02-24-18-48-16.bpo-33529.wpNNBD.rst b/Misc/NEWS.d/next/Security/2019-02-24-18-48-16.bpo-33529.wpNNBD.rst
new file mode 100644
index 00000000000..84d16f5a56a
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2019-02-24-18-48-16.bpo-33529.wpNNBD.rst
@@ -0,0 +1,2 @@
+Prevent fold function used in email header encoding from entering infinite
+loop when there are too many non-ASCII characters in a header.
From d97adfb409290a1e4ad549e4af58cacea86d3358 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Tue, 14 May 2019 19:29:53 +0200
Subject: [PATCH 054/199] bpo-36618: Don't add -fmax-type-align=8 flag for
clang (GH-13320)
Python 3.8 now respects the x86-64 ABI: memory allocations are
aligned on 16 bytes. The clang flag was only used as a temporary
workaround.
---
configure | 20 --------------------
configure.ac | 20 --------------------
2 files changed, 40 deletions(-)
diff --git a/configure b/configure
index e6e40073515..6da65ddbba5 100755
--- a/configure
+++ b/configure
@@ -6905,26 +6905,6 @@ then
esac
fi
-if test -n "${cc_is_clang}"
-then
- # bpo-36618: Add -fmax-type-align=8 to CFLAGS when clang compiler is
- # detected. The pymalloc memory allocator aligns memory on 8 bytes. On
- # x86-64, clang expects alignment on 16 bytes by default and so uses MOVAPS
- # instruction which can lead to segmentation fault. Instruct clang that
- # Python is limited to alignemnt on 8 bytes to use MOVUPS instruction
- # instead: slower but don't trigger a SIGSEGV if the memory is not aligned
- # on 16 bytes.
- #
- # Sadly, the flag must be added to CFLAGS and not just CFLAGS_NODIST,
- # since third party C extensions can have the same issue.
- #
- # Check if -fmax-type-align flag is supported (it's not supported by old
- # clang versions):
- if "$CC" -v --help 2>/dev/null |grep -- -fmax-type-align > /dev/null; then
- CFLAGS="$CFLAGS -fmax-type-align=8"
- fi
-fi
-
diff --git a/configure.ac b/configure.ac
index a02597da2db..e673e136be8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1543,26 +1543,6 @@ then
esac
fi
-if test -n "${cc_is_clang}"
-then
- # bpo-36618: Add -fmax-type-align=8 to CFLAGS when clang compiler is
- # detected. The pymalloc memory allocator aligns memory on 8 bytes. On
- # x86-64, clang expects alignment on 16 bytes by default and so uses MOVAPS
- # instruction which can lead to segmentation fault. Instruct clang that
- # Python is limited to alignemnt on 8 bytes to use MOVUPS instruction
- # instead: slower but don't trigger a SIGSEGV if the memory is not aligned
- # on 16 bytes.
- #
- # Sadly, the flag must be added to CFLAGS and not just CFLAGS_NODIST,
- # since third party C extensions can have the same issue.
- #
- # Check if -fmax-type-align flag is supported (it's not supported by old
- # clang versions):
- if "$CC" -v --help 2>/dev/null |grep -- -fmax-type-align > /dev/null; then
- CFLAGS="$CFLAGS -fmax-type-align=8"
- fi
-fi
-
AC_SUBST(BASECFLAGS)
AC_SUBST(CFLAGS_NODIST)
AC_SUBST(LDFLAGS_NODIST)
From e883091abf7ca84a88e956fe5202e75c53bd4128 Mon Sep 17 00:00:00 2001
From: "Gregory P. Smith"
Date: Tue, 14 May 2019 12:33:17 -0700
Subject: [PATCH 055/199] bpo-36760: Clarify subprocess capture_output docs.
(GH-13322)
Clarify how to capture stdout and stderr combined into one stream.
---
Doc/library/subprocess.rst | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index 3280c95cacb..d840b461f98 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -55,7 +55,9 @@ compatibility with older versions, see the :ref:`call-function-trio` section.
If *capture_output* is true, stdout and stderr will be captured.
When used, the internal :class:`Popen` object is automatically created with
``stdout=PIPE`` and ``stderr=PIPE``. The *stdout* and *stderr* arguments may
- not be supplied at the same time as *capture_output*.
+ not be supplied at the same time as *capture_output*. If you wish to capture
+ and combine both streams into one, use ``stdout=PIPE`` and ``stderr=STDOUT``
+ instead of *capture_output*.
The *timeout* argument is passed to :meth:`Popen.communicate`. If the timeout
expires, the child process will be killed and waited for. The
From 91c99873d115b9796377d5056785f2abc987520f Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Tue, 14 May 2019 22:01:51 +0200
Subject: [PATCH 056/199] bpo-36763: Add test for _PyCoreConfig_SetString()
(GH-13275)
test_embed: add test_init_read_set() to test newly added APIs: test
module_search_paths and executable.
---
Lib/test/test_embed.py | 42 ++++++++++++++++++++++++++++++------
Programs/_testembed.c | 48 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 83 insertions(+), 7 deletions(-)
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index fdf5793789d..ca06f3c3dbc 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -273,7 +273,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
UNTESTED_CORE_CONFIG = (
# FIXME: untested core configuration variables
'dll_path',
- 'executable',
'module_search_paths',
)
# Mark config which should be get by get_default_config()
@@ -310,7 +309,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'filesystem_errors': GET_DEFAULT_CONFIG,
'pycache_prefix': None,
- 'program_name': './_testembed',
+ 'program_name': GET_DEFAULT_CONFIG,
'argv': [""],
'program': '',
@@ -319,6 +318,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'module_search_path_env': None,
'home': None,
+ 'executable': GET_DEFAULT_CONFIG,
'prefix': GET_DEFAULT_CONFIG,
'base_prefix': GET_DEFAULT_CONFIG,
@@ -404,7 +404,7 @@ def main_xoptions(self, xoptions_list):
xoptions[opt] = True
return xoptions
- def get_expected_config(self, expected, env):
+ def get_expected_config(self, expected, env, add_path=None):
expected = dict(self.DEFAULT_CORE_CONFIG, **expected)
code = textwrap.dedent('''
@@ -420,6 +420,7 @@ def get_expected_config(self, expected, env):
'base_exec_prefix': sys.base_exec_prefix,
'filesystem_encoding': sys.getfilesystemencoding(),
'filesystem_errors': sys.getfilesystemencodeerrors(),
+ 'module_search_paths': sys.path,
}
data = json.dumps(data)
@@ -447,9 +448,21 @@ def get_expected_config(self, expected, env):
except json.JSONDecodeError:
self.fail(f"fail to decode stdout: {stdout!r}")
+ if expected['executable'] is self.GET_DEFAULT_CONFIG:
+ if sys.platform == 'win32':
+ expected['executable'] = self.test_exe
+ else:
+ if expected['program_name'] is not self.GET_DEFAULT_CONFIG:
+ expected['executable'] = os.path.abspath(expected['program_name'])
+ else:
+ expected['executable'] = os.path.join(os.getcwd(), '_testembed')
+ if expected['program_name'] is self.GET_DEFAULT_CONFIG:
+ expected['program_name'] = './_testembed'
+
for key, value in expected.items():
if value is self.GET_DEFAULT_CONFIG:
expected[key] = config[key]
+ expected['module_search_paths'] = config['module_search_paths']
return expected
def check_pre_config(self, config, expected):
@@ -457,10 +470,16 @@ def check_pre_config(self, config, expected):
core_config = dict(config['core_config'])
self.assertEqual(pre_config, expected)
- def check_core_config(self, config, expected):
+ def check_core_config(self, config, expected, add_path=None):
core_config = dict(config['core_config'])
+ if add_path is not None:
+ paths = [*expected['module_search_paths'], add_path]
+ if not paths[0]:
+ del paths[0]
+ self.assertEqual(core_config['module_search_paths'], paths)
for key in self.UNTESTED_CORE_CONFIG:
core_config.pop(key, None)
+ expected.pop(key, None)
self.assertEqual(core_config, expected)
def check_global_config(self, config):
@@ -485,7 +504,7 @@ def check_global_config(self, config):
self.assertEqual(config['global_config'], expected)
- def check_config(self, testname, expected_config, expected_preconfig):
+ def check_config(self, testname, expected_config, expected_preconfig, add_path=None):
env = dict(os.environ)
# Remove PYTHON* environment variables to get deterministic environment
for key in list(env):
@@ -504,13 +523,13 @@ def check_config(self, testname, expected_config, expected_preconfig):
self.fail(f"fail to decode stdout: {out!r}")
expected_preconfig = dict(self.DEFAULT_PRE_CONFIG, **expected_preconfig)
- expected_config = self.get_expected_config(expected_config, env)
+ expected_config = self.get_expected_config(expected_config, env, add_path)
for key in self.COPY_PRE_CONFIG:
if key not in expected_preconfig:
expected_preconfig[key] = expected_config[key]
self.check_pre_config(config, expected_preconfig)
- self.check_core_config(config, expected_config)
+ self.check_core_config(config, expected_config, add_path)
self.check_global_config(config)
def test_init_default_config(self):
@@ -665,6 +684,15 @@ def test_preinit_isolated2(self):
}
self.check_config("preinit_isolated2", config, preconfig)
+ def test_init_read_set(self):
+ preconfig = {}
+ core_config = {
+ 'program_name': './init_read_set',
+ 'executable': 'my_executable',
+ }
+ self.check_config("init_read_set", core_config, preconfig,
+ add_path="init_read_set_path")
+
if __name__ == "__main__":
unittest.main()
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index b12594799bf..73b37c5f1f3 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -1,4 +1,10 @@
+/* FIXME: PEP 587 makes these functions public */
+#ifndef Py_BUILD_CORE_MODULE
+# define Py_BUILD_CORE_MODULE
+#endif
+
#include
+#include "pycore_coreconfig.h" /* FIXME: PEP 587 makes these functions public */
#include "pythread.h"
#include
#include
@@ -679,6 +685,47 @@ static int test_init_dev_mode(void)
}
+static int test_init_read_set(void)
+{
+ _PyInitError err;
+ _PyCoreConfig config = _PyCoreConfig_INIT;
+
+ err = _PyCoreConfig_DecodeLocale(&config.program_name, "./init_read_set");
+ if (_Py_INIT_FAILED(err)) {
+ goto fail;
+ }
+
+ err = _PyCoreConfig_Read(&config);
+ if (_Py_INIT_FAILED(err)) {
+ goto fail;
+ }
+
+ if (_PyWstrList_Append(&config.module_search_paths,
+ L"init_read_set_path") < 0) {
+ err = _Py_INIT_NO_MEMORY();
+ goto fail;
+ }
+
+ /* override executable computed by _PyCoreConfig_Read() */
+ err = _PyCoreConfig_SetString(&config.executable, L"my_executable");
+ if (_Py_INIT_FAILED(err)) {
+ goto fail;
+ }
+
+ err = _Py_InitializeFromConfig(&config);
+ _PyCoreConfig_Clear(&config);
+ if (_Py_INIT_FAILED(err)) {
+ goto fail;
+ }
+ dump_config();
+ Py_Finalize();
+ return 0;
+
+fail:
+ _Py_ExitInitError(err);
+}
+
+
static int test_run_main(void)
{
_PyCoreConfig config = _PyCoreConfig_INIT;
@@ -736,6 +783,7 @@ static struct TestCase TestCases[] = {
{ "init_isolated", test_init_isolated },
{ "preinit_isolated1", test_preinit_isolated1 },
{ "preinit_isolated2", test_preinit_isolated2 },
+ { "init_read_set", test_init_read_set },
{ "run_main", test_run_main },
{ NULL, NULL }
};
From 54b74fe9df89f0e5646736f1f60376b4e37c422c Mon Sep 17 00:00:00 2001
From: Andrew Svetlov
Date: Wed, 15 May 2019 00:39:13 +0300
Subject: [PATCH 057/199] bpo-36801: Temporarily fix regression in
writer.drain() (#13330)
---
Lib/asyncio/streams.py | 4 +---
Lib/test/test_asyncio/test_streams.py | 23 -----------------------
2 files changed, 1 insertion(+), 26 deletions(-)
diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py
index 146a33818d9..2f0cbfdbe85 100644
--- a/Lib/asyncio/streams.py
+++ b/Lib/asyncio/streams.py
@@ -439,9 +439,7 @@ async def drain(self):
# Wait for protocol.connection_lost() call
# Raise connection closing error if any,
# ConnectionResetError otherwise
- fut = self._protocol._get_close_waiter(self)
- await fut
- raise ConnectionResetError('Connection lost')
+ await sleep(0)
await self._protocol._drain_helper()
diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py
index 8d6a1d26ac1..258d8a7f7fd 100644
--- a/Lib/test/test_asyncio/test_streams.py
+++ b/Lib/test/test_asyncio/test_streams.py
@@ -109,29 +109,6 @@ def test_open_unix_connection_no_loop_ssl(self):
self._basetest_open_connection_no_loop_ssl(conn_fut)
- @unittest.skipIf(ssl is None, 'No ssl module')
- def test_drain_on_closed_writer_ssl(self):
-
- async def inner(httpd):
- reader, writer = await asyncio.open_connection(
- *httpd.address,
- ssl=test_utils.dummy_ssl_context())
-
- messages = []
- self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))
- writer.write(b'GET / HTTP/1.0\r\n\r\n')
- data = await reader.read()
- self.assertTrue(data.endswith(b'\r\n\r\nTest message'))
-
- writer.close()
- with self.assertRaises(ConnectionResetError):
- await writer.drain()
-
- self.assertEqual(messages, [])
-
- with test_utils.run_test_server(use_ssl=True) as httpd:
- self.loop.run_until_complete(inner(httpd))
-
def _basetest_open_connection_error(self, open_connection_fut):
messages = []
self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))
From 5eb8b07f87c66a9ca54fcb90737753ce76a3054d Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Wed, 15 May 2019 02:12:48 +0200
Subject: [PATCH 058/199] bpo-36763: InitConfigTests tests all core config
(GH-13331)
Remove UNTESTED_CORE_CONFIG from test_embed.InitConfigTests: all core
config fields are now tested!
Changes:
* Test also dll_path on Windows
* Add run_main_config unit test: test config using _Py_RunMain().
---
Lib/test/test_embed.py | 45 ++++++++++++++++++++++++------------------
Programs/_testembed.c | 22 +++++++++++++++++++++
2 files changed, 48 insertions(+), 19 deletions(-)
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index ca06f3c3dbc..8f40e9fdb18 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -269,12 +269,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
maxDiff = 4096
UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape')
- # core config
- UNTESTED_CORE_CONFIG = (
- # FIXME: untested core configuration variables
- 'dll_path',
- 'module_search_paths',
- )
# Mark config which should be get by get_default_config()
GET_DEFAULT_CONFIG = object()
DEFAULT_PRE_CONFIG = {
@@ -324,6 +318,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'base_prefix': GET_DEFAULT_CONFIG,
'exec_prefix': GET_DEFAULT_CONFIG,
'base_exec_prefix': GET_DEFAULT_CONFIG,
+ 'module_search_paths': GET_DEFAULT_CONFIG,
'site_import': 1,
'bytes_warning': 0,
@@ -354,6 +349,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'legacy_windows_fs_encoding': 0,
})
DEFAULT_CORE_CONFIG.update({
+ 'dll_path': GET_DEFAULT_CONFIG,
'legacy_windows_stdio': 0,
})
@@ -410,7 +406,10 @@ def get_expected_config(self, expected, env, add_path=None):
code = textwrap.dedent('''
import json
import sys
+ import _testinternalcapi
+ configs = _testinternalcapi.get_configs()
+ core_config = configs['core_config']
data = {
'stdio_encoding': sys.stdout.encoding,
'stdio_errors': sys.stdout.errors,
@@ -420,8 +419,10 @@ def get_expected_config(self, expected, env, add_path=None):
'base_exec_prefix': sys.base_exec_prefix,
'filesystem_encoding': sys.getfilesystemencoding(),
'filesystem_errors': sys.getfilesystemencodeerrors(),
- 'module_search_paths': sys.path,
+ 'module_search_paths': core_config['module_search_paths'],
}
+ if sys.platform == 'win32':
+ data['dll_path'] = core_config['dll_path']
data = json.dumps(data)
data = data.encode('utf-8')
@@ -431,7 +432,7 @@ def get_expected_config(self, expected, env, add_path=None):
# Use -S to not import the site module: get the proper configuration
# when test_embed is run from a venv (bpo-35313)
- args = (sys.executable, '-S', '-c', code)
+ args = [sys.executable, '-S', '-c', code]
env = dict(env)
if not expected['isolated']:
env['PYTHONCOERCECLOCALE'] = '0'
@@ -462,7 +463,9 @@ def get_expected_config(self, expected, env, add_path=None):
for key, value in expected.items():
if value is self.GET_DEFAULT_CONFIG:
expected[key] = config[key]
- expected['module_search_paths'] = config['module_search_paths']
+
+ if add_path is not None:
+ expected['module_search_paths'].append(add_path)
return expected
def check_pre_config(self, config, expected):
@@ -470,16 +473,8 @@ def check_pre_config(self, config, expected):
core_config = dict(config['core_config'])
self.assertEqual(pre_config, expected)
- def check_core_config(self, config, expected, add_path=None):
+ def check_core_config(self, config, expected):
core_config = dict(config['core_config'])
- if add_path is not None:
- paths = [*expected['module_search_paths'], add_path]
- if not paths[0]:
- del paths[0]
- self.assertEqual(core_config['module_search_paths'], paths)
- for key in self.UNTESTED_CORE_CONFIG:
- core_config.pop(key, None)
- expected.pop(key, None)
self.assertEqual(core_config, expected)
def check_global_config(self, config):
@@ -529,7 +524,7 @@ def check_config(self, testname, expected_config, expected_preconfig, add_path=N
expected_preconfig[key] = expected_config[key]
self.check_pre_config(config, expected_preconfig)
- self.check_core_config(config, expected_config, add_path)
+ self.check_core_config(config, expected_config)
self.check_global_config(config)
def test_init_default_config(self):
@@ -693,6 +688,18 @@ def test_init_read_set(self):
self.check_config("init_read_set", core_config, preconfig,
add_path="init_read_set_path")
+ def test_run_main_config(self):
+ preconfig = {}
+ code = ('import _testinternalcapi, json; '
+ 'print(json.dumps(_testinternalcapi.get_configs()))')
+ core_config = {
+ 'argv': ['-c', 'arg2'],
+ 'program': 'python3',
+ 'program_name': './python3',
+ 'run_command': code + '\n',
+ }
+ self.check_config("run_main_config", core_config, preconfig)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 73b37c5f1f3..2560bfc62bb 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -747,6 +747,27 @@ static int test_run_main(void)
}
+static int test_run_main_config(void)
+{
+ _PyCoreConfig config = _PyCoreConfig_INIT;
+
+ wchar_t *argv[] = {L"python3", L"-c",
+ (L"import _testinternalcapi, json; "
+ L"print(json.dumps(_testinternalcapi.get_configs()))"),
+ L"arg2"};
+ config.argv.length = Py_ARRAY_LENGTH(argv);
+ config.argv.items = argv;
+ config.program_name = L"./python3";
+
+ _PyInitError err = _Py_InitializeFromConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+
+ return _Py_RunMain();
+}
+
+
/* *********************************************************
* List of test cases and the function that implements it.
*
@@ -785,6 +806,7 @@ static struct TestCase TestCases[] = {
{ "preinit_isolated2", test_preinit_isolated2 },
{ "init_read_set", test_init_read_set },
{ "run_main", test_run_main },
+ { "run_main_config", test_run_main_config },
{ NULL, NULL }
};
From 133fc89ca02b51b8d5b87556d94f1382c4ed72c1 Mon Sep 17 00:00:00 2001
From: Yavor Konstantinov <7553015+sehnsucht13@users.noreply.github.com>
Date: Wed, 15 May 2019 08:02:13 -0700
Subject: [PATCH 059/199] bpo-36799: Fix typo in ctypes.rst (GH-13104)
---
Doc/library/ctypes.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst
index baab0de8f8a..1c60b4bbda1 100644
--- a/Doc/library/ctypes.rst
+++ b/Doc/library/ctypes.rst
@@ -2376,7 +2376,7 @@ other data types containing pointer type fields.
and so on). Later assignments to the :attr:`_fields_` class variable will
raise an AttributeError.
- It is possible to defined sub-subclasses of structure types, they inherit
+ It is possible to define sub-subclasses of structure types, they inherit
the fields of the base class plus the :attr:`_fields_` defined in the
sub-subclass, if any.
@@ -2424,7 +2424,7 @@ other data types containing pointer type fields.
td.lptdesc = POINTER(some_type)
td.u.lptdesc = POINTER(some_type)
- It is possible to defined sub-subclasses of structures, they inherit the
+ It is possible to define sub-subclasses of structures, they inherit the
fields of the base class. If the subclass definition has a separate
:attr:`_fields_` variable, the fields specified in this are appended to the
fields of the base class.
From e307e5cd06f60e11e4e4f126fae412b9ec66a005 Mon Sep 17 00:00:00 2001
From: Xtreak
Date: Wed, 15 May 2019 21:48:35 +0530
Subject: [PATCH 060/199] Reference zipimport source code from docs. (GH-13310)
---
Doc/library/zipimport.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Doc/library/zipimport.rst b/Doc/library/zipimport.rst
index aa1831dbc60..2138697ff06 100644
--- a/Doc/library/zipimport.rst
+++ b/Doc/library/zipimport.rst
@@ -6,6 +6,8 @@
.. moduleauthor:: Just van Rossum
+**Source code:** :source:`Lib/zipimport.py`
+
--------------
This module adds the ability to import Python modules (:file:`\*.py`,
From c981ad16b0f9740bd3381c96b4227a1faa1a88d9 Mon Sep 17 00:00:00 2001
From: Jon Janzen
Date: Wed, 15 May 2019 22:14:38 +0200
Subject: [PATCH 061/199] bpo-26707: Enable plistlib to read UID keys.
(GH-12153)
Plistlib currently throws an exception when asked to decode a valid
.plist file that was generated by Apple's NSKeyedArchiver. Specifically,
this is caused by a byte 0x80 (signifying a UID) not being understood.
This fixes the problem by enabling the binary plist reader and writer
to read and write plistlib.UID objects.
---
Doc/library/plistlib.rst | 14 +++
Doc/whatsnew/3.8.rst | 8 ++
Lib/plistlib.py | 49 +++++++++-
Lib/test/test_plistlib.py | 98 ++++++++++++++++++-
Mac/Tools/plistlib_generate_testdata.py | 3 +
Misc/ACKS | 1 +
.../2019-03-04-01-28-33.bpo-26707.QY4kRZ.rst | 1 +
7 files changed, 169 insertions(+), 5 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-03-04-01-28-33.bpo-26707.QY4kRZ.rst
diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst
index 8bd6b63a8ee..d84fcac0ef2 100644
--- a/Doc/library/plistlib.rst
+++ b/Doc/library/plistlib.rst
@@ -36,6 +36,10 @@ or :class:`datetime.datetime` objects.
.. versionchanged:: 3.4
New API, old API deprecated. Support for binary format plists added.
+.. versionchanged:: 3.8
+ Support added for reading and writing :class:`UID` tokens in binary plists as used
+ by NSKeyedArchiver and NSKeyedUnarchiver.
+
.. seealso::
`PList manual page `_
@@ -179,6 +183,16 @@ The following classes are available:
.. deprecated:: 3.4 Use a :class:`bytes` object instead.
+.. class:: UID(data)
+
+ Wraps an :class:`int`. This is used when reading or writing NSKeyedArchiver
+ encoded data, which contains UID (see PList manual).
+
+ It has one attribute, :attr:`data` which can be used to retrieve the int value
+ of the UID. :attr:`data` must be in the range `0 <= data <= 2**64`.
+
+ .. versionadded:: 3.8
+
The following constants are available:
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index a2af201215c..c135183095c 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -394,6 +394,14 @@ to a path.
(Contributed by Joannah Nanjekye in :issue:`26978`)
+plistlib
+--------
+
+Added new :class:`plistlib.UID` and enabled support for reading and writing
+NSKeyedArchiver-encoded binary plists.
+(Contributed by Jon Janzen in :issue:`26707`.)
+
+
socket
------
diff --git a/Lib/plistlib.py b/Lib/plistlib.py
index 248f5143f4e..0133c89bdc6 100644
--- a/Lib/plistlib.py
+++ b/Lib/plistlib.py
@@ -48,7 +48,7 @@
__all__ = [
"readPlist", "writePlist", "readPlistFromBytes", "writePlistToBytes",
"Data", "InvalidFileException", "FMT_XML", "FMT_BINARY",
- "load", "dump", "loads", "dumps"
+ "load", "dump", "loads", "dumps", "UID"
]
import binascii
@@ -175,6 +175,34 @@ def __repr__(self):
#
+class UID:
+ def __init__(self, data):
+ if not isinstance(data, int):
+ raise TypeError("data must be an int")
+ if data >= 1 << 64:
+ raise ValueError("UIDs cannot be >= 2**64")
+ if data < 0:
+ raise ValueError("UIDs must be positive")
+ self.data = data
+
+ def __index__(self):
+ return self.data
+
+ def __repr__(self):
+ return "%s(%s)" % (self.__class__.__name__, repr(self.data))
+
+ def __reduce__(self):
+ return self.__class__, (self.data,)
+
+ def __eq__(self, other):
+ if not isinstance(other, UID):
+ return NotImplemented
+ return self.data == other.data
+
+ def __hash__(self):
+ return hash(self.data)
+
+
#
# XML support
#
@@ -649,8 +677,9 @@ def _read_object(self, ref):
s = self._get_size(tokenL)
result = self._fp.read(s * 2).decode('utf-16be')
- # tokenH == 0x80 is documented as 'UID' and appears to be used for
- # keyed-archiving, not in plists.
+ elif tokenH == 0x80: # UID
+ # used by Key-Archiver plist files
+ result = UID(int.from_bytes(self._fp.read(1 + tokenL), 'big'))
elif tokenH == 0xA0: # array
s = self._get_size(tokenL)
@@ -874,6 +903,20 @@ def _write_object(self, value):
self._fp.write(t)
+ elif isinstance(value, UID):
+ if value.data < 0:
+ raise ValueError("UIDs must be positive")
+ elif value.data < 1 << 8:
+ self._fp.write(struct.pack('>BB', 0x80, value))
+ elif value.data < 1 << 16:
+ self._fp.write(struct.pack('>BH', 0x81, value))
+ elif value.data < 1 << 32:
+ self._fp.write(struct.pack('>BL', 0x83, value))
+ elif value.data < 1 << 64:
+ self._fp.write(struct.pack('>BQ', 0x87, value))
+ else:
+ raise OverflowError(value)
+
elif isinstance(value, (list, tuple)):
refs = [self._getrefnum(o) for o in value]
s = len(refs)
diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py
index 8d8e0a750a2..5c2d0265079 100644
--- a/Lib/test/test_plistlib.py
+++ b/Lib/test/test_plistlib.py
@@ -1,5 +1,7 @@
# Copyright (C) 2003-2013 Python Software Foundation
-
+import copy
+import operator
+import pickle
import unittest
import plistlib
import os
@@ -10,6 +12,8 @@
from test import support
from io import BytesIO
+from plistlib import UID
+
ALL_FORMATS=(plistlib.FMT_XML, plistlib.FMT_BINARY)
# The testdata is generated using Mac/Tools/plistlib_generate_testdata.py
@@ -88,6 +92,17 @@
ZwB0AHwAiACUAJoApQCuALsAygDTAOQA7QD4AQQBDwEdASsBNgE3ATgBTwFn
AW4BcAFyAXQBdgF/AYMBhQGHAYwBlQGbAZ0BnwGhAaUBpwGwAbkBwAHBAcIB
xQHHAsQC0gAAAAAAAAIBAAAAAAAAADkAAAAAAAAAAAAAAAAAAALs'''),
+ 'KEYED_ARCHIVE': binascii.a2b_base64(b'''
+ YnBsaXN0MDDUAQIDBAUGHB1YJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVy
+ VCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVnB5dHlwZVYkY2xhc3NZTlMu
+ c3RyaW5nEAGAAl8QE0tleUFyY2hpdmUgVUlEIFRlc3TTEBESExQZWiRjbGFz
+ c25hbWVYJGNsYXNzZXNbJGNsYXNzaGludHNfEBdPQ19CdWlsdGluUHl0aG9u
+ VW5pY29kZaQVFhcYXxAXT0NfQnVpbHRpblB5dGhvblVuaWNvZGVfEBBPQ19Q
+ eXRob25Vbmljb2RlWE5TU3RyaW5nWE5TT2JqZWN0ohobXxAPT0NfUHl0aG9u
+ U3RyaW5nWE5TU3RyaW5nXxAPTlNLZXllZEFyY2hpdmVy0R4fVHJvb3SAAQAI
+ ABEAGgAjAC0AMgA3ADsAQQBIAE8AVgBgAGIAZAB6AIEAjACVAKEAuwDAANoA
+ 7QD2AP8BAgEUAR0BLwEyATcAAAAAAAACAQAAAAAAAAAgAAAAAAAAAAAAAAAA
+ AAABOQ=='''),
}
@@ -151,6 +166,14 @@ def test_invalid_type(self):
with self.subTest(fmt=fmt):
self.assertRaises(TypeError, plistlib.dumps, pl, fmt=fmt)
+ def test_invalid_uid(self):
+ with self.assertRaises(TypeError):
+ UID("not an int")
+ with self.assertRaises(ValueError):
+ UID(2 ** 64)
+ with self.assertRaises(ValueError):
+ UID(-19)
+
def test_int(self):
for pl in [0, 2**8-1, 2**8, 2**16-1, 2**16, 2**32-1, 2**32,
2**63-1, 2**64-1, 1, -2**63]:
@@ -200,6 +223,45 @@ def test_indentation_dict_mix(self):
data = {'1': {'2': [{'3': [[[[[{'test': b'aaaaaa'}]]]]]}]}}
self.assertEqual(plistlib.loads(plistlib.dumps(data)), data)
+ def test_uid(self):
+ data = UID(1)
+ self.assertEqual(plistlib.loads(plistlib.dumps(data, fmt=plistlib.FMT_BINARY)), data)
+ dict_data = {
+ 'uid0': UID(0),
+ 'uid2': UID(2),
+ 'uid8': UID(2 ** 8),
+ 'uid16': UID(2 ** 16),
+ 'uid32': UID(2 ** 32),
+ 'uid63': UID(2 ** 63)
+ }
+ self.assertEqual(plistlib.loads(plistlib.dumps(dict_data, fmt=plistlib.FMT_BINARY)), dict_data)
+
+ def test_uid_data(self):
+ uid = UID(1)
+ self.assertEqual(uid.data, 1)
+
+ def test_uid_eq(self):
+ self.assertEqual(UID(1), UID(1))
+ self.assertNotEqual(UID(1), UID(2))
+ self.assertNotEqual(UID(1), "not uid")
+
+ def test_uid_hash(self):
+ self.assertEqual(hash(UID(1)), hash(UID(1)))
+
+ def test_uid_repr(self):
+ self.assertEqual(repr(UID(1)), "UID(1)")
+
+ def test_uid_index(self):
+ self.assertEqual(operator.index(UID(1)), 1)
+
+ def test_uid_pickle(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ self.assertEqual(pickle.loads(pickle.dumps(UID(19), protocol=proto)), UID(19))
+
+ def test_uid_copy(self):
+ self.assertEqual(copy.copy(UID(1)), UID(1))
+ self.assertEqual(copy.deepcopy(UID(1)), UID(1))
+
def test_appleformatting(self):
for use_builtin_types in (True, False):
for fmt in ALL_FORMATS:
@@ -648,6 +710,38 @@ def test_dataobject_deprecated(self):
self.assertEqual(cur, in_data)
+class TestKeyedArchive(unittest.TestCase):
+ def test_keyed_archive_data(self):
+ # This is the structure of a NSKeyedArchive packed plist
+ data = {
+ '$version': 100000,
+ '$objects': [
+ '$null', {
+ 'pytype': 1,
+ '$class': UID(2),
+ 'NS.string': 'KeyArchive UID Test'
+ },
+ {
+ '$classname': 'OC_BuiltinPythonUnicode',
+ '$classes': [
+ 'OC_BuiltinPythonUnicode',
+ 'OC_PythonUnicode',
+ 'NSString',
+ 'NSObject'
+ ],
+ '$classhints': [
+ 'OC_PythonString', 'NSString'
+ ]
+ }
+ ],
+ '$archiver': 'NSKeyedArchiver',
+ '$top': {
+ 'root': UID(1)
+ }
+ }
+ self.assertEqual(plistlib.loads(TESTDATA["KEYED_ARCHIVE"]), data)
+
+
class MiscTestCase(unittest.TestCase):
def test__all__(self):
blacklist = {"PlistFormat", "PLISTHEADER"}
@@ -655,7 +749,7 @@ def test__all__(self):
def test_main():
- support.run_unittest(TestPlistlib, TestPlistlibDeprecated, MiscTestCase)
+ support.run_unittest(TestPlistlib, TestPlistlibDeprecated, TestKeyedArchive, MiscTestCase)
if __name__ == '__main__':
diff --git a/Mac/Tools/plistlib_generate_testdata.py b/Mac/Tools/plistlib_generate_testdata.py
index 057b61765b8..3349c604a37 100755
--- a/Mac/Tools/plistlib_generate_testdata.py
+++ b/Mac/Tools/plistlib_generate_testdata.py
@@ -5,6 +5,7 @@
from Cocoa import NSPropertyListXMLFormat_v1_0, NSPropertyListBinaryFormat_v1_0
from Cocoa import CFUUIDCreateFromString, NSNull, NSUUID, CFPropertyListCreateData
from Cocoa import NSURL
+from Cocoa import NSKeyedArchiver
import datetime
from collections import OrderedDict
@@ -89,6 +90,8 @@ def main():
else:
print(" %s: binascii.a2b_base64(b'''\n %s'''),"%(fmt_name, _encode_base64(bytes(data)).decode('ascii')[:-1]))
+ keyed_archive_data = NSKeyedArchiver.archivedDataWithRootObject_("KeyArchive UID Test")
+ print(" 'KEYED_ARCHIVE': binascii.a2b_base64(b'''\n %s''')," % (_encode_base64(bytes(keyed_archive_data)).decode('ascii')[:-1]))
print("}")
print()
diff --git a/Misc/ACKS b/Misc/ACKS
index ec5b017d515..f5a31a878c5 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -754,6 +754,7 @@ Geert Jansen
Jack Jansen
Hans-Peter Jansen
Bill Janssen
+Jon Janzen
Thomas Jarosch
Juhana Jauhiainen
Rajagopalasarma Jayakrishnan
diff --git a/Misc/NEWS.d/next/Library/2019-03-04-01-28-33.bpo-26707.QY4kRZ.rst b/Misc/NEWS.d/next/Library/2019-03-04-01-28-33.bpo-26707.QY4kRZ.rst
new file mode 100644
index 00000000000..ab76540c9ee
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-03-04-01-28-33.bpo-26707.QY4kRZ.rst
@@ -0,0 +1 @@
+Enable plistlib to read and write binary plist files that were created as a KeyedArchive file. Specifically, this allows the plistlib to process 0x80 tokens as UID objects.
\ No newline at end of file
From 1a2dd82f56bd813aacc570e172cefe55a8a41504 Mon Sep 17 00:00:00 2001
From: Antoine Pitrou
Date: Wed, 15 May 2019 23:45:18 +0200
Subject: [PATCH 062/199] bpo-36786: Run compileall in parallel during "make
install" (GH-13078)
---
Doc/library/compileall.rst | 6 ++++-
Lib/compileall.py | 25 ++++++++-----------
Lib/test/test_compileall.py | 2 +-
Makefile.pre.in | 12 ++++-----
.../2019-05-03-21-08-06.bpo-36786.gOLFbD.rst | 1 +
5 files changed, 24 insertions(+), 22 deletions(-)
create mode 100644 Misc/NEWS.d/next/Build/2019-05-03-21-08-06.bpo-36786.gOLFbD.rst
diff --git a/Doc/library/compileall.rst b/Doc/library/compileall.rst
index 5e08616e934..bb5000a0736 100644
--- a/Doc/library/compileall.rst
+++ b/Doc/library/compileall.rst
@@ -158,7 +158,8 @@ Public functions
The argument *workers* specifies how many workers are used to
compile files in parallel. The default is to not use multiple workers.
If the platform can't use multiple workers and *workers* argument is given,
- then sequential compilation will be used as a fallback. If *workers* is
+ then sequential compilation will be used as a fallback. If *workers*
+ is 0, the number of cores in the system is used. If *workers* is
lower than ``0``, a :exc:`ValueError` will be raised.
*invalidation_mode* should be a member of the
@@ -184,6 +185,9 @@ Public functions
.. versionchanged:: 3.7
The *invalidation_mode* parameter was added.
+ .. versionchanged:: 3.8
+ Setting *workers* to 0 now chooses the optimal number of cores.
+
.. function:: compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, invalidation_mode=py_compile.PycInvalidationMode.TIMESTAMP)
Compile the file with path *fullname*. Return a true value if the file
diff --git a/Lib/compileall.py b/Lib/compileall.py
index aa65c6b904e..49306d9dabb 100644
--- a/Lib/compileall.py
+++ b/Lib/compileall.py
@@ -67,20 +67,20 @@ def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
invalidation_mode: how the up-to-dateness of the pyc will be checked
"""
ProcessPoolExecutor = None
- if workers is not None:
- if workers < 0:
- raise ValueError('workers must be greater or equal to 0')
- elif workers != 1:
- try:
- # Only import when needed, as low resource platforms may
- # fail to import it
- from concurrent.futures import ProcessPoolExecutor
- except ImportError:
- workers = 1
+ if workers < 0:
+ raise ValueError('workers must be greater or equal to 0')
+ if workers != 1:
+ try:
+ # Only import when needed, as low resource platforms may
+ # fail to import it
+ from concurrent.futures import ProcessPoolExecutor
+ except ImportError:
+ workers = 1
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels,
ddir=ddir)
success = True
- if workers is not None and workers != 1 and ProcessPoolExecutor is not None:
+ 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,
@@ -290,9 +290,6 @@ def main():
print("Error reading file list {}".format(args.flist))
return False
- if args.workers is not None:
- args.workers = args.workers or None
-
if args.invalidation_mode:
ivl_mode = args.invalidation_mode.replace('-', '_').upper()
invalidation_mode = py_compile.PycInvalidationMode[ivl_mode]
diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py
index 8e584602de3..04f6e1e049d 100644
--- a/Lib/test/test_compileall.py
+++ b/Lib/test/test_compileall.py
@@ -575,7 +575,7 @@ def test_workers_available_cores(self, compile_dir):
new=[sys.executable, self.directory, "-j0"]):
compileall.main()
self.assertTrue(compile_dir.called)
- self.assertEqual(compile_dir.call_args[-1]['workers'], None)
+ self.assertEqual(compile_dir.call_args[-1]['workers'], 0)
class CommmandLineTestsWithSourceEpoch(CommandLineTestsBase,
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 75eb66be3c0..4924dedc357 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1432,30 +1432,30 @@ libinstall: build_all $(srcdir)/Modules/xxmodule.c
fi
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
$(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \
- -d $(LIBDEST) -f \
+ -j0 -d $(LIBDEST) -f \
-x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \
$(DESTDIR)$(LIBDEST)
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
$(PYTHON_FOR_BUILD) -Wi -O $(DESTDIR)$(LIBDEST)/compileall.py \
- -d $(LIBDEST) -f \
+ -j0 -d $(LIBDEST) -f \
-x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \
$(DESTDIR)$(LIBDEST)
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
$(PYTHON_FOR_BUILD) -Wi -OO $(DESTDIR)$(LIBDEST)/compileall.py \
- -d $(LIBDEST) -f \
+ -j0 -d $(LIBDEST) -f \
-x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \
$(DESTDIR)$(LIBDEST)
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
$(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \
- -d $(LIBDEST)/site-packages -f \
+ -j0 -d $(LIBDEST)/site-packages -f \
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
$(PYTHON_FOR_BUILD) -Wi -O $(DESTDIR)$(LIBDEST)/compileall.py \
- -d $(LIBDEST)/site-packages -f \
+ -j0 -d $(LIBDEST)/site-packages -f \
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
$(PYTHON_FOR_BUILD) -Wi -OO $(DESTDIR)$(LIBDEST)/compileall.py \
- -d $(LIBDEST)/site-packages -f \
+ -j0 -d $(LIBDEST)/site-packages -f \
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
$(PYTHON_FOR_BUILD) -m lib2to3.pgen2.driver $(DESTDIR)$(LIBDEST)/lib2to3/Grammar.txt
diff --git a/Misc/NEWS.d/next/Build/2019-05-03-21-08-06.bpo-36786.gOLFbD.rst b/Misc/NEWS.d/next/Build/2019-05-03-21-08-06.bpo-36786.gOLFbD.rst
new file mode 100644
index 00000000000..0fcda434a79
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2019-05-03-21-08-06.bpo-36786.gOLFbD.rst
@@ -0,0 +1 @@
+"make install" now runs compileall in parallel.
From d9e006bcefe6fac859b1b5d741725b9a91991044 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E2=80=AEzlohhcuB=20treboR?=
Date: Thu, 16 May 2019 00:02:11 +0200
Subject: [PATCH 063/199] bpo-33123: pathlib: Add missing_ok parameter to
Path.unlink (GH-6191)
Similarly to how several pathlib file creation functions have an "exists_ok" parameter, we should introduce "missing_ok" that makes removal functions not raise an exception when a file or directory is already absent. IMHO, this should cover Path.unlink and Path.rmdir. Note, Path.resolve() has a "strict" parameter since 3.6 that does the same thing. Naming this of this new parameter tries to be consistent with the "exists_ok" parameter as that is more explicit about what it does (as opposed to "strict").
https://bugs.python.org/issue33123
---
Doc/library/pathlib.rst | 11 ++++++++++-
Lib/pathlib.py | 8 ++++++--
Lib/test/test_pathlib.py | 5 +++++
.../Library/2018-03-22-19-13-19.bpo-33123._Y5ooE.rst | 2 ++
4 files changed, 23 insertions(+), 3 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2018-03-22-19-13-19.bpo-33123._Y5ooE.rst
diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
index 41aebc4f61c..166de8de1f0 100644
--- a/Doc/library/pathlib.rst
+++ b/Doc/library/pathlib.rst
@@ -1048,11 +1048,20 @@ call fails (for example because the path doesn't exist).
otherwise :exc:`FileExistsError` is raised.
-.. method:: Path.unlink()
+.. method:: Path.unlink(missing_ok=False)
Remove this file or symbolic link. If the path points to a directory,
use :func:`Path.rmdir` instead.
+ If *missing_ok* is false (the default), :exc:`FileNotFoundError` is
+ raised if the path does not exist.
+
+ If *missing_ok* is true, :exc:`FileNotFoundError` exceptions will be
+ ignored (same behavior as the POSIX ``rm -f`` command).
+
+ .. versionchanged:: 3.8
+ The *missing_ok* parameter was added.
+
.. method:: Path.link_to(target)
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 952cd94921e..b5bab1fe8f5 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -1279,14 +1279,18 @@ def lchmod(self, mode):
self._raise_closed()
self._accessor.lchmod(self, mode)
- def unlink(self):
+ def unlink(self, missing_ok=False):
"""
Remove this file or link.
If the path is a directory, use rmdir() instead.
"""
if self._closed:
self._raise_closed()
- self._accessor.unlink(self)
+ try:
+ self._accessor.unlink(self)
+ except FileNotFoundError:
+ if not missing_ok:
+ raise
def rmdir(self):
"""
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index 990207b9c4e..caad1c23876 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -1635,6 +1635,11 @@ def test_unlink(self):
self.assertFileNotFound(p.stat)
self.assertFileNotFound(p.unlink)
+ def test_unlink_missing_ok(self):
+ p = self.cls(BASE) / 'fileAAA'
+ self.assertFileNotFound(p.unlink)
+ p.unlink(missing_ok=True)
+
def test_rmdir(self):
p = self.cls(BASE) / 'dirA'
for q in p.iterdir():
diff --git a/Misc/NEWS.d/next/Library/2018-03-22-19-13-19.bpo-33123._Y5ooE.rst b/Misc/NEWS.d/next/Library/2018-03-22-19-13-19.bpo-33123._Y5ooE.rst
new file mode 100644
index 00000000000..8803ca84313
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-03-22-19-13-19.bpo-33123._Y5ooE.rst
@@ -0,0 +1,2 @@
+:class:`pathlib.Path.unlink` now accepts a *missing_ok* parameter to avoid a
+:exc:`FileNotFoundError` from being raised. Patch by Robert Buchholz.
From fb7e7505ed1337bf40fa7b8b68317d1e86675a86 Mon Sep 17 00:00:00 2001
From: Paul Monson
Date: Wed, 15 May 2019 15:38:55 -0700
Subject: [PATCH 064/199] bpo-35926: Add support for OpenSSL 1.1.1b on Windows
(GH-11779)
---
.azure-pipelines/ci.yml | 4 +-
Lib/test/test_asyncio/test_sslproto.py | 4 +-
Lib/test/test_ssl.py | 19 +++++-
Misc/ACKS | 1 +
.../2019-03-01-16-43-45.bpo-35926.mLszHo.rst | 1 +
Modules/_ssl.c | 2 +-
PCbuild/get_externals.bat | 4 +-
PCbuild/openssl.props | 3 +-
PCbuild/openssl.vcxproj | 63 ++++++++++---------
PCbuild/prepare_ssl.bat | 6 +-
PCbuild/python.props | 5 +-
PCbuild/readme.txt | 2 +-
12 files changed, 71 insertions(+), 43 deletions(-)
create mode 100644 Misc/NEWS.d/next/Windows/2019-03-01-16-43-45.bpo-35926.mLszHo.rst
diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml
index 15a83dd0370..1576599379c 100644
--- a/.azure-pipelines/ci.yml
+++ b/.azure-pipelines/ci.yml
@@ -59,7 +59,7 @@ jobs:
variables:
testRunTitle: '$(build.sourceBranchName)-linux'
testRunPlatform: linux
- openssl_version: 1.1.0j
+ openssl_version: 1.1.1b
steps:
- template: ./posix-steps.yml
@@ -116,7 +116,7 @@ jobs:
variables:
testRunTitle: '$(Build.SourceBranchName)-linux-coverage'
testRunPlatform: linux-coverage
- openssl_version: 1.1.0j
+ openssl_version: 1.1.1b
steps:
- template: ./posix-steps.yml
diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py
index 7bc2ccf0bdd..079b2558556 100644
--- a/Lib/test/test_asyncio/test_sslproto.py
+++ b/Lib/test/test_asyncio/test_sslproto.py
@@ -497,8 +497,8 @@ def test_start_tls_server_1(self):
server_context = test_utils.simple_server_sslcontext()
client_context = test_utils.simple_client_sslcontext()
- if sys.platform.startswith('freebsd'):
- # bpo-35031: Some FreeBSD buildbots fail to run this test
+ if sys.platform.startswith('freebsd') or sys.platform.startswith('win'):
+ # bpo-35031: Some FreeBSD and Windows buildbots fail to run this test
# as the eof was not being received by the server if the payload
# size is not big enough. This behaviour only appears if the
# client is using TLS1.3.
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 5b53b8250f6..d48d6e5569f 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -2188,7 +2188,7 @@ def wrap_conn(self):
self.sock, server_side=True)
self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol())
self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
- except (ConnectionResetError, BrokenPipeError) as e:
+ except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError) as e:
# We treat ConnectionResetError as though it were an
# SSLError - OpenSSL on Ubuntu abruptly closes the
# connection when asked to use an unsupported protocol.
@@ -2196,6 +2196,9 @@ def wrap_conn(self):
# BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
# tries to send session tickets after handshake.
# https://github.com/openssl/openssl/issues/6342
+ #
+ # ConnectionAbortedError is raised in TLS 1.3 mode, when OpenSSL
+ # tries to send session tickets after handshake when using WinSock.
self.server.conn_errors.append(str(e))
if self.server.chatty:
handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
@@ -2326,7 +2329,7 @@ def run(self):
sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n"
% (msg, ctype, msg.lower(), ctype))
self.write(msg.lower())
- except ConnectionResetError:
+ except (ConnectionResetError, ConnectionAbortedError):
# XXX: OpenSSL 1.1.1 sometimes raises ConnectionResetError
# when connection is not shut down gracefully.
if self.server.chatty and support.verbose:
@@ -2336,6 +2339,18 @@ def run(self):
)
self.close()
self.running = False
+ except ssl.SSLError as err:
+ # On Windows sometimes test_pha_required_nocert receives the
+ # PEER_DID_NOT_RETURN_A_CERTIFICATE exception
+ # before the 'tlsv13 alert certificate required' exception.
+ # If the server is stopped when PEER_DID_NOT_RETURN_A_CERTIFICATE
+ # is received test_pha_required_nocert fails with ConnectionResetError
+ # because the underlying socket is closed
+ if 'PEER_DID_NOT_RETURN_A_CERTIFICATE' == err.reason:
+ if self.server.chatty and support.verbose:
+ sys.stdout.write(err.args[1])
+ # test_pha_required_nocert is expecting this exception
+ raise ssl.SSLError('tlsv13 alert certificate required')
except OSError:
if self.server.chatty:
handle_error("Test server failure:\n")
diff --git a/Misc/ACKS b/Misc/ACKS
index f5a31a878c5..06e288dfcb2 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1104,6 +1104,7 @@ Florian Mladitsch
Doug Moen
Jakub Molinski
Juliette Monsel
+Paul Monson
The Dragon De Monsyne
Bastien Montagne
Skip Montanaro
diff --git a/Misc/NEWS.d/next/Windows/2019-03-01-16-43-45.bpo-35926.mLszHo.rst b/Misc/NEWS.d/next/Windows/2019-03-01-16-43-45.bpo-35926.mLszHo.rst
new file mode 100644
index 00000000000..03249c6a168
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2019-03-01-16-43-45.bpo-35926.mLszHo.rst
@@ -0,0 +1 @@
+Update to OpenSSL 1.1.1b for Windows.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index e75e3466dd3..390a1af1e59 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -669,7 +669,7 @@ fill_and_set_sslerror(PySSLSocket *sslsock, PyObject *type, int ssl_errno,
if (msg == NULL)
goto fail;
- init_value = Py_BuildValue("iN", ssl_errno, msg);
+ init_value = Py_BuildValue("iN", ERR_GET_REASON(ssl_errno), msg);
if (init_value == NULL)
goto fail;
diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat
index b82b6e6588e..42ffe6f485f 100644
--- a/PCbuild/get_externals.bat
+++ b/PCbuild/get_externals.bat
@@ -53,7 +53,7 @@ echo.Fetching external libraries...
set libraries=
set libraries=%libraries% bzip2-1.0.6
if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.3.0-rc0-r1
-if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.0j
+if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1b
set libraries=%libraries% sqlite-3.21.0.0
if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.9.0
if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.9.0
@@ -77,7 +77,7 @@ echo.Fetching external binaries...
set binaries=
if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi
-if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.0j
+if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1b
if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.9.0
if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06
diff --git a/PCbuild/openssl.props b/PCbuild/openssl.props
index 8c78cd4ab10..a7e16793c7f 100644
--- a/PCbuild/openssl.props
+++ b/PCbuild/openssl.props
@@ -11,7 +11,8 @@
<_DLLSuffix>-1_1
- <_DLLSuffix Condition="$(Platform) == 'x64'">$(_DLLSuffix)-x64
+ <_DLLSuffix Condition="$(Platform) == 'ARM'">$(_DLLSuffix)-arm
+ <_DLLSuffix Condition="$(Platform) == 'ARM64'">$(_DLLSuffix)-arm64
<_SSLDLL Include="$(opensslOutDir)\libcrypto$(_DLLSuffix).dll" />
diff --git a/PCbuild/openssl.vcxproj b/PCbuild/openssl.vcxproj
index 1a36d08ec06..0da6f674958 100644
--- a/PCbuild/openssl.vcxproj
+++ b/PCbuild/openssl.vcxproj
@@ -1,38 +1,22 @@

-
- Debug
- Win32
- ReleaseWin32
-
- PGInstrument
- Win32
-
-
- PGInstrument
- x64
-
-
- PGUpdate
- Win32
-
-
- PGUpdate
- x64
-
-
- Debug
- x64
- Releasex64
+
+ Release
+ ARM
+
+
+ Release
+ ARM64
+ {B5FD6F1D-129E-4BFF-9340-03606FAC7283}
@@ -40,15 +24,36 @@
-
-
+
+ Makefile32
- 64x86
- amd64VC-WIN32
- VC-WIN64A
+ true
+
+
+
+ Makefile
+ 64
+ amd64
+ VC-WIN64A-masm
+ true
+
+
+
+ Makefile
+ ARM
+ ARM
+ VC-WIN32-ARM
+ true
+
+
+
+ Makefile
+ ARM64
+ ARM64
+ VC-WIN64-ARMtrue
diff --git a/PCbuild/prepare_ssl.bat b/PCbuild/prepare_ssl.bat
index bd4b548528c..88fd0225f5e 100644
--- a/PCbuild/prepare_ssl.bat
+++ b/PCbuild/prepare_ssl.bat
@@ -42,7 +42,7 @@ if ERRORLEVEL 1 (echo Cannot locate MSBuild.exe on PATH or as MSBUILD variable &
call "%PCBUILD%\find_python.bat" "%PYTHON%"
if ERRORLEVEL 1 (echo Cannot locate python.exe on PATH or as PYTHON variable & exit /b 3)
-call "%PCBUILD%\get_externals.bat" --openssl-src %ORG_SETTING%
+call "%PCBUILD%\get_externals.bat" --openssl-src --no-openssl %ORG_SETTING%
if "%PERL%" == "" where perl > "%TEMP%\perl.loc" 2> nul && set /P PERL= <"%TEMP%\perl.loc" & del "%TEMP%\perl.loc"
if "%PERL%" == "" (echo Cannot locate perl.exe on PATH or as PERL variable & exit /b 4)
@@ -51,4 +51,8 @@ if "%PERL%" == "" (echo Cannot locate perl.exe on PATH or as PERL variable & exi
if errorlevel 1 exit /b
%MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=x64
if errorlevel 1 exit /b
+%MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=ARM
+if errorlevel 1 exit /b
+%MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=ARM64
+if errorlevel 1 exit /b
diff --git a/PCbuild/python.props b/PCbuild/python.props
index 52bc99e0560..b3e5b92f292 100644
--- a/PCbuild/python.props
+++ b/PCbuild/python.props
@@ -26,6 +26,7 @@
-->
amd64arm32
+ arm64win32
@@ -56,8 +57,8 @@
$(ExternalsDir)libffi\$(ExternalsDir)libffi\$(ArchName)\$(libffiOutDir)include
- $(ExternalsDir)openssl-1.1.0j\
- $(ExternalsDir)openssl-bin-1.1.0j\$(ArchName)\
+ $(ExternalsDir)openssl-1.1.1b\
+ $(ExternalsDir)openssl-bin-1.1.1b\$(ArchName)\$(opensslOutDir)include$(ExternalsDir)\nasm-2.11.06\$(ExternalsDir)\zlib-1.2.11\
diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt
index c8473286119..cf4aa4c9175 100644
--- a/PCbuild/readme.txt
+++ b/PCbuild/readme.txt
@@ -165,7 +165,7 @@ _lzma
Homepage:
http://tukaani.org/xz/
_ssl
- Python wrapper for version 1.1.0h of the OpenSSL secure sockets
+ Python wrapper for version 1.1.1b of the OpenSSL secure sockets
library, which is downloaded from our binaries repository at
https://github.com/python/cpython-bin-deps.
From 67ff6a103a1184b572750c30e231968c963e72f8 Mon Sep 17 00:00:00 2001
From: Paul Monson
Date: Wed, 15 May 2019 15:42:29 -0700
Subject: [PATCH 065/199] bpo-36511: Windows ARM32 buildbot changes (GH-12917)
---
PCbuild/rt.bat | 1 +
Tools/buildbot/test.bat | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/PCbuild/rt.bat b/PCbuild/rt.bat
index 212befc95b0..e603de6d517 100644
--- a/PCbuild/rt.bat
+++ b/PCbuild/rt.bat
@@ -39,6 +39,7 @@ if "%1"=="-O" (set dashO=-O) & shift & goto CheckOpts
if "%1"=="-q" (set qmode=yes) & shift & goto CheckOpts
if "%1"=="-d" (set suffix=_d) & shift & goto CheckOpts
if "%1"=="-x64" (set prefix=%pcbuild%amd64) & shift & goto CheckOpts
+if "%1"=="-arm32" (set prefix=%pcbuild%arm32) & shift & goto CheckOpts
if NOT "%1"=="" (set regrtestargs=%regrtestargs% %1) & shift & goto CheckOpts
if not defined prefix set prefix=%pcbuild%win32
diff --git a/Tools/buildbot/test.bat b/Tools/buildbot/test.bat
index 40ffc7efdd2..7815c55c152 100644
--- a/Tools/buildbot/test.bat
+++ b/Tools/buildbot/test.bat
@@ -5,9 +5,11 @@ setlocal
set here=%~dp0
set rt_opts=-q -d
set regrtest_args=-j1
+set arm32_ssh=
:CheckOpts
if "%1"=="-x64" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
+if "%1"=="-arm32" (set rt_opts=%rt_opts% %1) & (set arm32_ssh=true) & shift & goto CheckOpts
if "%1"=="-d" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
if "%1"=="-O" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
if "%1"=="-q" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
@@ -16,4 +18,37 @@ if "%1"=="+q" (set rt_opts=%rt_opts:-q=%) & shift & goto CheckOpts
if NOT "%1"=="" (set regrtest_args=%regrtest_args% %1) & shift & goto CheckOpts
echo on
+if "%arm32_ssh%"=="true" goto :Arm32Ssh
+
call "%here%..\..\PCbuild\rt.bat" %rt_opts% -uall -rwW --slowest --timeout=1200 --fail-env-changed %regrtest_args%
+exit /b 0
+
+:Arm32Ssh
+set dashU=-unetwork,decimal,subprocess,urlfetch,tzdata
+if "%SSH_SERVER%"=="" goto :Arm32SshHelp
+if "%PYTHON_SOURCE%"=="" (set PYTHON_SOURCE=%here%..\..\)
+if "%REMOTE_PYTHON_DIR%"=="" (set REMOTE_PYTHON_DIR=C:\python\)
+set TEMP_ARGS=--temp %REMOTE_PYTHON_DIR%temp
+ssh %SSH_SERVER% "if EXIST %REMOTE_PYTHON_DIR% (rd %REMOTE_PYTHON_DIR% /s/q)"
+ssh %SSH_SERVER% "md %REMOTE_PYTHON_DIR%PCBuild\arm32"
+ssh %SSH_SERVER% "md %REMOTE_PYTHON_DIR%temp"
+for /f "USEBACKQ" %%i in (`dir PCbuild\*.bat /b`) do @scp PCBuild\%%i "%SSH_SERVER%:%REMOTE_PYTHON_DIR%PCBuild"
+for /f "USEBACKQ" %%i in (`dir PCbuild\*.py /b`) do @scp PCBuild\%%i "%SSH_SERVER%:%REMOTE_PYTHON_DIR%PCBuild"
+for /f "USEBACKQ" %%i in (`dir PCbuild\arm32\*.exe /b`) do @scp PCBuild\arm32\%%i "%SSH_SERVER%:%REMOTE_PYTHON_DIR%PCBuild\arm32"
+for /f "USEBACKQ" %%i in (`dir PCbuild\arm32\*.pyd /b`) do @scp PCBuild\arm32\%%i "%SSH_SERVER%:%REMOTE_PYTHON_DIR%PCBuild\arm32"
+for /f "USEBACKQ" %%i in (`dir PCbuild\arm32\*.dll /b`) do @scp PCBuild\arm32\%%i "%SSH_SERVER%:%REMOTE_PYTHON_DIR%PCBuild\arm32"
+scp -r "%PYTHON_SOURCE%Include" "%SSH_SERVER%:%REMOTE_PYTHON_DIR%Include"
+scp -r "%PYTHON_SOURCE%Lib" "%SSH_SERVER%:%REMOTE_PYTHON_DIR%Lib"
+
+set rt_args=%rt_opts% %dashU% -rwW --slowest --timeout=1200 --fail-env-changed %regrtest_args% %TEMP_ARGS%
+ssh %SSH_SERVER% "set TEMP=%REMOTE_PYTHON_DIR%temp & %REMOTE_PYTHON_DIR%PCbuild\rt.bat" %rt_args%
+exit /b 0
+
+:Arm32SshHelp
+echo SSH_SERVER environment variable must be set to administrator@[ip address]
+echo where [ip address] is the address of a Windows IoT Core ARM32 device.
+echo.
+echo The test worker should have the SSH agent running.
+echo Also a key must be created with ssh-keygen and added to both the buildbot worker machine
+echo and the ARM32 worker device: see https://docs.microsoft.com/en-us/windows/iot-core/connect-your-device/ssh
+exit /b 127
From 4f820723c86c94f857d8d8de47a3c28f985946bd Mon Sep 17 00:00:00 2001
From: Paul Monson
Date: Wed, 15 May 2019 16:10:39 -0700
Subject: [PATCH 066/199] bpo-36511: Windows arm32 buildbot changes (remove
extra space) (GH-13351)
@zooba
I just realized that this whitespace fix didn't get pushed.
https://bugs.python.org/issue36511
---
Tools/buildbot/test.bat | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Tools/buildbot/test.bat b/Tools/buildbot/test.bat
index 7815c55c152..b84e8e25567 100644
--- a/Tools/buildbot/test.bat
+++ b/Tools/buildbot/test.bat
@@ -41,7 +41,7 @@ scp -r "%PYTHON_SOURCE%Include" "%SSH_SERVER%:%REMOTE_PYTHON_DIR%Include"
scp -r "%PYTHON_SOURCE%Lib" "%SSH_SERVER%:%REMOTE_PYTHON_DIR%Lib"
set rt_args=%rt_opts% %dashU% -rwW --slowest --timeout=1200 --fail-env-changed %regrtest_args% %TEMP_ARGS%
-ssh %SSH_SERVER% "set TEMP=%REMOTE_PYTHON_DIR%temp & %REMOTE_PYTHON_DIR%PCbuild\rt.bat" %rt_args%
+ssh %SSH_SERVER% "set TEMP=%REMOTE_PYTHON_DIR%temp& %REMOTE_PYTHON_DIR%PCbuild\rt.bat" %rt_args%
exit /b 0
:Arm32SshHelp
From 9b5a0efcdc5b6d23b6e05bb3d30263983b7da308 Mon Sep 17 00:00:00 2001
From: Xtreak
Date: Thu, 16 May 2019 10:04:24 +0530
Subject: [PATCH 067/199] Fix typos in documentation (#13344)
---
Doc/faq/programming.rst | 2 +-
Doc/library/pickle.rst | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst
index f14e8cc824e..9660a701427 100644
--- a/Doc/faq/programming.rst
+++ b/Doc/faq/programming.rst
@@ -792,7 +792,7 @@ Its documentation looks like this::
invoked using the three argument form.
The slash at the end of the parameter list means that all three parameters are
-positional-only. Thus, calling :func:`pow` with keyword aguments would lead to
+positional-only. Thus, calling :func:`pow` with keyword arguments would lead to
an error::
>>> pow(x=3, y=4)
diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst
index 55005f00943..27721e69882 100644
--- a/Doc/library/pickle.rst
+++ b/Doc/library/pickle.rst
@@ -642,7 +642,7 @@ or both.
by other classes as long as they implement :meth:`__setitem__`.
* Optionally, a callable with a ``(obj, state)`` signature. This
- callable allows the user to programatically control the state-updating
+ callable allows the user to programmatically control the state-updating
behavior of a specific object, instead of using ``obj``'s static
:meth:`__setstate__` method. If not ``None``, this callable will have
priority over ``obj``'s :meth:`__setstate__`.
From 8a533ffb499b168ed4bdb707c9919290631e267d Mon Sep 17 00:00:00 2001
From: Terry Jan Reedy
Date: Thu, 16 May 2019 01:20:37 -0400
Subject: [PATCH 068/199] Fix typos in documentation. Patch by tirkarthi.
(GH-13354)
---
Doc/library/idle.rst | 4 ++--
Lib/idlelib/help.html | 12 ++++++------
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst
index ad449112832..f511d64b550 100644
--- a/Doc/library/idle.rst
+++ b/Doc/library/idle.rst
@@ -50,7 +50,7 @@ default title and context menu.
On macOS, there is one application menu. It dynamically changes according
to the window currently selected. It has an IDLE menu, and some entries
-described below are moved around to conform to Apple guidlines.
+described below are moved around to conform to Apple guidelines.
File menu (Shell and Editor)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -769,7 +769,7 @@ facilitate development of tkinter programs. Enter ``import tkinter as tk;
root = tk.Tk()`` in standard Python and nothing appears. Enter the same
in IDLE and a tk window appears. In standard Python, one must also enter
``root.update()`` to see the window. IDLE does the equivalent in the
-background, about 20 times a second, which is about every 50 milleseconds.
+background, about 20 times a second, which is about every 50 milliseconds.
Next enter ``b = tk.Button(root, text='button'); b.pack()``. Again,
nothing visibly changes in standard Python until one enters ``root.update()``.
diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html
index ba44331e87b..56f9ca503da 100644
--- a/Lib/idlelib/help.html
+++ b/Lib/idlelib/help.html
@@ -6,7 +6,7 @@
- IDLE — Python 3.8.0a3 documentation
+ IDLE — Python 3.8.0a4 documentation
@@ -19,7 +19,7 @@
@@ -72,7 +72,7 @@
@@ -130,7 +130,7 @@ window. They currently have the same top menu but a different
default title and context menu.
On macOS, there is one application menu. It dynamically changes according
to the window currently selected. It has an IDLE menu, and some entries
-described below are moved around to conform to Apple guidlines.
+described below are moved around to conform to Apple guidelines.
- Last updated on Apr 26, 2019.
+ Last updated on May 16, 2019.
Found a bug?
From bfba8c373e362d48d4ee0e0cf55b8d9c169344ae Mon Sep 17 00:00:00 2001
From: Inada Naoki
Date: Thu, 16 May 2019 15:03:20 +0900
Subject: [PATCH 069/199] bpo-36748: optimize TextIOWrapper.write() for ASCII
string (GH-13002)
---
.../2019-04-29-15-18-13.bpo-36748.YBKWps.rst | 3 +
Modules/_io/textio.c | 116 ++++++++++++++----
2 files changed, 98 insertions(+), 21 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-04-29-15-18-13.bpo-36748.YBKWps.rst
diff --git a/Misc/NEWS.d/next/Library/2019-04-29-15-18-13.bpo-36748.YBKWps.rst b/Misc/NEWS.d/next/Library/2019-04-29-15-18-13.bpo-36748.YBKWps.rst
new file mode 100644
index 00000000000..0eacc3c99cd
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-04-29-15-18-13.bpo-36748.YBKWps.rst
@@ -0,0 +1,3 @@
+Optimized write buffering in C implementation of ``TextIOWrapper``. Writing
+ASCII string to ``TextIOWrapper`` with ascii, latin1, or utf-8 encoding is
+about 20% faster. Patch by Inada Naoki.
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 8c391659ecd..a08ab5b0e27 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -674,8 +674,8 @@ typedef struct
*/
PyObject *decoded_chars; /* buffer for text returned from decoder */
Py_ssize_t decoded_chars_used; /* offset into _decoded_chars for read() */
- PyObject *pending_bytes; /* list of bytes objects waiting to be
- written, or NULL */
+ PyObject *pending_bytes; // data waiting to be written.
+ // ascii unicode, bytes, or list of them.
Py_ssize_t pending_bytes_count;
/* snapshot is either NULL, or a tuple (dec_flags, next_input) where
@@ -777,6 +777,15 @@ latin1_encode(textio *self, PyObject *text)
return _PyUnicode_AsLatin1String(text, PyUnicode_AsUTF8(self->errors));
}
+// Return true when encoding can be skipped when text is ascii.
+static inline int
+is_asciicompat_encoding(encodefunc_t f)
+{
+ return f == (encodefunc_t) ascii_encode
+ || f == (encodefunc_t) latin1_encode
+ || f == (encodefunc_t) utf8_encode;
+}
+
/* Map normalized encoding names onto the specialized encoding funcs */
typedef struct {
@@ -1489,21 +1498,62 @@ _io_TextIOWrapper_detach_impl(textio *self)
static int
_textiowrapper_writeflush(textio *self)
{
- PyObject *pending, *b, *ret;
-
if (self->pending_bytes == NULL)
return 0;
- pending = self->pending_bytes;
- Py_INCREF(pending);
- self->pending_bytes_count = 0;
- Py_CLEAR(self->pending_bytes);
+ PyObject *pending = self->pending_bytes;
+ PyObject *b;
- b = _PyBytes_Join(_PyIO_empty_bytes, pending);
+ if (PyBytes_Check(pending)) {
+ b = pending;
+ Py_INCREF(b);
+ }
+ else if (PyUnicode_Check(pending)) {
+ assert(PyUnicode_IS_ASCII(pending));
+ assert(PyUnicode_GET_LENGTH(pending) == self->pending_bytes_count);
+ b = PyBytes_FromStringAndSize(
+ PyUnicode_DATA(pending), PyUnicode_GET_LENGTH(pending));
+ if (b == NULL) {
+ return -1;
+ }
+ }
+ else {
+ assert(PyList_Check(pending));
+ b = PyBytes_FromStringAndSize(NULL, self->pending_bytes_count);
+ if (b == NULL) {
+ return -1;
+ }
+
+ char *buf = PyBytes_AsString(b);
+ Py_ssize_t pos = 0;
+
+ for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pending); i++) {
+ PyObject *obj = PyList_GET_ITEM(pending, i);
+ char *src;
+ Py_ssize_t len;
+ if (PyUnicode_Check(obj)) {
+ assert(PyUnicode_IS_ASCII(obj));
+ src = PyUnicode_DATA(obj);
+ len = PyUnicode_GET_LENGTH(obj);
+ }
+ else {
+ assert(PyBytes_Check(obj));
+ if (PyBytes_AsStringAndSize(obj, &src, &len) < 0) {
+ Py_DECREF(b);
+ return -1;
+ }
+ }
+ memcpy(buf + pos, src, len);
+ pos += len;
+ }
+ assert(pos == self->pending_bytes_count);
+ }
+
+ self->pending_bytes_count = 0;
+ self->pending_bytes = NULL;
Py_DECREF(pending);
- if (b == NULL)
- return -1;
- ret = NULL;
+
+ PyObject *ret;
do {
ret = PyObject_CallMethodObjArgs(self->buffer,
_PyIO_str_write, b, NULL);
@@ -1566,16 +1616,23 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text)
/* XXX What if we were just reading? */
if (self->encodefunc != NULL) {
- b = (*self->encodefunc)((PyObject *) self, text);
+ if (PyUnicode_IS_ASCII(text) && is_asciicompat_encoding(self->encodefunc)) {
+ b = text;
+ Py_INCREF(b);
+ }
+ else {
+ b = (*self->encodefunc)((PyObject *) self, text);
+ }
self->encoding_start_of_stream = 0;
}
else
b = PyObject_CallMethodObjArgs(self->encoder,
_PyIO_str_encode, text, NULL);
+
Py_DECREF(text);
if (b == NULL)
return NULL;
- if (!PyBytes_Check(b)) {
+ if (b != text && !PyBytes_Check(b)) {
PyErr_Format(PyExc_TypeError,
"encoder should return a bytes object, not '%.200s'",
Py_TYPE(b)->tp_name);
@@ -1583,20 +1640,37 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text)
return NULL;
}
+ Py_ssize_t bytes_len;
+ if (b == text) {
+ bytes_len = PyUnicode_GET_LENGTH(b);
+ }
+ else {
+ bytes_len = PyBytes_GET_SIZE(b);
+ }
+
if (self->pending_bytes == NULL) {
- self->pending_bytes = PyList_New(0);
- if (self->pending_bytes == NULL) {
+ self->pending_bytes_count = 0;
+ self->pending_bytes = b;
+ }
+ else if (!PyList_CheckExact(self->pending_bytes)) {
+ PyObject *list = PyList_New(2);
+ if (list == NULL) {
Py_DECREF(b);
return NULL;
}
- self->pending_bytes_count = 0;
+ PyList_SET_ITEM(list, 0, self->pending_bytes);
+ PyList_SET_ITEM(list, 1, b);
+ self->pending_bytes = list;
}
- if (PyList_Append(self->pending_bytes, b) < 0) {
+ else {
+ if (PyList_Append(self->pending_bytes, b) < 0) {
+ Py_DECREF(b);
+ return NULL;
+ }
Py_DECREF(b);
- return NULL;
}
- self->pending_bytes_count += PyBytes_GET_SIZE(b);
- Py_DECREF(b);
+
+ self->pending_bytes_count += bytes_len;
if (self->pending_bytes_count > self->chunk_size || needflush ||
text_needflush) {
if (_textiowrapper_writeflush(self) < 0)
From 6e7890028213b30939327e7cf885bf097fc14472 Mon Sep 17 00:00:00 2001
From: Andrew Svetlov
Date: Thu, 16 May 2019 16:30:16 +0300
Subject: [PATCH 070/199] bpo-35589: Prevent buffer copy in sock_sendall()
(GH-11418)
No NEWs is needed since the problem was introduced on master only and never released.
https://bugs.python.org/issue35589
---
Lib/asyncio/selector_events.py | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 29968214f8e..6461d307763 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -428,32 +428,35 @@ async def sock_sendall(self, sock, data):
if n == len(data):
# all data sent
return
- else:
- data = bytearray(memoryview(data)[n:])
fut = self.create_future()
fd = sock.fileno()
fut.add_done_callback(
functools.partial(self._sock_write_done, fd))
- self.add_writer(fd, self._sock_sendall, fut, sock, data)
+ # use a trick with a list in closure to store a mutable state
+ self.add_writer(fd, self._sock_sendall, fut, sock,
+ memoryview(data), [n])
return await fut
- def _sock_sendall(self, fut, sock, data):
+ def _sock_sendall(self, fut, sock, view, pos):
if fut.done():
# Future cancellation can be scheduled on previous loop iteration
return
+ start = pos[0]
try:
- n = sock.send(data)
+ n = sock.send(view[start:])
except (BlockingIOError, InterruptedError):
return
except Exception as exc:
fut.set_exception(exc)
return
- if n == len(data):
+ start += n
+
+ if start == len(view):
fut.set_result(None)
else:
- del data[:n]
+ pos[0] = start
async def sock_connect(self, sock, address):
"""Connect to a remote socket at address.
From dbacfc227381fbc7b3c886ea0bd7806ab3dc62c2 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Thu, 16 May 2019 16:39:26 +0200
Subject: [PATCH 071/199] bpo-36763: _PyInitError always use int for exitcode
(GH-13360)
We cannot use "unsigned int" for exitcode on Windows, since
Py_Main() and _Py_RunMain() always return an "int".
Changes:
* _PyPathConfig_ComputeSysPath0() now returns -1 if an exception is
raised.
* pymain_run_python() no longer uses _PyInitError but display the
exception and set exitcode to 1 in case of error.
* Fix _Py_RunMain(): return an exitcode rather than calling
exit() on pymain_run_python() failure.
* _Py_ExitInitError() no longer uses ExitProcess() on Windows, use
exit() on all platforms.
* _Py_ExitInitError() now fails with a fatal error if 'err' is not an
error not an exit.
---
Include/cpython/coreconfig.h | 4 ---
Modules/main.c | 48 +++++++++++++++++-------------------
Python/pathconfig.c | 18 ++++++++------
Python/pylifecycle.c | 11 +++------
4 files changed, 37 insertions(+), 44 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index 47a6baa1118..f9bde1492db 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -15,11 +15,7 @@ typedef struct {
} _type;
const char *_func;
const char *err_msg;
-#ifdef MS_WINDOWS
- unsigned int exitcode;
-#else
int exitcode;
-#endif
} _PyInitError;
/* Almost all errors causing Python initialization to fail */
diff --git a/Modules/main.c b/Modules/main.c
index 0f99e2af5db..47d0574648a 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -130,7 +130,7 @@ pymain_sys_path_add_path0(PyInterpreterState *interp, PyObject *path0)
if (sysdict != NULL) {
sys_path = _PyDict_GetItemIdWithError(sysdict, &PyId_path);
if (sys_path == NULL && PyErr_Occurred()) {
- goto error;
+ return -1;
}
}
else {
@@ -138,17 +138,13 @@ pymain_sys_path_add_path0(PyInterpreterState *interp, PyObject *path0)
}
if (sys_path == NULL) {
PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path");
- goto error;
+ return -1;
}
if (PyList_Insert(sys_path, 0, path0)) {
- goto error;
+ return -1;
}
return 0;
-
-error:
- PyErr_Print();
- return -1;
}
@@ -443,11 +439,9 @@ pymain_repl(_PyCoreConfig *config, PyCompilerFlags *cf, int *exitcode)
}
-static _PyInitError
+static void
pymain_run_python(int *exitcode)
{
- _PyInitError err;
-
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
/* pymain_run_stdin() modify the config */
_PyCoreConfig *config = &interp->core_config;
@@ -464,22 +458,20 @@ pymain_run_python(int *exitcode)
if (main_importer_path != NULL) {
if (pymain_sys_path_add_path0(interp, main_importer_path) < 0) {
- err = _Py_INIT_EXIT(1);
- goto done;
+ goto error;
}
}
else if (!config->isolated) {
PyObject *path0 = NULL;
- if (_PyPathConfig_ComputeSysPath0(&config->argv, &path0)) {
- if (path0 == NULL) {
- err = _Py_INIT_NO_MEMORY();
- goto done;
- }
+ int res = _PyPathConfig_ComputeSysPath0(&config->argv, &path0);
+ if (res < 0) {
+ goto error;
+ }
+ if (res > 0) {
if (pymain_sys_path_add_path0(interp, path0) < 0) {
Py_DECREF(path0);
- err = _Py_INIT_EXIT(1);
- goto done;
+ goto error;
}
Py_DECREF(path0);
}
@@ -508,11 +500,14 @@ pymain_run_python(int *exitcode)
}
pymain_repl(config, &cf, exitcode);
- err = _Py_INIT_OK();
+ goto done;
+
+error:
+ PyErr_Print();
+ *exitcode = 1;
done:
Py_XDECREF(main_importer_path);
- return err;
}
@@ -578,17 +573,14 @@ _Py_RunMain(void)
{
int exitcode = 0;
- _PyInitError err = pymain_run_python(&exitcode);
- if (_Py_INIT_FAILED(err)) {
- pymain_exit_error(err);
- }
-
+ pymain_run_python(&exitcode);
if (Py_FinalizeEx() < 0) {
/* Value unlikely to be confused with a non-error exit status or
other special meaning */
exitcode = 120;
}
+done:
pymain_free();
if (_Py_UnhandledKeyboardInterrupt) {
@@ -603,6 +595,10 @@ static int
pymain_main(_PyArgv *args)
{
_PyInitError err = pymain_init(args);
+ if (_Py_INIT_IS_EXIT(err)) {
+ pymain_free();
+ return err.exitcode;
+ }
if (_Py_INIT_FAILED(err)) {
pymain_exit_error(err);
}
diff --git a/Python/pathconfig.c b/Python/pathconfig.c
index 7fea7c36678..2fcb8160580 100644
--- a/Python/pathconfig.c
+++ b/Python/pathconfig.c
@@ -570,18 +570,17 @@ Py_GetProgramName(void)
directory ("-m module" case) which will be prepended to sys.argv:
sys.path[0].
- Return 1 if the path is correctly resolved, but *path0_p can be NULL
- if the Unicode object fail to be created.
+ Return 1 if the path is correctly resolved and written into *path0_p.
- Return 0 if it fails to resolve the full path (and *path0_p will be NULL).
- For example, return 0 if the current working directory has been removed
- (bpo-36236) or if argv is empty.
+ Return 0 if it fails to resolve the full path. For example, return 0 if the
+ current working directory has been removed (bpo-36236) or if argv is empty.
+
+ Raise an exception and return -1 on error.
*/
int
_PyPathConfig_ComputeSysPath0(const _PyWstrList *argv, PyObject **path0_p)
{
assert(_PyWstrList_CheckConsistency(argv));
- assert(*path0_p == NULL);
if (argv->length == 0) {
/* Leave sys.path unchanged if sys.argv is empty */
@@ -697,7 +696,12 @@ _PyPathConfig_ComputeSysPath0(const _PyWstrList *argv, PyObject **path0_p)
}
#endif /* All others */
- *path0_p = PyUnicode_FromWideChar(path0, n);
+ PyObject *path0_obj = PyUnicode_FromWideChar(path0, n);
+ if (path0_obj == NULL) {
+ return -1;
+ }
+
+ *path0_p = path0_obj;
return 1;
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 4e74e0b80c8..a173eb380a5 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -2124,17 +2124,14 @@ Py_FatalError(const char *msg)
void _Py_NO_RETURN
_Py_ExitInitError(_PyInitError err)
{
- assert(_Py_INIT_FAILED(err));
if (_Py_INIT_IS_EXIT(err)) {
-#ifdef MS_WINDOWS
- ExitProcess(err.exitcode);
-#else
exit(err.exitcode);
-#endif
+ }
+ else if (_Py_INIT_IS_ERROR(err)) {
+ fatal_error(err._func, err.err_msg, 1);
}
else {
- assert(_Py_INIT_IS_ERROR(err));
- fatal_error(err._func, err.err_msg, 1);
+ Py_FatalError("_Py_ExitInitError() must not be called on success");
}
}
From 68b34a720485f399e8699235b8f4e08f227dd43b Mon Sep 17 00:00:00 2001
From: Andrew Svetlov
Date: Thu, 16 May 2019 17:52:10 +0300
Subject: [PATCH 072/199] bpo-36921: Deprecate @coroutine for sake of async def
(GH-13346)
The second attempt. Now deprecate `@coroutine` only, keep `yield from fut` as is.
https://bugs.python.org/issue36921
---
Doc/library/asyncio-task.rst | 7 +-
Lib/asyncio/coroutines.py | 4 +
Lib/asyncio/locks.py | 8 +-
Lib/asyncio/tasks.py | 6 +-
Lib/test/test_asyncio/test_base_events.py | 54 +--
Lib/test/test_asyncio/test_events.py | 20 +-
Lib/test/test_asyncio/test_locks.py | 84 ++--
Lib/test/test_asyncio/test_pep492.py | 7 +-
Lib/test/test_asyncio/test_streams.py | 3 +-
Lib/test/test_asyncio/test_tasks.py | 432 +++++++++---------
Lib/test/test_typing.py | 5 +-
.../2019-05-15-21-35-23.bpo-36921.kA1306.rst | 1 +
12 files changed, 311 insertions(+), 320 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-15-21-35-23.bpo-36921.kA1306.rst
diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
index a1297f5fb7f..e7cf39b2bcc 100644
--- a/Doc/library/asyncio-task.rst
+++ b/Doc/library/asyncio-task.rst
@@ -916,12 +916,13 @@ enforced.
async def main():
await old_style_coroutine()
- This decorator is **deprecated** and is scheduled for removal in
- Python 3.10.
-
This decorator should not be used for :keyword:`async def`
coroutines.
+ .. deprecated-removed:: 3.8 3.10
+
+ Use :keyword:`async def` instead.
+
.. function:: iscoroutine(obj)
Return ``True`` if *obj* is a :ref:`coroutine object `.
diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py
index c665ebe33ee..9664ea74d75 100644
--- a/Lib/asyncio/coroutines.py
+++ b/Lib/asyncio/coroutines.py
@@ -7,6 +7,7 @@
import sys
import traceback
import types
+import warnings
from . import base_futures
from . import constants
@@ -107,6 +108,9 @@ def coroutine(func):
If the coroutine is not yielded from before it is destroyed,
an error message is logged.
"""
+ warnings.warn('"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead',
+ DeprecationWarning,
+ stacklevel=2)
if inspect.iscoroutinefunction(func):
# In Python 3.5 that's all we need to do for coroutines
# defined with "async def".
diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py
index 639bd11bd06..d59eb8f210c 100644
--- a/Lib/asyncio/locks.py
+++ b/Lib/asyncio/locks.py
@@ -3,12 +3,13 @@
__all__ = ('Lock', 'Event', 'Condition', 'Semaphore', 'BoundedSemaphore')
import collections
+import types
import warnings
from . import events
from . import futures
from . import exceptions
-from .coroutines import coroutine
+from .import coroutines
class _ContextManager:
@@ -55,7 +56,7 @@ def __exit__(self, *args):
# always raises; that's how the with-statement works.
pass
- @coroutine
+ @types.coroutine
def __iter__(self):
# This is not a coroutine. It is meant to enable the idiom:
#
@@ -78,6 +79,9 @@ def __iter__(self):
yield from self.acquire()
return _ContextManager(self)
+ # The flag is needed for legacy asyncio.iscoroutine()
+ __iter__._is_coroutine = coroutines._is_coroutine
+
async def __acquire_ctx(self):
await self.acquire()
return _ContextManager(self)
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index 211b9126b01..b274b9bd332 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -23,7 +23,7 @@
from . import events
from . import exceptions
from . import futures
-from .coroutines import coroutine
+from .coroutines import _is_coroutine
# Helper to generate new task names
# This uses itertools.count() instead of a "+= 1" operation because the latter
@@ -638,7 +638,7 @@ def ensure_future(coro_or_future, *, loop=None):
'required')
-@coroutine
+@types.coroutine
def _wrap_awaitable(awaitable):
"""Helper for asyncio.ensure_future().
@@ -647,6 +647,8 @@ def _wrap_awaitable(awaitable):
"""
return (yield from awaitable.__await__())
+_wrap_awaitable._is_coroutine = _is_coroutine
+
class _GatheringFuture(futures.Future):
"""Helper for gather().
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
index 25420b2ff6f..27e21b33d36 100644
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -575,9 +575,8 @@ def zero_error(fut):
def test_default_exc_handler_coro(self):
self.loop._process_events = mock.Mock()
- @asyncio.coroutine
- def zero_error_coro():
- yield from asyncio.sleep(0.01)
+ async def zero_error_coro():
+ await asyncio.sleep(0.01)
1/0
# Test Future.__del__
@@ -723,8 +722,7 @@ def test_set_task_factory(self):
class MyTask(asyncio.Task):
pass
- @asyncio.coroutine
- def coro():
+ async def coro():
pass
factory = lambda loop, coro: MyTask(coro, loop=loop)
@@ -779,8 +777,7 @@ def test_create_task(self):
class MyTask(asyncio.Task):
pass
- @asyncio.coroutine
- def test():
+ async def test():
pass
class EventLoop(base_events.BaseEventLoop):
@@ -830,8 +827,7 @@ def test_run_forever_keyboard_interrupt(self):
# Python issue #22601: ensure that the temporary task created by
# run_forever() consumes the KeyboardInterrupt and so don't log
# a warning
- @asyncio.coroutine
- def raise_keyboard_interrupt():
+ async def raise_keyboard_interrupt():
raise KeyboardInterrupt
self.loop._process_events = mock.Mock()
@@ -849,8 +845,7 @@ def raise_keyboard_interrupt():
def test_run_until_complete_baseexception(self):
# Python issue #22429: run_until_complete() must not schedule a pending
# call to stop() if the future raised a BaseException
- @asyncio.coroutine
- def raise_keyboard_interrupt():
+ async def raise_keyboard_interrupt():
raise KeyboardInterrupt
self.loop._process_events = mock.Mock()
@@ -1070,9 +1065,7 @@ def test_create_connection_multiple_errors(self, m_socket):
class MyProto(asyncio.Protocol):
pass
- @asyncio.coroutine
- def getaddrinfo(*args, **kw):
- yield from []
+ async def getaddrinfo(*args, **kw):
return [(2, 1, 6, '', ('107.6.106.82', 80)),
(2, 1, 6, '', ('107.6.106.82', 80))]
@@ -1191,9 +1184,8 @@ def test_create_connection_no_host_port_sock(self):
self.assertRaises(ValueError, self.loop.run_until_complete, coro)
def test_create_connection_no_getaddrinfo(self):
- @asyncio.coroutine
- def getaddrinfo(*args, **kw):
- yield from []
+ async def getaddrinfo(*args, **kw):
+ return []
def getaddrinfo_task(*args, **kwds):
return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop)
@@ -1219,8 +1211,7 @@ def getaddrinfo_task(*args, **kwds):
OSError, self.loop.run_until_complete, coro)
def test_create_connection_multiple(self):
- @asyncio.coroutine
- def getaddrinfo(*args, **kw):
+ async def getaddrinfo(*args, **kw):
return [(2, 1, 6, '', ('0.0.0.1', 80)),
(2, 1, 6, '', ('0.0.0.2', 80))]
@@ -1247,8 +1238,7 @@ def bind(addr):
m_socket.socket.return_value.bind = bind
- @asyncio.coroutine
- def getaddrinfo(*args, **kw):
+ async def getaddrinfo(*args, **kw):
return [(2, 1, 6, '', ('0.0.0.1', 80)),
(2, 1, 6, '', ('0.0.0.2', 80))]
@@ -1349,8 +1339,7 @@ def test_create_connection_service_name(self, m_socket):
self.loop.run_until_complete(coro)
def test_create_connection_no_local_addr(self):
- @asyncio.coroutine
- def getaddrinfo(host, *args, **kw):
+ async def getaddrinfo(host, *args, **kw):
if host == 'example.com':
return [(2, 1, 6, '', ('107.6.106.82', 80)),
(2, 1, 6, '', ('107.6.106.82', 80))]
@@ -1488,11 +1477,10 @@ def test_create_server_empty_host(self):
# if host is empty string use None instead
host = object()
- @asyncio.coroutine
- def getaddrinfo(*args, **kw):
+ async def getaddrinfo(*args, **kw):
nonlocal host
host = args[0]
- yield from []
+ return []
def getaddrinfo_task(*args, **kwds):
return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop)
@@ -1854,9 +1842,10 @@ def test_accept_connection_exception(self, m_log):
MyProto, sock, None, None, mock.ANY, mock.ANY)
def test_call_coroutine(self):
- @asyncio.coroutine
- def simple_coroutine():
- pass
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def simple_coroutine():
+ pass
self.loop.set_debug(True)
coro_func = simple_coroutine
@@ -1880,9 +1869,7 @@ def test_log_slow_callbacks(self, m_logger):
def stop_loop_cb(loop):
loop.stop()
- @asyncio.coroutine
- def stop_loop_coro(loop):
- yield from ()
+ async def stop_loop_coro(loop):
loop.stop()
asyncio.set_event_loop(self.loop)
@@ -1909,8 +1896,7 @@ def stop_loop_coro(loop):
class RunningLoopTests(unittest.TestCase):
def test_running_loop_within_a_loop(self):
- @asyncio.coroutine
- def runner(loop):
+ async def runner(loop):
loop.run_forever()
loop = asyncio.new_event_loop()
diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
index b46b614e556..0ae6eab1e1e 100644
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -253,12 +253,10 @@ def tearDown(self):
super().tearDown()
def test_run_until_complete_nesting(self):
- @asyncio.coroutine
- def coro1():
- yield
+ async def coro1():
+ await asyncio.sleep(0)
- @asyncio.coroutine
- def coro2():
+ async def coro2():
self.assertTrue(self.loop.is_running())
self.loop.run_until_complete(coro1())
@@ -735,8 +733,7 @@ def test_connect_accepted_socket_ssl_timeout_for_plain_socket(self):
@mock.patch('asyncio.base_events.socket')
def create_server_multiple_hosts(self, family, hosts, mock_sock):
- @asyncio.coroutine
- def getaddrinfo(host, port, *args, **kw):
+ async def getaddrinfo(host, port, *args, **kw):
if family == socket.AF_INET:
return [(family, socket.SOCK_STREAM, 6, '', (host, port))]
else:
@@ -1662,8 +1659,7 @@ def test_add_fds_after_closing(self):
loop.add_writer(w, callback)
def test_close_running_event_loop(self):
- @asyncio.coroutine
- def close_loop(loop):
+ async def close_loop(loop):
self.loop.close()
coro = close_loop(self.loop)
@@ -1673,8 +1669,7 @@ def close_loop(loop):
def test_close(self):
self.loop.close()
- @asyncio.coroutine
- def test():
+ async def test():
pass
func = lambda: False
@@ -2142,7 +2137,8 @@ def test_handle_repr(self):
'')
# decorated function
- cb = asyncio.coroutine(noop)
+ with self.assertWarns(DeprecationWarning):
+ cb = asyncio.coroutine(noop)
h = asyncio.Handle(cb, (), self.loop)
self.assertEqual(repr(h),
''
diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py
index b61cf743c3c..5063a1da448 100644
--- a/Lib/test/test_asyncio/test_locks.py
+++ b/Lib/test/test_asyncio/test_locks.py
@@ -44,10 +44,11 @@ def test_repr(self):
self.assertTrue(repr(lock).endswith('[unlocked]>'))
self.assertTrue(RGX_REPR.match(repr(lock)))
- @asyncio.coroutine
- def acquire_lock():
- with self.assertWarns(DeprecationWarning):
- yield from lock
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def acquire_lock():
+ with self.assertWarns(DeprecationWarning):
+ yield from lock
self.loop.run_until_complete(acquire_lock())
self.assertTrue(repr(lock).endswith('[locked]>'))
@@ -56,10 +57,11 @@ def acquire_lock():
def test_lock(self):
lock = asyncio.Lock(loop=self.loop)
- @asyncio.coroutine
- def acquire_lock():
- with self.assertWarns(DeprecationWarning):
- return (yield from lock)
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def acquire_lock():
+ with self.assertWarns(DeprecationWarning):
+ return (yield from lock)
res = self.loop.run_until_complete(acquire_lock())
@@ -79,17 +81,18 @@ def test_lock_by_with_statement(self):
asyncio.BoundedSemaphore(loop=loop),
]
- @asyncio.coroutine
- def test(lock):
- yield from asyncio.sleep(0.01)
- self.assertFalse(lock.locked())
- with self.assertWarns(DeprecationWarning):
- with (yield from lock) as _lock:
- self.assertIs(_lock, None)
- self.assertTrue(lock.locked())
- yield from asyncio.sleep(0.01)
- self.assertTrue(lock.locked())
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def test(lock):
+ yield from asyncio.sleep(0.01)
self.assertFalse(lock.locked())
+ with self.assertWarns(DeprecationWarning):
+ with (yield from lock) as _lock:
+ self.assertIs(_lock, None)
+ self.assertTrue(lock.locked())
+ yield from asyncio.sleep(0.01)
+ self.assertTrue(lock.locked())
+ self.assertFalse(lock.locked())
for primitive in primitives:
loop.run_until_complete(test(primitive))
@@ -290,10 +293,11 @@ def test_release_no_waiters(self):
def test_context_manager(self):
lock = asyncio.Lock(loop=self.loop)
- @asyncio.coroutine
- def acquire_lock():
- with self.assertWarns(DeprecationWarning):
- return (yield from lock)
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def acquire_lock():
+ with self.assertWarns(DeprecationWarning):
+ return (yield from lock)
with self.loop.run_until_complete(acquire_lock()):
self.assertTrue(lock.locked())
@@ -303,10 +307,11 @@ def acquire_lock():
def test_context_manager_cant_reuse(self):
lock = asyncio.Lock(loop=self.loop)
- @asyncio.coroutine
- def acquire_lock():
- with self.assertWarns(DeprecationWarning):
- return (yield from lock)
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def acquire_lock():
+ with self.assertWarns(DeprecationWarning):
+ return (yield from lock)
# This spells "yield from lock" outside a generator.
cm = self.loop.run_until_complete(acquire_lock())
@@ -773,10 +778,11 @@ def test_repr(self):
def test_context_manager(self):
cond = asyncio.Condition(loop=self.loop)
- @asyncio.coroutine
- def acquire_cond():
- with self.assertWarns(DeprecationWarning):
- return (yield from cond)
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def acquire_cond():
+ with self.assertWarns(DeprecationWarning):
+ return (yield from cond)
with self.loop.run_until_complete(acquire_cond()):
self.assertTrue(cond.locked())
@@ -869,10 +875,11 @@ def test_semaphore(self):
sem = asyncio.Semaphore(loop=self.loop)
self.assertEqual(1, sem._value)
- @asyncio.coroutine
- def acquire_lock():
- with self.assertWarns(DeprecationWarning):
- return (yield from sem)
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def acquire_lock():
+ with self.assertWarns(DeprecationWarning):
+ return (yield from sem)
res = self.loop.run_until_complete(acquire_lock())
@@ -1012,10 +1019,11 @@ def test_release_no_waiters(self):
def test_context_manager(self):
sem = asyncio.Semaphore(2, loop=self.loop)
- @asyncio.coroutine
- def acquire_lock():
- with self.assertWarns(DeprecationWarning):
- return (yield from sem)
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def acquire_lock():
+ with self.assertWarns(DeprecationWarning):
+ return (yield from sem)
with self.loop.run_until_complete(acquire_lock()):
self.assertFalse(sem.locked())
diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py
index 558e268415c..297a3b3901d 100644
--- a/Lib/test/test_asyncio/test_pep492.py
+++ b/Lib/test/test_asyncio/test_pep492.py
@@ -130,9 +130,10 @@ class Awaitable:
def __await__(self):
return ('spam',)
- @asyncio.coroutine
- def func():
- return Awaitable()
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def func():
+ return Awaitable()
coro = func()
self.assertEqual(coro.send(None), 'spam')
diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py
index 258d8a7f7fd..fed609816da 100644
--- a/Lib/test/test_asyncio/test_streams.py
+++ b/Lib/test/test_asyncio/test_streams.py
@@ -588,8 +588,7 @@ def test_exception_waiter(self):
stream = asyncio.StreamReader(loop=self.loop,
_asyncio_internal=True)
- @asyncio.coroutine
- def set_err():
+ async def set_err():
stream.set_exception(ValueError())
t1 = asyncio.Task(stream.readline(), loop=self.loop)
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index fa9783f2ff2..1c1f912ff8a 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -28,8 +28,7 @@ def tearDownModule():
asyncio.set_event_loop_policy(None)
-@asyncio.coroutine
-def coroutine_function():
+async def coroutine_function():
pass
@@ -103,8 +102,7 @@ class Evil:
def __del__(self):
gc.collect()
- @asyncio.coroutine
- def run():
+ async def run():
return Evil()
self.loop.run_until_complete(
@@ -138,8 +136,7 @@ async def test():
self.loop.run_until_complete(task)
def test_task_class(self):
- @asyncio.coroutine
- def notmuch():
+ async def notmuch():
return 'ok'
t = self.new_task(self.loop, notmuch())
self.loop.run_until_complete(t)
@@ -156,9 +153,10 @@ def notmuch():
loop.close()
def test_ensure_future_coroutine(self):
- @asyncio.coroutine
- def notmuch():
- return 'ok'
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def notmuch():
+ return 'ok'
t = asyncio.ensure_future(notmuch(), loop=self.loop)
self.loop.run_until_complete(t)
self.assertTrue(t.done())
@@ -194,8 +192,7 @@ def test_ensure_future_future(self):
self.assertIs(f, f_orig)
def test_ensure_future_task(self):
- @asyncio.coroutine
- def notmuch():
+ async def notmuch():
return 'ok'
t_orig = self.new_task(self.loop, notmuch())
t = asyncio.ensure_future(t_orig)
@@ -222,9 +219,10 @@ def __init__(self, coro):
def __await__(self):
return (yield from self.coro)
- @asyncio.coroutine
- def coro():
- return 'ok'
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro():
+ return 'ok'
loop = asyncio.new_event_loop()
self.set_event_loop(loop)
@@ -276,9 +274,7 @@ async def runner():
def test_task_repr(self):
self.loop.set_debug(False)
- @asyncio.coroutine
- def notmuch():
- yield from []
+ async def notmuch():
return 'abc'
# test coroutine function
@@ -327,8 +323,7 @@ def notmuch():
"" % coro)
def test_task_repr_autogenerated(self):
- @asyncio.coroutine
- def notmuch():
+ async def notmuch():
return 123
t1 = self.new_task(self.loop, notmuch(), None)
@@ -346,8 +341,7 @@ def notmuch():
self.loop.run_until_complete(t2)
def test_task_repr_name_not_str(self):
- @asyncio.coroutine
- def notmuch():
+ async def notmuch():
return 123
t = self.new_task(self.loop, notmuch())
@@ -358,11 +352,12 @@ def notmuch():
def test_task_repr_coro_decorator(self):
self.loop.set_debug(False)
- @asyncio.coroutine
- def notmuch():
- # notmuch() function doesn't use yield from: it will be wrapped by
- # @coroutine decorator
- return 123
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def notmuch():
+ # notmuch() function doesn't use yield from: it will be wrapped by
+ # @coroutine decorator
+ return 123
# test coroutine function
self.assertEqual(notmuch.__name__, 'notmuch')
@@ -440,7 +435,8 @@ def test_task_repr_partial_corowrapper(self):
async def func(x, y):
await asyncio.sleep(0)
- partial_func = asyncio.coroutine(functools.partial(func, 1))
+ with self.assertWarns(DeprecationWarning):
+ partial_func = asyncio.coroutine(functools.partial(func, 1))
task = self.loop.create_task(partial_func(2))
# make warnings quiet
@@ -492,11 +488,12 @@ async def task():
self.assertFalse(t.cancel())
def test_cancel_yield(self):
- @asyncio.coroutine
- def task():
- yield
- yield
- return 12
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def task():
+ yield
+ yield
+ return 12
t = self.new_task(self.loop, task())
test_utils.run_briefly(self.loop) # start coro
@@ -618,8 +615,7 @@ def test_cancel_at_end(self):
loop = asyncio.new_event_loop()
self.set_event_loop(loop)
- @asyncio.coroutine
- def task():
+ async def task():
t.cancel()
self.assertTrue(t._must_cancel) # White-box test.
return 12
@@ -736,8 +732,7 @@ def gen():
foo_started = False
- @asyncio.coroutine
- def foo():
+ async def foo():
nonlocal foo_started
foo_started = True
@@ -814,8 +809,7 @@ async def foo():
def test_wait_for_blocking(self):
loop = self.new_test_loop()
- @asyncio.coroutine
- def coro():
+ async def coro():
return 'done'
res = loop.run_until_complete(asyncio.wait_for(coro(), timeout=None))
@@ -976,9 +970,10 @@ async def foo():
def test_wait_duplicate_coroutines(self):
- @asyncio.coroutine
- def coro(s):
- return s
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro(s):
+ return s
c = coro('test')
task =self.new_task(
@@ -1036,14 +1031,12 @@ def test_wait_really_done(self):
# there is possibility that some tasks in the pending list
# became done but their callbacks haven't all been called yet
- @asyncio.coroutine
- def coro1():
- yield
+ async def coro1():
+ await asyncio.sleep(0)
- @asyncio.coroutine
- def coro2():
- yield
- yield
+ async def coro2():
+ await asyncio.sleep(0)
+ await asyncio.sleep(0)
a = self.new_task(self.loop, coro1())
b = self.new_task(self.loop, coro2())
@@ -1070,8 +1063,7 @@ def gen():
# first_exception, task already has exception
a = self.new_task(loop, asyncio.sleep(10.0))
- @asyncio.coroutine
- def exc():
+ async def exc():
raise ZeroDivisionError('err')
b = self.new_task(loop, exc())
@@ -1131,9 +1123,8 @@ def gen():
a = self.new_task(loop, asyncio.sleep(0.1))
- @asyncio.coroutine
- def sleeper():
- yield from asyncio.sleep(0.15)
+ async def sleeper():
+ await asyncio.sleep(0.15)
raise ZeroDivisionError('really')
b = self.new_task(loop, sleeper())
@@ -1220,25 +1211,25 @@ def gen():
completed = set()
time_shifted = False
- @asyncio.coroutine
- def sleeper(dt, x):
- nonlocal time_shifted
- yield from asyncio.sleep(dt)
- completed.add(x)
- if not time_shifted and 'a' in completed and 'b' in completed:
- time_shifted = True
- loop.advance_time(0.14)
- return x
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def sleeper(dt, x):
+ nonlocal time_shifted
+ yield from asyncio.sleep(dt)
+ completed.add(x)
+ if not time_shifted and 'a' in completed and 'b' in completed:
+ time_shifted = True
+ loop.advance_time(0.14)
+ return x
a = sleeper(0.01, 'a')
b = sleeper(0.01, 'b')
c = sleeper(0.15, 'c')
- @asyncio.coroutine
- def foo():
+ async def foo():
values = []
for f in asyncio.as_completed([b, c, a], loop=loop):
- values.append((yield from f))
+ values.append(await f)
return values
res = loop.run_until_complete(self.new_task(loop, foo()))
@@ -1350,18 +1341,20 @@ def gen():
def test_as_completed_duplicate_coroutines(self):
- @asyncio.coroutine
- def coro(s):
- return s
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro(s):
+ return s
- @asyncio.coroutine
- def runner():
- result = []
- c = coro('ham')
- for f in asyncio.as_completed([c, c, coro('spam')],
- loop=self.loop):
- result.append((yield from f))
- return result
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def runner():
+ result = []
+ c = coro('ham')
+ for f in asyncio.as_completed([c, c, coro('spam')],
+ loop=self.loop):
+ result.append((yield from f))
+ return result
fut = self.new_task(self.loop, runner())
self.loop.run_until_complete(fut)
@@ -1380,10 +1373,9 @@ def gen():
loop = self.new_test_loop(gen)
- @asyncio.coroutine
- def sleeper(dt, arg):
- yield from asyncio.sleep(dt/2)
- res = yield from asyncio.sleep(dt/2, arg)
+ async def sleeper(dt, arg):
+ await asyncio.sleep(dt/2)
+ res = await asyncio.sleep(dt/2, arg)
return res
t = self.new_task(loop, sleeper(0.1, 'yeah'))
@@ -1431,16 +1423,14 @@ def gen():
loop = self.new_test_loop(gen)
- @asyncio.coroutine
- def sleep(dt):
- yield from asyncio.sleep(dt)
+ async def sleep(dt):
+ await asyncio.sleep(dt)
- @asyncio.coroutine
- def doit():
+ async def doit():
sleeper = self.new_task(loop, sleep(5000))
loop.call_later(0.1, sleeper.cancel)
try:
- yield from sleeper
+ await sleeper
except asyncio.CancelledError:
return 'cancelled'
else:
@@ -1453,9 +1443,8 @@ def doit():
def test_task_cancel_waiter_future(self):
fut = self.new_future(self.loop)
- @asyncio.coroutine
- def coro():
- yield from fut
+ async def coro():
+ await fut
task = self.new_task(self.loop, coro())
test_utils.run_briefly(self.loop)
@@ -1469,8 +1458,7 @@ def coro():
self.assertTrue(fut.cancelled())
def test_task_set_methods(self):
- @asyncio.coroutine
- def notmuch():
+ async def notmuch():
return 'ko'
gen = notmuch()
@@ -1487,11 +1475,12 @@ def notmuch():
'ko')
def test_step_result(self):
- @asyncio.coroutine
- def notmuch():
- yield None
- yield 1
- return 'ko'
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def notmuch():
+ yield None
+ yield 1
+ return 'ko'
self.assertRaises(
RuntimeError, self.loop.run_until_complete, notmuch())
@@ -1511,10 +1500,9 @@ def add_done_callback(self, *args, **kwargs):
fut = Fut(loop=self.loop)
result = None
- @asyncio.coroutine
- def wait_for_future():
+ async def wait_for_future():
nonlocal result
- result = yield from fut
+ result = await fut
t = self.new_task(self.loop, wait_for_future())
test_utils.run_briefly(self.loop)
@@ -1536,16 +1524,14 @@ def gen():
loop = self.new_test_loop(gen)
- @asyncio.coroutine
- def sleeper():
- yield from asyncio.sleep(10)
+ async def sleeper():
+ await asyncio.sleep(10)
base_exc = BaseException()
- @asyncio.coroutine
- def notmutch():
+ async def notmutch():
try:
- yield from sleeper()
+ await sleeper()
except asyncio.CancelledError:
raise base_exc
@@ -1571,9 +1557,10 @@ def fn1():
yield
self.assertFalse(asyncio.iscoroutinefunction(fn1))
- @asyncio.coroutine
- def fn2():
- yield
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def fn2():
+ yield
self.assertTrue(asyncio.iscoroutinefunction(fn2))
self.assertFalse(asyncio.iscoroutinefunction(mock.Mock()))
@@ -1581,9 +1568,10 @@ def fn2():
def test_yield_vs_yield_from(self):
fut = self.new_future(self.loop)
- @asyncio.coroutine
- def wait_for_future():
- yield fut
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def wait_for_future():
+ yield fut
task = wait_for_future()
with self.assertRaises(RuntimeError):
@@ -1592,17 +1580,19 @@ def wait_for_future():
self.assertFalse(fut.done())
def test_yield_vs_yield_from_generator(self):
- @asyncio.coroutine
- def coro():
- yield
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro():
+ yield
- @asyncio.coroutine
- def wait_for_future():
- gen = coro()
- try:
- yield gen
- finally:
- gen.close()
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def wait_for_future():
+ gen = coro()
+ try:
+ yield gen
+ finally:
+ gen.close()
task = wait_for_future()
self.assertRaises(
@@ -1610,9 +1600,10 @@ def wait_for_future():
self.loop.run_until_complete, task)
def test_coroutine_non_gen_function(self):
- @asyncio.coroutine
- def func():
- return 'test'
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def func():
+ return 'test'
self.assertTrue(asyncio.iscoroutinefunction(func))
@@ -1625,12 +1616,12 @@ def func():
def test_coroutine_non_gen_function_return_future(self):
fut = self.new_future(self.loop)
- @asyncio.coroutine
- def func():
- return fut
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def func():
+ return fut
- @asyncio.coroutine
- def coro():
+ async def coro():
fut.set_result('test')
t1 = self.new_task(self.loop, func())
@@ -1887,11 +1878,12 @@ def check():
# A function that asserts various things.
# Called twice, with different debug flag values.
- @asyncio.coroutine
- def coro():
- # The actual coroutine.
- self.assertTrue(gen.gi_running)
- yield from fut
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro():
+ # The actual coroutine.
+ self.assertTrue(gen.gi_running)
+ yield from fut
# A completed Future used to run the coroutine.
fut = self.new_future(self.loop)
@@ -1922,19 +1914,22 @@ def coro():
def test_yield_from_corowrapper(self):
with set_coroutine_debug(True):
- @asyncio.coroutine
- def t1():
- return (yield from t2())
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def t1():
+ return (yield from t2())
- @asyncio.coroutine
- def t2():
- f = self.new_future(self.loop)
- self.new_task(self.loop, t3(f))
- return (yield from f)
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def t2():
+ f = self.new_future(self.loop)
+ self.new_task(self.loop, t3(f))
+ return (yield from f)
- @asyncio.coroutine
- def t3(f):
- f.set_result((1, 2, 3))
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def t3(f):
+ f.set_result((1, 2, 3))
task = self.new_task(self.loop, t1())
val = self.loop.run_until_complete(task)
@@ -2009,13 +2004,14 @@ async def coro():
def test_log_destroyed_pending_task(self):
Task = self.__class__.Task
- @asyncio.coroutine
- def kill_me(loop):
- future = self.new_future(loop)
- yield from future
- # at this point, the only reference to kill_me() task is
- # the Task._wakeup() method in future._callbacks
- raise Exception("code never reached")
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def kill_me(loop):
+ future = self.new_future(loop)
+ yield from future
+ # at this point, the only reference to kill_me() task is
+ # the Task._wakeup() method in future._callbacks
+ raise Exception("code never reached")
mock_handler = mock.Mock()
self.loop.set_debug(True)
@@ -2064,14 +2060,12 @@ def test_tb_logger_not_called_after_cancel(self, m_log):
loop = asyncio.new_event_loop()
self.set_event_loop(loop)
- @asyncio.coroutine
- def coro():
+ async def coro():
raise TypeError
- @asyncio.coroutine
- def runner():
+ async def runner():
task = self.new_task(loop, coro())
- yield from asyncio.sleep(0.05)
+ await asyncio.sleep(0.05)
task.cancel()
task = None
@@ -2081,9 +2075,10 @@ def runner():
@mock.patch('asyncio.coroutines.logger')
def test_coroutine_never_yielded(self, m_log):
with set_coroutine_debug(True):
- @asyncio.coroutine
- def coro_noop():
- pass
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro_noop():
+ pass
tb_filename = __file__
tb_lineno = sys._getframe().f_lineno + 2
@@ -2112,13 +2107,15 @@ def test_return_coroutine_from_coroutine(self):
from @asyncio.coroutine()-wrapped function should have same effect as
returning generator object or Future."""
def check():
- @asyncio.coroutine
- def outer_coro():
+ with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
- def inner_coro():
- return 1
+ def outer_coro():
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def inner_coro():
+ return 1
- return inner_coro()
+ return inner_coro()
result = self.loop.run_until_complete(outer_coro())
self.assertEqual(result, 1)
@@ -2147,11 +2144,10 @@ def _test_cancel_wait_for(self, timeout):
loop = asyncio.new_event_loop()
self.addCleanup(loop.close)
- @asyncio.coroutine
- def blocking_coroutine():
+ async def blocking_coroutine():
fut = self.new_future(loop)
# Block: fut result is never set
- yield from fut
+ await fut
task = loop.create_task(blocking_coroutine())
@@ -2230,14 +2226,12 @@ async def main():
def test_exception_traceback(self):
# See http://bugs.python.org/issue28843
- @asyncio.coroutine
- def foo():
+ async def foo():
1 / 0
- @asyncio.coroutine
- def main():
+ async def main():
task = self.new_task(self.loop, foo())
- yield # skip one loop iteration
+ await asyncio.sleep(0) # skip one loop iteration
self.assertIsNotNone(task.exception().__traceback__)
self.loop.run_until_complete(main())
@@ -2248,9 +2242,10 @@ def call_soon(callback, *args, **kwargs):
raise ValueError
self.loop.call_soon = call_soon
- @asyncio.coroutine
- def coro():
- pass
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro():
+ pass
self.assertFalse(m_log.error.called)
@@ -2280,9 +2275,10 @@ def test_create_task_with_noncoroutine(self):
def test_create_task_with_oldstyle_coroutine(self):
- @asyncio.coroutine
- def coro():
- pass
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro():
+ pass
task = self.new_task(self.loop, coro())
self.assertIsInstance(task, self.Task)
@@ -2553,8 +2549,7 @@ class CTask_CFuture_Tests(BaseTaskTests, SetMethodsTest,
@support.refcount_test
def test_refleaks_in_task___init__(self):
gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')
- @asyncio.coroutine
- def coro():
+ async def coro():
pass
task = self.new_task(self.loop, coro())
self.loop.run_until_complete(task)
@@ -2565,8 +2560,7 @@ def coro():
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
def test_del__log_destroy_pending_segfault(self):
- @asyncio.coroutine
- def coro():
+ async def coro():
pass
task = self.new_task(self.loop, coro())
self.loop.run_until_complete(task)
@@ -3054,15 +3048,13 @@ def setUp(self):
def wrap_futures(self, *futures):
coros = []
for fut in futures:
- @asyncio.coroutine
- def coro(fut=fut):
- return (yield from fut)
+ async def coro(fut=fut):
+ return await fut
coros.append(coro())
return coros
def test_constructor_loop_selection(self):
- @asyncio.coroutine
- def coro():
+ async def coro():
return 'abc'
gen1 = coro()
gen2 = coro()
@@ -3078,9 +3070,10 @@ def coro():
self.other_loop.run_until_complete(fut2)
def test_duplicate_coroutines(self):
- @asyncio.coroutine
- def coro(s):
- return s
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro(s):
+ return s
c = coro('abc')
fut = asyncio.gather(c, c, coro('def'), c, loop=self.one_loop)
self._run_loop(self.one_loop)
@@ -3091,21 +3084,19 @@ def test_cancellation_broadcast(self):
proof = 0
waiter = asyncio.Future(loop=self.one_loop)
- @asyncio.coroutine
- def inner():
+ async def inner():
nonlocal proof
- yield from waiter
+ await waiter
proof += 1
child1 = asyncio.ensure_future(inner(), loop=self.one_loop)
child2 = asyncio.ensure_future(inner(), loop=self.one_loop)
gatherer = None
- @asyncio.coroutine
- def outer():
+ async def outer():
nonlocal proof, gatherer
gatherer = asyncio.gather(child1, child2, loop=self.one_loop)
- yield from gatherer
+ await gatherer
proof += 100
f = asyncio.ensure_future(outer(), loop=self.one_loop)
@@ -3123,17 +3114,15 @@ def outer():
def test_exception_marking(self):
# Test for the first line marked "Mark exception retrieved."
- @asyncio.coroutine
- def inner(f):
- yield from f
+ async def inner(f):
+ await f
raise RuntimeError('should not be ignored')
a = asyncio.Future(loop=self.one_loop)
b = asyncio.Future(loop=self.one_loop)
- @asyncio.coroutine
- def outer():
- yield from asyncio.gather(inner(a), inner(b), loop=self.one_loop)
+ async def outer():
+ await asyncio.gather(inner(a), inner(b), loop=self.one_loop)
f = asyncio.ensure_future(outer(), loop=self.one_loop)
test_utils.run_briefly(self.one_loop)
@@ -3152,15 +3141,14 @@ def setUp(self):
self.loop = asyncio.new_event_loop()
self.set_event_loop(self.loop) # Will cleanup properly
- @asyncio.coroutine
- def add(self, a, b, fail=False, cancel=False):
+ async def add(self, a, b, fail=False, cancel=False):
"""Wait 0.05 second and return a + b."""
- yield from asyncio.sleep(0.05)
+ await asyncio.sleep(0.05)
if fail:
raise RuntimeError("Fail!")
if cancel:
asyncio.current_task(self.loop).cancel()
- yield
+ await asyncio.sleep(0)
return a + b
def target(self, fail=False, cancel=False, timeout=None,
@@ -3261,11 +3249,10 @@ def inc_result(num):
nonlocal result
result += num
- @asyncio.coroutine
- def coro():
+ async def coro():
self.loop.call_soon(inc_result, 1)
self.assertEqual(result, 0)
- num = yield from asyncio.sleep(0, result=10)
+ num = await asyncio.sleep(0, result=10)
self.assertEqual(result, 1) # inc'ed by call_soon
inc_result(num) # num should be 11
@@ -3318,24 +3305,27 @@ def tearDown(self):
def test_yield_from_awaitable(self):
- @asyncio.coroutine
- def coro():
- yield from asyncio.sleep(0)
- return 'ok'
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro():
+ yield from asyncio.sleep(0)
+ return 'ok'
result = self.loop.run_until_complete(coro())
self.assertEqual('ok', result)
def test_await_old_style_coro(self):
- @asyncio.coroutine
- def coro1():
- return 'ok1'
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro1():
+ return 'ok1'
- @asyncio.coroutine
- def coro2():
- yield from asyncio.sleep(0)
- return 'ok2'
+ with self.assertWarns(DeprecationWarning):
+ @asyncio.coroutine
+ def coro2():
+ yield from asyncio.sleep(0)
+ return 'ok2'
async def inner():
return await asyncio.gather(coro1(), coro2(), loop=self.loop)
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 0d66ebbd184..a547fe274c8 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -1708,9 +1708,8 @@ def __init__(self, value: typing.Iterable[T_a]):
def __aiter__(self) -> typing.AsyncIterator[T_a]:
return self
- @asyncio.coroutine
- def __anext__(self) -> T_a:
- data = yield from self.value
+ async def __anext__(self) -> T_a:
+ data = await self.value
if data:
return data
else:
diff --git a/Misc/NEWS.d/next/Library/2019-05-15-21-35-23.bpo-36921.kA1306.rst b/Misc/NEWS.d/next/Library/2019-05-15-21-35-23.bpo-36921.kA1306.rst
new file mode 100644
index 00000000000..b443b379d8f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-15-21-35-23.bpo-36921.kA1306.rst
@@ -0,0 +1 @@
+Deprecate ``@coroutine`` for sake of ``async def``.
From ae239f6b0626e926613a4a1dbafa323bd41fec32 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Thu, 16 May 2019 17:02:56 +0200
Subject: [PATCH 073/199] bpo-36763: Add _PyCoreConfig.parse_argv (GH-13361)
* _PyCoreConfig_Read() doesn't parse nor update argv
if parse_argv is 0.
* Move path configuration fields in _PyCoreConfig.
* Add an unit test for parse_argv=0.
* Remove unused "done": label in _Py_RunMain().
---
Include/cpython/coreconfig.h | 61 +++++++++++++++++++++++-------------
Lib/test/test_embed.py | 9 ++++++
Modules/main.c | 2 +-
Programs/_testembed.c | 32 +++++++++++++++++++
Python/coreconfig.c | 41 ++++++++++++++++--------
5 files changed, 109 insertions(+), 36 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index f9bde1492db..a04342ea980 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -207,32 +207,26 @@ typedef struct {
wchar_t *filesystem_errors;
wchar_t *pycache_prefix; /* PYTHONPYCACHEPREFIX, -X pycache_prefix=PATH */
+ int parse_argv; /* Parse argv command line arguments? */
+
+ /* Command line arguments (sys.argv).
+
+ By default, Python command line arguments are parsed and then stripped
+ from argv. Set parse_argv to 0 to avoid that.
+
+ If argv is empty, an empty string is added to ensure that sys.argv
+ always exists and is never empty. */
+ _PyWstrList argv;
+
+ /* Program: argv[0] or "".
+ Used to display Python usage if parsing command line arguments fails.
+ Used to initialize the default value of program_name */
+ wchar_t *program;
wchar_t *program_name; /* Program name, see also Py_GetProgramName() */
- _PyWstrList argv; /* Command line arguments */
- wchar_t *program; /* argv[0] or "" */
+
_PyWstrList xoptions; /* Command line -X options */
_PyWstrList warnoptions; /* Warnings options */
- /* Path configuration inputs */
- wchar_t *module_search_path_env; /* PYTHONPATH environment variable */
- wchar_t *home; /* PYTHONHOME environment variable,
- see also Py_SetPythonHome(). */
-
- /* Path configuration outputs */
- int use_module_search_paths; /* If non-zero, use module_search_paths */
- _PyWstrList module_search_paths; /* sys.path paths. Computed if
- use_module_search_paths is equal
- to zero. */
-
- wchar_t *executable; /* sys.executable */
- wchar_t *prefix; /* sys.prefix */
- wchar_t *base_prefix; /* sys.base_prefix */
- wchar_t *exec_prefix; /* sys.exec_prefix */
- wchar_t *base_exec_prefix; /* sys.base_exec_prefix */
-#ifdef MS_WINDOWS
- wchar_t *dll_path; /* Windows DLL path */
-#endif
-
/* If equal to zero, disable the import of the module site and the
site-dependent manipulations of sys.path that it entails. Also disable
these manipulations if site is explicitly imported later (call
@@ -350,6 +344,28 @@ typedef struct {
int legacy_windows_stdio;
#endif
+ /* --- Path configuration inputs ------------ */
+
+ wchar_t *module_search_path_env; /* PYTHONPATH environment variable */
+ wchar_t *home; /* PYTHONHOME environment variable,
+ see also Py_SetPythonHome(). */
+
+ /* --- Path configuration outputs ----------- */
+
+ int use_module_search_paths; /* If non-zero, use module_search_paths */
+ _PyWstrList module_search_paths; /* sys.path paths. Computed if
+ use_module_search_paths is equal
+ to zero. */
+
+ wchar_t *executable; /* sys.executable */
+ wchar_t *prefix; /* sys.prefix */
+ wchar_t *base_prefix; /* sys.base_prefix */
+ wchar_t *exec_prefix; /* sys.exec_prefix */
+ wchar_t *base_exec_prefix; /* sys.base_exec_prefix */
+#ifdef MS_WINDOWS
+ wchar_t *dll_path; /* Windows DLL path */
+#endif
+
/* --- Parameter only used by Py_Main() ---------- */
/* Skip the first line of the source ('run_filename' parameter), allowing use of non-Unix forms of
@@ -408,6 +424,7 @@ typedef struct {
.faulthandler = -1, \
.tracemalloc = -1, \
.use_module_search_paths = 0, \
+ .parse_argv = 1, \
.site_import = -1, \
.bytes_warning = -1, \
.inspect = -1, \
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 8f40e9fdb18..3fabe5f9b25 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -304,6 +304,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'pycache_prefix': None,
'program_name': GET_DEFAULT_CONFIG,
+ 'parse_argv': 1,
'argv': [""],
'program': '',
@@ -700,6 +701,14 @@ def test_run_main_config(self):
}
self.check_config("run_main_config", core_config, preconfig)
+ def test_init_dont_parse_argv(self):
+ core_config = {
+ 'argv': ['-v', '-c', 'arg1', '-W', 'arg2'],
+ 'parse_argv': 0,
+ 'program': 'program',
+ }
+ self.check_config("init_dont_parse_argv", core_config, {})
+
if __name__ == "__main__":
unittest.main()
diff --git a/Modules/main.c b/Modules/main.c
index 47d0574648a..b47ac70d62c 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -574,13 +574,13 @@ _Py_RunMain(void)
int exitcode = 0;
pymain_run_python(&exitcode);
+
if (Py_FinalizeEx() < 0) {
/* Value unlikely to be confused with a non-error exit status or
other special meaning */
exitcode = 120;
}
-done:
pymain_free();
if (_Py_UnhandledKeyboardInterrupt) {
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 2560bfc62bb..6eee2e8bd3e 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -511,6 +511,37 @@ static int test_init_from_config(void)
}
+static int test_init_dont_parse_argv(void)
+{
+ _PyInitError err;
+
+ _PyCoreConfig config = _PyCoreConfig_INIT;
+
+ static wchar_t* argv[] = {
+ L"-v",
+ L"-c",
+ L"arg1",
+ L"-W",
+ L"arg2",
+ };
+
+ config.program = L"program";
+ config.program_name = L"./_testembed";
+
+ config.argv.length = Py_ARRAY_LENGTH(argv);
+ config.argv.items = argv;
+ config.parse_argv = 0;
+
+ err = _Py_InitializeFromConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+ dump_config();
+ Py_Finalize();
+ return 0;
+}
+
+
static void test_init_env_putenvs(void)
{
putenv("PYTHONHASHSEED=42");
@@ -797,6 +828,7 @@ static struct TestCase TestCases[] = {
{ "init_default_config", test_init_default_config },
{ "init_global_config", test_init_global_config },
{ "init_from_config", test_init_from_config },
+ { "init_dont_parse_argv", test_init_dont_parse_argv },
{ "init_env", test_init_env },
{ "init_env_dev_mode", test_init_env_dev_mode },
{ "init_env_dev_mode_alloc", test_init_env_dev_mode_alloc },
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index ac01712127a..2b13c5f0f9e 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -628,6 +628,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
COPY_WSTR_ATTR(program_name);
COPY_WSTR_ATTR(program);
+ COPY_ATTR(parse_argv);
COPY_WSTRLIST(argv);
COPY_WSTRLIST(warnoptions);
COPY_WSTRLIST(xoptions);
@@ -727,6 +728,7 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config)
SET_ITEM_WSTR(filesystem_errors);
SET_ITEM_WSTR(pycache_prefix);
SET_ITEM_WSTR(program_name);
+ SET_ITEM_INT(parse_argv);
SET_ITEM_WSTRLIST(argv);
SET_ITEM_WSTR(program);
SET_ITEM_WSTRLIST(xoptions);
@@ -1490,6 +1492,8 @@ config_read(_PyCoreConfig *config, _PyPreCmdline *cmdline)
}
if (config->isolated > 0) {
+ /* _PyPreCmdline_Read() sets use_environment to 0 if isolated is set,
+ _PyPreCmdline_SetCoreConfig() overrides config->use_environment. */
config->user_site_directory = 0;
}
@@ -1660,7 +1664,7 @@ config_usage(int error, const wchar_t* program)
/* Parse the command line arguments */
static _PyInitError
config_parse_cmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline,
- _PyWstrList *warnoptions)
+ _PyWstrList *warnoptions, int *opt_index)
{
_PyInitError err;
const _PyWstrList *argv = &precmdline->argv;
@@ -1833,8 +1837,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline,
_PyOS_optind--;
}
- /* -c and -m options are exclusive */
- assert(!(config->run_command != NULL && config->run_module != NULL));
+ *opt_index = _PyOS_optind;
return _Py_INIT_OK();
}
@@ -1978,13 +1981,14 @@ config_init_warnoptions(_PyCoreConfig *config,
static _PyInitError
-config_init_argv(_PyCoreConfig *config, const _PyPreCmdline *cmdline)
+config_update_argv(_PyCoreConfig *config, const _PyPreCmdline *cmdline,
+ int opt_index)
{
const _PyWstrList *cmdline_argv = &cmdline->argv;
_PyWstrList config_argv = _PyWstrList_INIT;
/* Copy argv to be able to modify it (to force -c/-m) */
- if (cmdline_argv->length <= _PyOS_optind) {
+ if (cmdline_argv->length <= opt_index) {
/* Ensure at least one (empty) argument is seen */
if (_PyWstrList_Append(&config_argv, L"") < 0) {
return _Py_INIT_NO_MEMORY();
@@ -1992,8 +1996,8 @@ config_init_argv(_PyCoreConfig *config, const _PyPreCmdline *cmdline)
}
else {
_PyWstrList slice;
- slice.length = cmdline_argv->length - _PyOS_optind;
- slice.items = &cmdline_argv->items[_PyOS_optind];
+ slice.length = cmdline_argv->length - opt_index;
+ slice.items = &cmdline_argv->items[opt_index];
if (_PyWstrList_Copy(&config_argv, &slice) < 0) {
return _Py_INIT_NO_MEMORY();
}
@@ -2058,14 +2062,22 @@ config_read_cmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
_PyWstrList cmdline_warnoptions = _PyWstrList_INIT;
_PyWstrList env_warnoptions = _PyWstrList_INIT;
- err = config_parse_cmdline(config, precmdline, &cmdline_warnoptions);
- if (_Py_INIT_FAILED(err)) {
- goto done;
+ if (config->parse_argv < 0) {
+ config->parse_argv = 1;
}
- err = config_init_argv(config, precmdline);
- if (_Py_INIT_FAILED(err)) {
- goto done;
+ if (config->parse_argv) {
+ int opt_index;
+ err = config_parse_cmdline(config, precmdline, &cmdline_warnoptions,
+ &opt_index);
+ if (_Py_INIT_FAILED(err)) {
+ goto done;
+ }
+
+ err = config_update_argv(config, precmdline, opt_index);
+ if (_Py_INIT_FAILED(err)) {
+ goto done;
+ }
}
err = config_read(config, precmdline);
@@ -2212,6 +2224,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
assert(config->verbose >= 0);
assert(config->quiet >= 0);
assert(config->user_site_directory >= 0);
+ assert(config->parse_argv >= 0);
assert(config->buffered_stdio >= 0);
assert(config->program_name != NULL);
assert(config->program != NULL);
@@ -2236,6 +2249,8 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
#ifdef MS_WINDOWS
assert(config->legacy_windows_stdio >= 0);
#endif
+ /* -c and -m options are exclusive */
+ assert(!(config->run_command != NULL && config->run_module != NULL));
assert(config->check_hash_pycs_mode != NULL);
assert(config->_install_importlib >= 0);
assert(config->_frozen >= 0);
From 9ef5dcaa0b3c7c7ba28dbb3ec0c9507d9d05e3a9 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Thu, 16 May 2019 17:38:16 +0200
Subject: [PATCH 074/199] bpo-36763: Add _Py_InitializeMain() (GH-13362)
* Add a private _Py_InitializeMain() function.
* Add again _PyCoreConfig._init_main.
* _Py_InitializeFromConfig() now uses _init_main to decide
if _Py_InitializeMainInterpreter() should be called.
* _PyCoreConfig: rename _frozen to pathconfig_warnings, its value is
now the opposite of Py_FrozenFlag.
* Add an unit test for _init_main=0 and _Py_InitializeMain().
---
Include/cpython/coreconfig.h | 13 ++++---
Include/cpython/pylifecycle.h | 1 +
Lib/test/test_embed.py | 43 ++++++++++++++++-------
Modules/getpath.c | 6 ++--
Programs/_freeze_importlib.c | 3 +-
Programs/_testembed.c | 64 ++++++++++++++++++++++++++++-------
Python/coreconfig.c | 12 ++++---
Python/frozenmain.c | 2 +-
Python/pylifecycle.c | 17 +++++++++-
Python/pythonrun.c | 9 +++++
10 files changed, 130 insertions(+), 40 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index a04342ea980..c2c55668406 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -398,10 +398,14 @@ typedef struct {
See PEP 552 "Deterministic pycs" for more details. */
wchar_t *check_hash_pycs_mode;
- /* If greater than 0, suppress _PyPathConfig_Calculate() warnings.
+ /* If greater than 0, suppress _PyPathConfig_Calculate() warnings on Unix.
+ The parameter has no effect on Windows.
- If set to -1 (default), inherit Py_FrozenFlag value. */
- int _frozen;
+ If set to -1 (default), inherit !Py_FrozenFlag value. */
+ int pathconfig_warnings;
+
+ /* If equal to 0, stop Python initialization before the "main" phase */
+ int _init_main;
} _PyCoreConfig;
@@ -438,7 +442,8 @@ typedef struct {
.buffered_stdio = -1, \
._install_importlib = 1, \
.check_hash_pycs_mode = NULL, \
- ._frozen = -1}
+ .pathconfig_warnings = -1, \
+ ._init_main = 1}
/* Note: _PyCoreConfig_INIT sets other fields to 0/NULL */
#ifdef __cplusplus
diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h
index 2366c774e7f..a3ab6c915ef 100644
--- a/Include/cpython/pylifecycle.h
+++ b/Include/cpython/pylifecycle.h
@@ -40,6 +40,7 @@ PyAPI_FUNC(_PyInitError) _Py_InitializeFromWideArgs(
const _PyCoreConfig *config,
int argc,
wchar_t **argv);
+PyAPI_FUNC(_PyInitError) _Py_InitializeMain(void);
PyAPI_FUNC(int) _Py_RunMain(void);
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 3fabe5f9b25..c3c1a3e3bac 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -343,7 +343,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'_install_importlib': 1,
'check_hash_pycs_mode': 'default',
- '_frozen': 0,
+ 'pathconfig_warnings': 1,
+ '_init_main': 1,
}
if MS_WINDOWS:
DEFAULT_PRE_CONFIG.update({
@@ -371,7 +372,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
('Py_DontWriteBytecodeFlag', 'write_bytecode', True),
('Py_FileSystemDefaultEncodeErrors', 'filesystem_errors'),
('Py_FileSystemDefaultEncoding', 'filesystem_encoding'),
- ('Py_FrozenFlag', '_frozen'),
+ ('Py_FrozenFlag', 'pathconfig_warnings', True),
('Py_IgnoreEnvironmentFlag', 'use_environment', True),
('Py_InspectFlag', 'inspect'),
('Py_InteractiveFlag', 'interactive'),
@@ -500,7 +501,8 @@ def check_global_config(self, config):
self.assertEqual(config['global_config'], expected)
- def check_config(self, testname, expected_config, expected_preconfig, add_path=None):
+ def check_config(self, testname, expected_config, expected_preconfig,
+ add_path=None, stderr=None):
env = dict(os.environ)
# Remove PYTHON* environment variables to get deterministic environment
for key in list(env):
@@ -511,19 +513,22 @@ def check_config(self, testname, expected_config, expected_preconfig, add_path=N
env['PYTHONCOERCECLOCALE'] = '0'
env['PYTHONUTF8'] = '0'
- out, err = self.run_embedded_interpreter(testname, env=env)
- # Ignore err
- try:
- config = json.loads(out)
- except json.JSONDecodeError:
- self.fail(f"fail to decode stdout: {out!r}")
-
expected_preconfig = dict(self.DEFAULT_PRE_CONFIG, **expected_preconfig)
expected_config = self.get_expected_config(expected_config, env, add_path)
for key in self.COPY_PRE_CONFIG:
if key not in expected_preconfig:
expected_preconfig[key] = expected_config[key]
+ out, err = self.run_embedded_interpreter(testname, env=env)
+ if stderr is None and not expected_config['verbose']:
+ stderr = ""
+ if stderr is not None:
+ self.assertEqual(err.rstrip(), stderr)
+ try:
+ config = json.loads(out)
+ except json.JSONDecodeError:
+ self.fail(f"fail to decode stdout: {out!r}")
+
self.check_pre_config(config, expected_preconfig)
self.check_core_config(config, expected_config)
self.check_global_config(config)
@@ -689,7 +694,7 @@ def test_init_read_set(self):
self.check_config("init_read_set", core_config, preconfig,
add_path="init_read_set_path")
- def test_run_main_config(self):
+ def test_init_run_main(self):
preconfig = {}
code = ('import _testinternalcapi, json; '
'print(json.dumps(_testinternalcapi.get_configs()))')
@@ -699,7 +704,21 @@ def test_run_main_config(self):
'program_name': './python3',
'run_command': code + '\n',
}
- self.check_config("run_main_config", core_config, preconfig)
+ self.check_config("init_run_main", core_config, preconfig)
+
+ def test_init_main(self):
+ preconfig = {}
+ code = ('import _testinternalcapi, json; '
+ 'print(json.dumps(_testinternalcapi.get_configs()))')
+ core_config = {
+ 'argv': ['-c', 'arg2'],
+ 'program': 'python3',
+ 'program_name': './python3',
+ 'run_command': code + '\n',
+ '_init_main': 0,
+ }
+ self.check_config("init_main", core_config, preconfig,
+ stderr="Run Python code before _Py_InitializeMain")
def test_init_dont_parse_argv(self):
core_config = {
diff --git a/Modules/getpath.c b/Modules/getpath.c
index 3991ad719c1..34357e47bc2 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -493,7 +493,7 @@ calculate_prefix(const _PyCoreConfig *core_config,
}
if (!calculate->prefix_found) {
- if (!core_config->_frozen) {
+ if (core_config->pathconfig_warnings) {
fprintf(stderr,
"Could not find platform independent libraries \n");
}
@@ -681,7 +681,7 @@ calculate_exec_prefix(const _PyCoreConfig *core_config,
}
if (!calculate->exec_prefix_found) {
- if (!core_config->_frozen) {
+ if (core_config->pathconfig_warnings) {
fprintf(stderr,
"Could not find platform dependent libraries \n");
}
@@ -1206,7 +1206,7 @@ calculate_path_impl(const _PyCoreConfig *core_config,
}
if ((!calculate->prefix_found || !calculate->exec_prefix_found) &&
- !core_config->_frozen)
+ core_config->pathconfig_warnings)
{
fprintf(stderr,
"Consider setting $PYTHONHOME to [:]\n");
diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c
index 4b2ed70de97..8cbbe17cfaf 100644
--- a/Programs/_freeze_importlib.c
+++ b/Programs/_freeze_importlib.c
@@ -83,7 +83,8 @@ main(int argc, char *argv[])
config.program_name = L"./_freeze_importlib";
/* Don't install importlib, since it could execute outdated bytecode. */
config._install_importlib = 0;
- config._frozen = 1;
+ config.pathconfig_warnings = 0;
+ config._init_main = 0;
_PyInitError err = _Py_InitializeFromConfig(&config);
/* No need to call _PyCoreConfig_Clear() since we didn't allocate any
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 6eee2e8bd3e..4ee2cd1b407 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -757,17 +757,25 @@ static int test_init_read_set(void)
}
-static int test_run_main(void)
+wchar_t *init_main_argv[] = {
+ L"python3", L"-c",
+ (L"import _testinternalcapi, json; "
+ L"print(json.dumps(_testinternalcapi.get_configs()))"),
+ L"arg2"};
+
+
+static void configure_init_main(_PyCoreConfig *config)
+{
+ config->argv.length = Py_ARRAY_LENGTH(init_main_argv);
+ config->argv.items = init_main_argv;
+ config->program_name = L"./python3";
+}
+
+
+static int test_init_run_main(void)
{
_PyCoreConfig config = _PyCoreConfig_INIT;
-
- wchar_t *argv[] = {L"python3", L"-c",
- (L"import sys; "
- L"print(f'_Py_RunMain(): sys.argv={sys.argv}')"),
- L"arg2"};
- config.argv.length = Py_ARRAY_LENGTH(argv);
- config.argv.items = argv;
- config.program_name = L"./python3";
+ configure_init_main(&config);
_PyInitError err = _Py_InitializeFromConfig(&config);
if (_Py_INIT_FAILED(err)) {
@@ -778,13 +786,42 @@ static int test_run_main(void)
}
-static int test_run_main_config(void)
+static int test_init_main(void)
+{
+ _PyCoreConfig config = _PyCoreConfig_INIT;
+ configure_init_main(&config);
+ config._init_main = 0;
+
+ _PyInitError err = _Py_InitializeFromConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+
+ /* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */
+ int res = PyRun_SimpleString(
+ "import sys; "
+ "print('Run Python code before _Py_InitializeMain', "
+ "file=sys.stderr)");
+ if (res < 0) {
+ exit(1);
+ }
+
+ err = _Py_InitializeMain();
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+
+ return _Py_RunMain();
+}
+
+
+static int test_run_main(void)
{
_PyCoreConfig config = _PyCoreConfig_INIT;
wchar_t *argv[] = {L"python3", L"-c",
- (L"import _testinternalcapi, json; "
- L"print(json.dumps(_testinternalcapi.get_configs()))"),
+ (L"import sys; "
+ L"print(f'_Py_RunMain(): sys.argv={sys.argv}')"),
L"arg2"};
config.argv.length = Py_ARRAY_LENGTH(argv);
config.argv.items = argv;
@@ -837,8 +874,9 @@ static struct TestCase TestCases[] = {
{ "preinit_isolated1", test_preinit_isolated1 },
{ "preinit_isolated2", test_preinit_isolated2 },
{ "init_read_set", test_init_read_set },
+ { "init_run_main", test_init_run_main },
+ { "init_main", test_init_main },
{ "run_main", test_run_main },
- { "run_main_config", test_run_main_config },
{ NULL, NULL }
};
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index 2b13c5f0f9e..8a5e5d509cb 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -667,7 +667,8 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
COPY_WSTR_ATTR(run_module);
COPY_WSTR_ATTR(run_filename);
COPY_WSTR_ATTR(check_hash_pycs_mode);
- COPY_ATTR(_frozen);
+ COPY_ATTR(pathconfig_warnings);
+ COPY_ATTR(_init_main);
#undef COPY_ATTR
#undef COPY_WSTR_ATTR
@@ -766,7 +767,8 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config)
SET_ITEM_WSTR(run_filename);
SET_ITEM_INT(_install_importlib);
SET_ITEM_WSTR(check_hash_pycs_mode);
- SET_ITEM_INT(_frozen);
+ SET_ITEM_INT(pathconfig_warnings);
+ SET_ITEM_INT(_init_main);
return dict;
@@ -855,7 +857,7 @@ _PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config)
#ifdef MS_WINDOWS
COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag);
#endif
- COPY_FLAG(_frozen, Py_FrozenFlag);
+ COPY_NOT_FLAG(pathconfig_warnings, Py_FrozenFlag);
COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag);
COPY_NOT_FLAG(site_import, Py_NoSiteFlag);
@@ -892,7 +894,7 @@ _PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config)
#ifdef MS_WINDOWS
COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag);
#endif
- COPY_FLAG(_frozen, Py_FrozenFlag);
+ COPY_NOT_FLAG(pathconfig_warnings, Py_FrozenFlag);
COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag);
COPY_NOT_FLAG(site_import, Py_NoSiteFlag);
@@ -2253,7 +2255,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
assert(!(config->run_command != NULL && config->run_module != NULL));
assert(config->check_hash_pycs_mode != NULL);
assert(config->_install_importlib >= 0);
- assert(config->_frozen >= 0);
+ assert(config->pathconfig_warnings >= 0);
err = _Py_INIT_OK();
diff --git a/Python/frozenmain.c b/Python/frozenmain.c
index a777576ad78..f2499ef84cd 100644
--- a/Python/frozenmain.c
+++ b/Python/frozenmain.c
@@ -40,7 +40,7 @@ Py_FrozenMain(int argc, char **argv)
}
_PyCoreConfig config = _PyCoreConfig_INIT;
- config._frozen = 1; /* Suppress errors from getpath.c */
+ config.pathconfig_warnings = 0; /* Suppress errors from getpath.c */
if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
inspect = 1;
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index a173eb380a5..e89152637fe 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -970,6 +970,21 @@ _Py_InitializeMainInterpreter(_PyRuntimeState *runtime,
return _Py_INIT_OK();
}
+
+_PyInitError
+_Py_InitializeMain(void)
+{
+ _PyInitError err = _PyRuntime_Initialize();
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+ _PyRuntimeState *runtime = &_PyRuntime;
+ PyInterpreterState *interp = _PyRuntimeState_GetThreadState(runtime)->interp;
+
+ return _Py_InitializeMainInterpreter(runtime, interp);
+}
+
+
#undef _INIT_DEBUG_PRINT
static _PyInitError
@@ -990,7 +1005,7 @@ init_python(const _PyCoreConfig *config, const _PyArgv *args)
}
config = &interp->core_config;
- if (!config->_frozen) {
+ if (config->_init_main) {
err = _Py_InitializeMainInterpreter(runtime, interp);
if (_Py_INIT_FAILED(err)) {
return err;
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 3d83044af9a..bc131fd7e5e 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -1046,6 +1046,15 @@ run_eval_code_obj(PyCodeObject *co, PyObject *globals, PyObject *locals)
* Py_Main() based one.
*/
_Py_UnhandledKeyboardInterrupt = 0;
+
+ /* Set globals['__builtins__'] if it doesn't exist */
+ if (globals != NULL && PyDict_GetItemString(globals, "__builtins__") == NULL) {
+ PyInterpreterState *interp = _PyInterpreterState_Get();
+ if (PyDict_SetItemString(globals, "__builtins__", interp->builtins) < 0) {
+ return NULL;
+ }
+ }
+
v = PyEval_EvalCode((PyObject*)co, globals, locals);
if (!v && PyErr_Occurred() == PyExc_KeyboardInterrupt) {
_Py_UnhandledKeyboardInterrupt = 1;
From 54b43bb3bb88339b63182b3515cda3efa530ed62 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Thu, 16 May 2019 18:30:15 +0200
Subject: [PATCH 075/199] bpo-36763: Add _PyCoreConfig.configure_c_stdio
(GH-13363)
Add tests for configure_c_stdio and pathconfig_warnings parameters.
---
Include/cpython/coreconfig.h | 9 +++++++++
Lib/test/test_embed.py | 4 ++++
Programs/_testembed.c | 7 +++++++
Python/coreconfig.c | 20 +++++++++++++++++---
4 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index c2c55668406..b531118ea3c 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -312,6 +312,14 @@ typedef struct {
!Py_NoUserSiteDirectory. */
int user_site_directory;
+ /* If non-zero, configure C standard steams (stdio, stdout,
+ stderr):
+
+ - Set O_BINARY mode on Windows.
+ - If buffered_stdio is equal to zero, make streams unbuffered.
+ Otherwise, enable streams buffering if interactive is non-zero. */
+ int configure_c_stdio;
+
/* If equal to 0, enable unbuffered mode: force the stdout and stderr
streams to be unbuffered.
@@ -439,6 +447,7 @@ typedef struct {
.verbose = -1, \
.quiet = -1, \
.user_site_directory = -1, \
+ .configure_c_stdio = 1, \
.buffered_stdio = -1, \
._install_importlib = 1, \
.check_hash_pycs_mode = NULL, \
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index c3c1a3e3bac..b1872ace8a6 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -331,6 +331,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'verbose': 0,
'quiet': 0,
'user_site_directory': 1,
+ 'configure_c_stdio': 1,
'buffered_stdio': 1,
'stdio_encoding': GET_DEFAULT_CONFIG,
@@ -558,6 +559,7 @@ def test_init_global_config(self):
'filesystem_encoding': 'utf-8',
'filesystem_errors': self.UTF8_MODE_ERRORS,
'user_site_directory': 0,
+ 'pathconfig_warnings': 0,
}
self.check_config("init_global_config", config, preconfig)
@@ -597,11 +599,13 @@ def test_init_from_config(self):
'write_bytecode': 0,
'verbose': 1,
'quiet': 1,
+ 'configure_c_stdio': 0,
'buffered_stdio': 0,
'user_site_directory': 0,
'faulthandler': 1,
'check_hash_pycs_mode': 'always',
+ 'pathconfig_warnings': 0,
}
self.check_config("init_from_config", config, preconfig)
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 4ee2cd1b407..87d159fe721 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -360,6 +360,8 @@ static int test_init_global_config(void)
putenv("PYTHONUNBUFFERED=");
Py_UnbufferedStdioFlag = 1;
+ Py_FrozenFlag = 1;
+
/* FIXME: test Py_LegacyWindowsFSEncodingFlag */
/* FIXME: test Py_LegacyWindowsStdioFlag */
@@ -481,6 +483,8 @@ static int test_init_from_config(void)
Py_QuietFlag = 0;
config.quiet = 1;
+ config.configure_c_stdio = 0;
+
putenv("PYTHONUNBUFFERED=");
Py_UnbufferedStdioFlag = 0;
config.buffered_stdio = 0;
@@ -501,6 +505,9 @@ static int test_init_from_config(void)
config.check_hash_pycs_mode = L"always";
+ Py_FrozenFlag = 0;
+ config.pathconfig_warnings = 0;
+
err = _Py_InitializeFromConfig(&config);
if (_Py_INIT_FAILED(err)) {
_Py_ExitInitError(err);
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index 8a5e5d509cb..e51bf9424a3 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -654,6 +654,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
COPY_ATTR(verbose);
COPY_ATTR(quiet);
COPY_ATTR(user_site_directory);
+ COPY_ATTR(configure_c_stdio);
COPY_ATTR(buffered_stdio);
COPY_WSTR_ATTR(filesystem_encoding);
COPY_WSTR_ATTR(filesystem_errors);
@@ -755,6 +756,7 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config)
SET_ITEM_INT(verbose);
SET_ITEM_INT(quiet);
SET_ITEM_INT(user_site_directory);
+ SET_ITEM_INT(configure_c_stdio);
SET_ITEM_INT(buffered_stdio);
SET_ITEM_WSTR(stdio_encoding);
SET_ITEM_WSTR(stdio_errors);
@@ -1582,7 +1584,6 @@ config_read(_PyCoreConfig *config, _PyPreCmdline *cmdline)
return _Py_INIT_NO_MEMORY();
}
}
-
return _Py_INIT_OK();
}
@@ -1632,7 +1633,10 @@ void
_PyCoreConfig_Write(const _PyCoreConfig *config, _PyRuntimeState *runtime)
{
_PyCoreConfig_SetGlobalConfig(config);
- config_init_stdio(config);
+
+ if (config->configure_c_stdio) {
+ config_init_stdio(config);
+ }
/* Write the new pre-configuration into _PyRuntime */
_PyPreConfig *preconfig = &runtime->preconfig;
@@ -2067,6 +2071,9 @@ config_read_cmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
if (config->parse_argv < 0) {
config->parse_argv = 1;
}
+ if (config->configure_c_stdio < 0) {
+ config->configure_c_stdio = 1;
+ }
if (config->parse_argv) {
int opt_index;
@@ -2171,7 +2178,9 @@ _PyCoreConfig_SetWideArgv(_PyCoreConfig *config, int argc, wchar_t **argv)
* Command line arguments
* Environment variables
- * Py_xxx global configuration variables */
+ * Py_xxx global configuration variables
+
+ The only side effects are to modify config and to call _Py_SetArgcArgv(). */
_PyInitError
_PyCoreConfig_Read(_PyCoreConfig *config)
{
@@ -2227,14 +2236,19 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
assert(config->quiet >= 0);
assert(config->user_site_directory >= 0);
assert(config->parse_argv >= 0);
+ assert(config->configure_c_stdio >= 0);
assert(config->buffered_stdio >= 0);
assert(config->program_name != NULL);
assert(config->program != NULL);
assert(_PyWstrList_CheckConsistency(&config->argv));
+ /* sys.argv must be non-empty: empty argv is replaced with [''] */
+ assert(config->argv.length >= 1);
assert(_PyWstrList_CheckConsistency(&config->xoptions));
assert(_PyWstrList_CheckConsistency(&config->warnoptions));
assert(_PyWstrList_CheckConsistency(&config->module_search_paths));
if (config->_install_importlib) {
+ assert(config->use_module_search_paths != 0);
+ /* don't check config->module_search_paths */
assert(config->executable != NULL);
assert(config->prefix != NULL);
assert(config->base_prefix != NULL);
From aee19f54f6fe45f6b3c906987941e5a8af4468e9 Mon Sep 17 00:00:00 2001
From: Pablo Galindo
Date: Thu, 16 May 2019 21:08:15 +0100
Subject: [PATCH 076/199] bpo-36751: Undeprecate getfullargspec (GH-13245)
---
Doc/library/inspect.rst | 5 ----
Doc/whatsnew/3.8.rst | 4 ---
Lib/inspect.py | 6 -----
Lib/test/test_inspect.py | 54 +++++++++++++++-------------------------
Misc/NEWS.d/3.8.0a4.rst | 11 --------
5 files changed, 20 insertions(+), 60 deletions(-)
diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
index d12f122a57b..81824ddc1e5 100644
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -948,11 +948,6 @@ Classes and functions
APIs. This function is retained primarily for use in code that needs to
maintain compatibility with the Python 2 ``inspect`` module API.
- .. deprecated:: 3.8
- Use :func:`signature` and
- :ref:`Signature Object `, which provide a
- better introspecting API for callables.
-
.. versionchanged:: 3.4
This function is now based on :func:`signature`, but still ignores
``__wrapped__`` attributes and includes the already bound first
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index c135183095c..d47993bf112 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -780,10 +780,6 @@ Deprecated
`.
(Contributed by Serhiy Storchaka in :issue:`36492`.)
-* The function :func:`~inspect.getfullargspec` in the :mod:`inspect`
- module is deprecated in favor of the :func:`inspect.signature`
- API. (Contributed by Pablo Galindo in :issue:`36751`.)
-
API and Feature Removals
========================
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 6c3027987b3..a4f28f75570 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1103,16 +1103,10 @@ def getfullargspec(func):
'kwonlydefaults' is a dictionary mapping names from kwonlyargs to defaults.
'annotations' is a dictionary mapping parameter names to annotations.
- .. deprecated:: 3.8
- Use inspect.signature() instead of inspect.getfullargspec().
-
Notable differences from inspect.signature():
- the "self" parameter is always reported, even for bound methods
- wrapper chains defined by __wrapped__ *not* unwrapped automatically
"""
-
- warnings.warn("Use inspect.signature() instead of inspect.getfullargspec()",
- DeprecationWarning, stacklevel=2)
try:
# Re: `skip_bound_arg=False`
#
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index c54cdb23c24..be52b389e62 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -750,25 +750,22 @@ class D(B, C): pass
def assertArgSpecEquals(self, routine, args_e, varargs_e=None,
varkw_e=None, defaults_e=None, formatted=None):
- with self.assertWarns(DeprecationWarning):
- args, varargs, varkw, defaults = inspect.getargspec(routine)
+ args, varargs, varkw, defaults = inspect.getargspec(routine)
self.assertEqual(args, args_e)
self.assertEqual(varargs, varargs_e)
self.assertEqual(varkw, varkw_e)
self.assertEqual(defaults, defaults_e)
if formatted is not None:
- with self.assertWarns(DeprecationWarning):
- self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults),
- formatted)
+ self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults),
+ formatted)
def assertFullArgSpecEquals(self, routine, args_e, varargs_e=None,
varkw_e=None, defaults_e=None,
posonlyargs_e=[], kwonlyargs_e=[],
kwonlydefaults_e=None,
ann_e={}, formatted=None):
- with self.assertWarns(DeprecationWarning):
- args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
- inspect.getfullargspec(routine)
+ args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
+ inspect.getfullargspec(routine)
self.assertEqual(args, args_e)
self.assertEqual(varargs, varargs_e)
self.assertEqual(varkw, varkw_e)
@@ -777,9 +774,8 @@ def assertFullArgSpecEquals(self, routine, args_e, varargs_e=None,
self.assertEqual(kwonlydefaults, kwonlydefaults_e)
self.assertEqual(ann, ann_e)
if formatted is not None:
- with self.assertWarns(DeprecationWarning):
- self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults,
- kwonlyargs, kwonlydefaults, ann),
+ self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults,
+ kwonlyargs, kwonlydefaults, ann),
formatted)
def test_getargspec(self):
@@ -879,13 +875,11 @@ def test():
def test_getfullargspec_signature_annos(self):
def test(a:'spam') -> 'ham': pass
- with self.assertWarns(DeprecationWarning):
- spec = inspect.getfullargspec(test)
+ spec = inspect.getfullargspec(test)
self.assertEqual(test.__annotations__, spec.annotations)
def test(): pass
- with self.assertWarns(DeprecationWarning):
- spec = inspect.getfullargspec(test)
+ spec = inspect.getfullargspec(test)
self.assertEqual(test.__annotations__, spec.annotations)
@unittest.skipIf(MISSING_C_DOCSTRINGS,
@@ -910,8 +904,7 @@ def test_getfullargspec_builtin_methods(self):
def test_getfullargspec_builtin_func(self):
import _testcapi
builtin = _testcapi.docstring_with_signature_with_defaults
- with self.assertWarns(DeprecationWarning):
- spec = inspect.getfullargspec(builtin)
+ spec = inspect.getfullargspec(builtin)
self.assertEqual(spec.defaults[0], 'avocado')
@cpython_only
@@ -920,20 +913,17 @@ def test_getfullargspec_builtin_func(self):
def test_getfullargspec_builtin_func_no_signature(self):
import _testcapi
builtin = _testcapi.docstring_no_signature
- with self.assertWarns(DeprecationWarning):
- with self.assertRaises(TypeError):
- inspect.getfullargspec(builtin)
+ with self.assertRaises(TypeError):
+ inspect.getfullargspec(builtin)
def test_getfullargspec_definition_order_preserved_on_kwonly(self):
for fn in signatures_with_lexicographic_keyword_only_parameters():
- with self.assertWarns(DeprecationWarning):
- signature = inspect.getfullargspec(fn)
+ signature = inspect.getfullargspec(fn)
l = list(signature.kwonlyargs)
sorted_l = sorted(l)
self.assertTrue(l)
self.assertEqual(l, sorted_l)
- with self.assertWarns(DeprecationWarning):
- signature = inspect.getfullargspec(unsorted_keyword_only_parameters_fn)
+ signature = inspect.getfullargspec(unsorted_keyword_only_parameters_fn)
l = list(signature.kwonlyargs)
self.assertEqual(l, unsorted_keyword_only_parameters)
@@ -1390,9 +1380,8 @@ class TestGetcallargsFunctions(unittest.TestCase):
def assertEqualCallArgs(self, func, call_params_string, locs=None):
locs = dict(locs or {}, func=func)
r1 = eval('func(%s)' % call_params_string, None, locs)
- with self.assertWarns(DeprecationWarning):
- r2 = eval('inspect.getcallargs(func, %s)' % call_params_string, None,
- locs)
+ r2 = eval('inspect.getcallargs(func, %s)' % call_params_string, None,
+ locs)
self.assertEqual(r1, r2)
def assertEqualException(self, func, call_param_string, locs=None):
@@ -1404,9 +1393,8 @@ def assertEqualException(self, func, call_param_string, locs=None):
else:
self.fail('Exception not raised')
try:
- with self.assertWarns(DeprecationWarning):
- eval('inspect.getcallargs(func, %s)' % call_param_string, None,
- locs)
+ eval('inspect.getcallargs(func, %s)' % call_param_string, None,
+ locs)
except Exception as e:
ex2 = e
else:
@@ -1564,16 +1552,14 @@ def test_errors(self):
def f5(*, a): pass
with self.assertRaisesRegex(TypeError,
'missing 1 required keyword-only'):
- with self.assertWarns(DeprecationWarning):
- inspect.getcallargs(f5)
+ inspect.getcallargs(f5)
# issue20817:
def f6(a, b, c):
pass
with self.assertRaisesRegex(TypeError, "'a', 'b' and 'c'"):
- with self.assertWarns(DeprecationWarning):
- inspect.getcallargs(f6)
+ inspect.getcallargs(f6)
# bpo-33197
with self.assertRaisesRegex(ValueError,
diff --git a/Misc/NEWS.d/3.8.0a4.rst b/Misc/NEWS.d/3.8.0a4.rst
index 76bb4970ff8..b92e60a9269 100644
--- a/Misc/NEWS.d/3.8.0a4.rst
+++ b/Misc/NEWS.d/3.8.0a4.rst
@@ -33,17 +33,6 @@ directory if the :envvar:`PATH` environment variable is not set.
..
-.. bpo: 36751
-.. date: 2019-04-29-23-30-21
-.. nonce: 3NCRbm
-.. section: Core and Builtins
-
-The :func:`~inspect.getfullargspec` function in the :mod:`inspect` module is
-deprecated in favor of the :func:`inspect.signature` API. Contributed by
-Pablo Galindo.
-
-..
-
.. bpo: 36722
.. date: 2019-04-25-21-02-40
.. nonce: 8NApVM
From 870b035bc6da96689b59dd6f79782ec6f1873617 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Fri, 17 May 2019 03:15:12 +0200
Subject: [PATCH 077/199] bpo-36763: Cleanup precmdline in _PyCoreConfig_Read()
(GH-13371)
precmdline is only needed in _PyCoreConfig_Read(), not in
config_read_cmdline(). Reorganize _PyCoreConfig_Read().
---
Include/internal/pycore_getopt.h | 2 +-
Python/coreconfig.c | 93 +++++++++++++++++---------------
Python/getopt.c | 4 +-
Python/preconfig.c | 2 +-
4 files changed, 54 insertions(+), 47 deletions(-)
diff --git a/Include/internal/pycore_getopt.h b/Include/internal/pycore_getopt.h
index 834b8c8a140..7f0dd13ae57 100644
--- a/Include/internal/pycore_getopt.h
+++ b/Include/internal/pycore_getopt.h
@@ -17,6 +17,6 @@ typedef struct {
int val;
} _PyOS_LongOption;
-extern int _PyOS_GetOpt(Py_ssize_t argc, wchar_t **argv, int *longindex);
+extern int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex);
#endif /* !Py_INTERNAL_PYGETOPT_H */
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index e51bf9424a3..ce778a640d3 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -1486,21 +1486,11 @@ config_init_fs_encoding(_PyCoreConfig *config, const _PyPreConfig *preconfig)
static _PyInitError
-config_read(_PyCoreConfig *config, _PyPreCmdline *cmdline)
+config_read(_PyCoreConfig *config)
{
_PyInitError err;
const _PyPreConfig *preconfig = &_PyRuntime.preconfig;
- if (_PyPreCmdline_SetCoreConfig(cmdline, config) < 0) {
- return _Py_INIT_NO_MEMORY();
- }
-
- if (config->isolated > 0) {
- /* _PyPreCmdline_Read() sets use_environment to 0 if isolated is set,
- _PyPreCmdline_SetCoreConfig() overrides config->use_environment. */
- config->user_site_directory = 0;
- }
-
if (config->use_environment) {
err = config_read_env_vars(config);
if (_Py_INIT_FAILED(err)) {
@@ -1584,6 +1574,19 @@ config_read(_PyCoreConfig *config, _PyPreCmdline *cmdline)
return _Py_INIT_NO_MEMORY();
}
}
+
+ if (config->check_hash_pycs_mode == NULL) {
+ err = _PyCoreConfig_SetString(&config->check_hash_pycs_mode,
+ L"default");
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+ }
+
+ if (config->configure_c_stdio < 0) {
+ config->configure_c_stdio = 1;
+ }
+
return _Py_INIT_OK();
}
@@ -1669,11 +1672,11 @@ config_usage(int error, const wchar_t* program)
/* Parse the command line arguments */
static _PyInitError
-config_parse_cmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline,
- _PyWstrList *warnoptions, int *opt_index)
+config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions,
+ int *opt_index)
{
_PyInitError err;
- const _PyWstrList *argv = &precmdline->argv;
+ const _PyWstrList *argv = &config->argv;
int print_version = 0;
_PyOS_ResetGetOpt();
@@ -1890,9 +1893,9 @@ config_init_env_warnoptions(const _PyCoreConfig *config, _PyWstrList *warnoption
static _PyInitError
-config_init_program(_PyCoreConfig *config, const _PyPreCmdline *cmdline)
+config_init_program(_PyCoreConfig *config)
{
- const _PyWstrList *argv = &cmdline->argv;
+ const _PyWstrList *argv = &config->argv;
wchar_t *program;
if (argv->length >= 1) {
program = argv->items[0];
@@ -1987,10 +1990,9 @@ config_init_warnoptions(_PyCoreConfig *config,
static _PyInitError
-config_update_argv(_PyCoreConfig *config, const _PyPreCmdline *cmdline,
- int opt_index)
+config_update_argv(_PyCoreConfig *config, int opt_index)
{
- const _PyWstrList *cmdline_argv = &cmdline->argv;
+ const _PyWstrList *cmdline_argv = &config->argv;
_PyWstrList config_argv = _PyWstrList_INIT;
/* Copy argv to be able to modify it (to force -c/-m) */
@@ -2054,6 +2056,16 @@ core_read_precmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
_PyCoreConfig_GetCoreConfig(&preconfig, config);
err = _PyPreCmdline_Read(precmdline, &preconfig);
+ if (_Py_INIT_FAILED(err)) {
+ goto done;
+ }
+
+ if (_PyPreCmdline_SetCoreConfig(precmdline, config) < 0) {
+ err = _Py_INIT_NO_MEMORY();
+ goto done;
+ }
+
+ err = _Py_INIT_OK();
done:
_PyPreConfig_Clear(&preconfig);
@@ -2062,7 +2074,7 @@ core_read_precmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
static _PyInitError
-config_read_cmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
+config_read_cmdline(_PyCoreConfig *config)
{
_PyInitError err;
_PyWstrList cmdline_warnoptions = _PyWstrList_INIT;
@@ -2071,29 +2083,27 @@ config_read_cmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
if (config->parse_argv < 0) {
config->parse_argv = 1;
}
- if (config->configure_c_stdio < 0) {
- config->configure_c_stdio = 1;
+
+ if (config->program == NULL) {
+ err = config_init_program(config);
+ if (_Py_INIT_FAILED(err)) {
+ goto done;
+ }
}
if (config->parse_argv) {
int opt_index;
- err = config_parse_cmdline(config, precmdline, &cmdline_warnoptions,
- &opt_index);
+ err = config_parse_cmdline(config, &cmdline_warnoptions, &opt_index);
if (_Py_INIT_FAILED(err)) {
goto done;
}
- err = config_update_argv(config, precmdline, opt_index);
+ err = config_update_argv(config, opt_index);
if (_Py_INIT_FAILED(err)) {
goto done;
}
}
- err = config_read(config, precmdline);
- if (_Py_INIT_FAILED(err)) {
- goto done;
- }
-
if (config->use_environment) {
err = config_init_env_warnoptions(config, &env_warnoptions);
if (_Py_INIT_FAILED(err)) {
@@ -2107,13 +2117,6 @@ config_read_cmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
goto done;
}
- if (config->check_hash_pycs_mode == NULL) {
- err = _PyCoreConfig_SetString(&config->check_hash_pycs_mode, L"default");
- if (_Py_INIT_FAILED(err)) {
- goto done;
- }
- }
-
err = _Py_INIT_OK();
done:
@@ -2199,14 +2202,18 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
goto done;
}
- if (config->program == NULL) {
- err = config_init_program(config, &precmdline);
- if (_Py_INIT_FAILED(err)) {
- goto done;
- }
+ assert(config->isolated >= 0);
+ if (config->isolated) {
+ config->use_environment = 0;
+ config->user_site_directory = 0;
}
- err = config_read_cmdline(config, &precmdline);
+ err = config_read_cmdline(config);
+ if (_Py_INIT_FAILED(err)) {
+ goto done;
+ }
+
+ err = config_read(config);
if (_Py_INIT_FAILED(err)) {
goto done;
}
diff --git a/Python/getopt.c b/Python/getopt.c
index 10bd1d49d7d..1a7db3fce88 100644
--- a/Python/getopt.c
+++ b/Python/getopt.c
@@ -41,7 +41,7 @@ int _PyOS_opterr = 1; /* generate error messages */
Py_ssize_t _PyOS_optind = 1; /* index into argv array */
const wchar_t *_PyOS_optarg = NULL; /* optional argument */
-static wchar_t *opt_ptr = L"";
+static const wchar_t *opt_ptr = L"";
/* Python command line short and long options */
@@ -61,7 +61,7 @@ void _PyOS_ResetGetOpt(void)
opt_ptr = L"";
}
-int _PyOS_GetOpt(Py_ssize_t argc, wchar_t **argv, int *longindex)
+int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
{
wchar_t *ptr;
wchar_t option;
diff --git a/Python/preconfig.c b/Python/preconfig.c
index 48b9e8383aa..2d0ace5df29 100644
--- a/Python/preconfig.c
+++ b/Python/preconfig.c
@@ -174,7 +174,7 @@ _PyPreCmdline_SetCoreConfig(const _PyPreCmdline *cmdline, _PyCoreConfig *config)
static _PyInitError
precmdline_parse_cmdline(_PyPreCmdline *cmdline)
{
- _PyWstrList *argv = &cmdline->argv;
+ const _PyWstrList *argv = &cmdline->argv;
_PyOS_ResetGetOpt();
/* Don't log parsing errors into stderr here: _PyCoreConfig_Read()
From 14514d9084a40f599c57da853a305aa264562a43 Mon Sep 17 00:00:00 2001
From: Zackery Spytz
Date: Fri, 17 May 2019 01:13:03 -0600
Subject: [PATCH 078/199] bpo-36946: Fix possible signed integer overflow when
handling slices. (GH-13375)
The final addition (cur += step) may overflow, so use size_t for "cur".
"cur" is always positive (even for negative steps), so it is safe to use
size_t here.
Co-Authored-By: Martin Panter
---
Lib/ctypes/test/test_arrays.py | 11 +++++++++++
Lib/test/seq_tests.py | 1 +
Lib/test/string_tests.py | 2 +-
Lib/test/test_array.py | 4 ++--
Lib/test/test_bytes.py | 5 +++--
Lib/test/test_mmap.py | 4 ++--
.../2019-05-16-23-53-45.bpo-36946.qjxr0Y.rst | 1 +
Modules/_ctypes/_ctypes.c | 6 ++++--
Modules/_elementtree.c | 6 ++++--
Modules/arraymodule.c | 6 ++++--
Modules/mmapmodule.c | 6 ++++--
Objects/bytearrayobject.c | 3 ++-
Objects/bytesobject.c | 3 ++-
Objects/tupleobject.c | 3 ++-
Objects/unicodeobject.c | 3 ++-
15 files changed, 45 insertions(+), 19 deletions(-)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-05-16-23-53-45.bpo-36946.qjxr0Y.rst
diff --git a/Lib/ctypes/test/test_arrays.py b/Lib/ctypes/test/test_arrays.py
index 0fc5d7ebf84..87ecbf04e7e 100644
--- a/Lib/ctypes/test/test_arrays.py
+++ b/Lib/ctypes/test/test_arrays.py
@@ -69,6 +69,17 @@ def test_simple(self):
from operator import delitem
self.assertRaises(TypeError, delitem, ca, 0)
+ def test_step_overflow(self):
+ a = (c_int * 5)()
+ a[3::sys.maxsize] = (1,)
+ self.assertListEqual(a[3::sys.maxsize], [1])
+ a = (c_char * 5)()
+ a[3::sys.maxsize] = b"A"
+ self.assertEqual(a[3::sys.maxsize], b"A")
+ a = (c_wchar * 5)()
+ a[3::sys.maxsize] = u"X"
+ self.assertEqual(a[3::sys.maxsize], u"X")
+
def test_numeric_arrays(self):
alen = 5
diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py
index 6aedd2be94d..65b110ef781 100644
--- a/Lib/test/seq_tests.py
+++ b/Lib/test/seq_tests.py
@@ -209,6 +209,7 @@ def test_getslice(self):
a = self.type2test([0,1,2,3,4])
self.assertEqual(a[ -pow(2,128): 3 ], self.type2test([0,1,2]))
self.assertEqual(a[ 3: pow(2,145) ], self.type2test([3,4]))
+ self.assertEqual(a[3::sys.maxsize], self.type2test([3]))
def test_contains(self):
u = self.type2test([0, 1, 2])
diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py
index 836a43b81dd..38da941f7f5 100644
--- a/Lib/test/string_tests.py
+++ b/Lib/test/string_tests.py
@@ -1135,7 +1135,7 @@ def test_slice(self):
def test_extended_getslice(self):
# Test extended slicing by comparing with list slicing.
s = string.ascii_letters + string.digits
- indices = (0, None, 1, 3, 41, -1, -2, -37)
+ indices = (0, None, 1, 3, 41, sys.maxsize, -1, -2, -37)
for start in indices:
for stop in indices:
# Skip step 0 (invalid)
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index 57c396d610b..c2439579e8e 100644
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -746,7 +746,7 @@ def test_extended_getslice(self):
# Test extended slicing by comparing with list slicing
# (Assumes list conversion works correctly, too)
a = array.array(self.typecode, self.example)
- indices = (0, None, 1, 3, 19, 100, -1, -2, -31, -100)
+ indices = (0, None, 1, 3, 19, 100, sys.maxsize, -1, -2, -31, -100)
for start in indices:
for stop in indices:
# Everything except the initial 0 (invalid step)
@@ -844,7 +844,7 @@ def test_setslice(self):
self.assertRaises(TypeError, a.__setitem__, slice(0, 1), b)
def test_extended_set_del_slice(self):
- indices = (0, None, 1, 3, 19, 100, -1, -2, -31, -100)
+ indices = (0, None, 1, 3, 19, 100, sys.maxsize, -1, -2, -31, -100)
for start in indices:
for stop in indices:
# Everything except the initial 0 (invalid step)
diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py
index a0913603e73..9502a8f974b 100644
--- a/Lib/test/test_bytes.py
+++ b/Lib/test/test_bytes.py
@@ -285,7 +285,7 @@ def test_extended_getslice(self):
# Test extended slicing by comparing with list slicing.
L = list(range(255))
b = self.type2test(L)
- indices = (0, None, 1, 3, 19, 100, -1, -2, -31, -100)
+ indices = (0, None, 1, 3, 19, 100, sys.maxsize, -1, -2, -31, -100)
for start in indices:
for stop in indices:
# Skip step 0 (invalid)
@@ -1242,7 +1242,8 @@ def test_del_expand(self):
self.assertLessEqual(sys.getsizeof(b), size)
def test_extended_set_del_slice(self):
- indices = (0, None, 1, 3, 19, 300, 1<<333, -1, -2, -31, -300)
+ indices = (0, None, 1, 3, 19, 300, 1<<333, sys.maxsize,
+ -1, -2, -31, -300)
for start in indices:
for stop in indices:
# Skip invalid step 0
diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py
index dd857a0632a..495d24ad807 100644
--- a/Lib/test/test_mmap.py
+++ b/Lib/test/test_mmap.py
@@ -439,7 +439,7 @@ def test_extended_getslice(self):
m = mmap.mmap(-1, len(s))
m[:] = s
self.assertEqual(m[:], s)
- indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
+ indices = (0, None, 1, 3, 19, 300, sys.maxsize, -1, -2, -31, -300)
for start in indices:
for stop in indices:
# Skip step 0 (invalid)
@@ -451,7 +451,7 @@ def test_extended_set_del_slice(self):
# Test extended slicing by comparing with list slicing.
s = bytes(reversed(range(256)))
m = mmap.mmap(-1, len(s))
- indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
+ indices = (0, None, 1, 3, 19, 300, sys.maxsize, -1, -2, -31, -300)
for start in indices:
for stop in indices:
# Skip invalid step 0
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-16-23-53-45.bpo-36946.qjxr0Y.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-16-23-53-45.bpo-36946.qjxr0Y.rst
new file mode 100644
index 00000000000..aa5de80a294
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-16-23-53-45.bpo-36946.qjxr0Y.rst
@@ -0,0 +1 @@
+Fix possible signed integer overflow when handling slices.
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 13cf76a16d7..7b5115359ed 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -4487,7 +4487,8 @@ Array_subscript(PyObject *myself, PyObject *item)
StgDictObject *stgdict, *itemdict;
PyObject *proto;
PyObject *np;
- Py_ssize_t start, stop, step, slicelen, cur, i;
+ Py_ssize_t start, stop, step, slicelen, i;
+ size_t cur;
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
return NULL;
@@ -4627,7 +4628,8 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
return Array_ass_item(myself, i, value);
}
else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelen, otherlen, i, cur;
+ Py_ssize_t start, stop, step, slicelen, otherlen, i;
+ size_t cur;
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
return -1;
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index f5fc4437deb..b1fb3eeffb1 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -1809,7 +1809,8 @@ element_subscr(PyObject* self_, PyObject* item)
return element_getitem(self_, i);
}
else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelen, cur, i;
+ Py_ssize_t start, stop, step, slicelen, i;
+ size_t cur;
PyObject* list;
if (!self->extra)
@@ -1861,7 +1862,8 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
return element_setitem(self_, i, value);
}
else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelen, newlen, cur, i;
+ Py_ssize_t start, stop, step, slicelen, newlen, i;
+ size_t cur;
PyObject* recycle = NULL;
PyObject* seq;
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 4be3beb29cc..523afb99e8a 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -2343,7 +2343,8 @@ array_subscr(arrayobject* self, PyObject* item)
return array_item(self, i);
}
else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength, cur, i;
+ Py_ssize_t start, stop, step, slicelength, i;
+ size_t cur;
PyObject* result;
arrayobject* ar;
int itemsize = self->ob_descr->itemsize;
@@ -2527,7 +2528,8 @@ array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value)
return 0;
}
else {
- Py_ssize_t cur, i;
+ size_t cur;
+ Py_ssize_t i;
if (needed != slicelength) {
PyErr_Format(PyExc_ValueError,
diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c
index 6ddbf70d9a9..33366b2d933 100644
--- a/Modules/mmapmodule.c
+++ b/Modules/mmapmodule.c
@@ -806,7 +806,8 @@ mmap_subscript(mmap_object *self, PyObject *item)
slicelen);
else {
char *result_buf = (char *)PyMem_Malloc(slicelen);
- Py_ssize_t cur, i;
+ size_t cur;
+ Py_ssize_t i;
PyObject *result;
if (result_buf == NULL)
@@ -926,7 +927,8 @@ mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
memcpy(self->data + start, vbuf.buf, slicelen);
}
else {
- Py_ssize_t cur, i;
+ size_t cur;
+ Py_ssize_t i;
for (cur = start, i = 0;
i < slicelen;
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c
index eaf5dceb03a..8d5ba540120 100644
--- a/Objects/bytearrayobject.c
+++ b/Objects/bytearrayobject.c
@@ -410,7 +410,8 @@ bytearray_subscript(PyByteArrayObject *self, PyObject *index)
return PyLong_FromLong((unsigned char)(PyByteArray_AS_STRING(self)[i]));
}
else if (PySlice_Check(index)) {
- Py_ssize_t start, stop, step, slicelength, cur, i;
+ Py_ssize_t start, stop, step, slicelength, i;
+ size_t cur;
if (PySlice_Unpack(index, &start, &stop, &step) < 0) {
return NULL;
}
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index b7c5b75283e..ebbdb7c3c16 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -1677,7 +1677,8 @@ bytes_subscript(PyBytesObject* self, PyObject* item)
return PyLong_FromLong((unsigned char)self->ob_sval[i]);
}
else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength, cur, i;
+ Py_ssize_t start, stop, step, slicelength, i;
+ size_t cur;
char* source_buf;
char* result_buf;
PyObject* result;
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 9f0fc1cc2c3..dc1d0e5ad0d 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -753,7 +753,8 @@ tuplesubscript(PyTupleObject* self, PyObject* item)
return tupleitem(self, i);
}
else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength, cur, i;
+ Py_ssize_t start, stop, step, slicelength, i;
+ size_t cur;
PyObject* result;
PyObject* it;
PyObject **src, **dest;
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index eaba5836cb1..0aa5e4ad18d 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -13991,7 +13991,8 @@ unicode_subscript(PyObject* self, PyObject* item)
i += PyUnicode_GET_LENGTH(self);
return unicode_getitem(self, i);
} else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength, cur, i;
+ Py_ssize_t start, stop, step, slicelength, i;
+ size_t cur;
PyObject *result;
void *src_data, *dest_data;
int src_kind, dest_kind;
From ac8eb8f36bf7ca636f8d886eb65a3b532f4725d5 Mon Sep 17 00:00:00 2001
From: Erwan Le Pape
Date: Fri, 17 May 2019 10:28:39 +0200
Subject: [PATCH 079/199] bpo-35545: Fix asyncio discarding IPv6 scopes
(GH-11271)
This PR proposes a solution to [bpo-35545](https://bugs.python.org/issue35545) by adding an optional `flowinfo` and `scopeid` to `asyncio.base_events._ipaddr_info` to carry the full address information into `_ipaddr_info` and avoid discarding IPv6 specific information.
Changelog entry & regression tests to come.
https://bugs.python.org/issue35545
---
Lib/asyncio/base_events.py | 6 ++---
Lib/test/test_asyncio/test_base_events.py | 22 +++++++++++++++++++
.../2019-05-11-16-21-29.bpo-35545.FcvJvP.rst | 2 ++
3 files changed, 27 insertions(+), 3 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-11-16-21-29.bpo-35545.FcvJvP.rst
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index 9613ac2a114..de9fa4f4f7f 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -102,7 +102,7 @@ def _set_reuseport(sock):
'SO_REUSEPORT defined but not implemented.')
-def _ipaddr_info(host, port, family, type, proto):
+def _ipaddr_info(host, port, family, type, proto, flowinfo=0, scopeid=0):
# Try to skip getaddrinfo if "host" is already an IP. Users might have
# handled name resolution in their own code and pass in resolved IPs.
if not hasattr(socket, 'inet_pton'):
@@ -151,7 +151,7 @@ def _ipaddr_info(host, port, family, type, proto):
socket.inet_pton(af, host)
# The host has already been resolved.
if _HAS_IPv6 and af == socket.AF_INET6:
- return af, type, proto, '', (host, port, 0, 0)
+ return af, type, proto, '', (host, port, flowinfo, scopeid)
else:
return af, type, proto, '', (host, port)
except OSError:
@@ -1348,7 +1348,7 @@ async def _ensure_resolved(self, address, *,
family=0, type=socket.SOCK_STREAM,
proto=0, flags=0, loop):
host, port = address[:2]
- info = _ipaddr_info(host, port, family, type, proto)
+ info = _ipaddr_info(host, port, family, type, proto, *address[2:])
if info is not None:
# "host" is already a resolved IP.
return [info]
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
index 27e21b33d36..f068fc781f5 100644
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -1299,6 +1299,28 @@ def _test_create_connection_ip_addr(self, m_socket, allow_inet_pton):
t.close()
test_utils.run_briefly(self.loop) # allow transport to close
+ @patch_socket
+ def test_create_connection_ipv6_scope(self, m_socket):
+ m_socket.getaddrinfo = socket.getaddrinfo
+ sock = m_socket.socket.return_value
+ sock.family = socket.AF_INET6
+
+ self.loop._add_reader = mock.Mock()
+ self.loop._add_reader._is_coroutine = False
+ self.loop._add_writer = mock.Mock()
+ self.loop._add_writer._is_coroutine = False
+
+ coro = self.loop.create_connection(asyncio.Protocol, 'fe80::1%1', 80)
+ t, p = self.loop.run_until_complete(coro)
+ try:
+ sock.connect.assert_called_with(('fe80::1', 80, 0, 1))
+ _, kwargs = m_socket.socket.call_args
+ self.assertEqual(kwargs['family'], m_socket.AF_INET6)
+ self.assertEqual(kwargs['type'], m_socket.SOCK_STREAM)
+ finally:
+ t.close()
+ test_utils.run_briefly(self.loop) # allow transport to close
+
@patch_socket
def test_create_connection_ip_addr(self, m_socket):
self._test_create_connection_ip_addr(m_socket, True)
diff --git a/Misc/NEWS.d/next/Library/2019-05-11-16-21-29.bpo-35545.FcvJvP.rst b/Misc/NEWS.d/next/Library/2019-05-11-16-21-29.bpo-35545.FcvJvP.rst
new file mode 100644
index 00000000000..f4349afefcd
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-11-16-21-29.bpo-35545.FcvJvP.rst
@@ -0,0 +1,2 @@
+Fix asyncio discarding IPv6 scopes when ensuring hostname resolutions
+internally
From 245f528a92d7748dbd7acf9cba860153c143bbfe Mon Sep 17 00:00:00 2001
From: Stefan Hoelzl
Date: Fri, 17 May 2019 10:50:03 +0200
Subject: [PATCH 080/199] Doc: Add link threading.settrace to sys.settrace
(GH-13345)
---
Doc/library/sys.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
index 591972e9b78..5039ffa933a 100644
--- a/Doc/library/sys.rst
+++ b/Doc/library/sys.rst
@@ -1204,8 +1204,8 @@ always available.
Set the system's trace function, which allows you to implement a Python
source code debugger in Python. The function is thread-specific; for a
- debugger to support multiple threads, it must be registered using
- :func:`settrace` for each thread being debugged.
+ debugger to support multiple threads, it must register a trace function using
+ :func:`settrace` for each thread being debugged or use :func:`threading.settrace`.
Trace functions should have three arguments: *frame*, *event*, and
*arg*. *frame* is the current stack frame. *event* is a string: ``'call'``,
From fed02e15b39b6f1521ea21654be5fc0757a8720a Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Fri, 17 May 2019 11:12:09 +0200
Subject: [PATCH 081/199] bpo-36763: Remove _PyCoreConfig.program (GH-13373)
Use _PyCoreConfig.program_name instead.
---
Include/cpython/coreconfig.h | 14 ++++++---
Lib/test/test_embed.py | 5 ---
Modules/main.c | 4 +--
Programs/_testembed.c | 3 --
Python/coreconfig.c | 60 ++++++++++--------------------------
5 files changed, 27 insertions(+), 59 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index b531118ea3c..1ba2663c966 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -218,11 +218,15 @@ typedef struct {
always exists and is never empty. */
_PyWstrList argv;
- /* Program: argv[0] or "".
- Used to display Python usage if parsing command line arguments fails.
- Used to initialize the default value of program_name */
- wchar_t *program;
- wchar_t *program_name; /* Program name, see also Py_GetProgramName() */
+ /* Program name:
+
+ - If Py_SetProgramName() was called, use its value.
+ - On macOS, use PYTHONEXECUTABLE environment variable if set.
+ - If WITH_NEXT_FRAMEWORK macro is defined, use __PYVENV_LAUNCHER__
+ environment variable is set.
+ - Use argv[0] if available and non-empty.
+ - Use "python" on Windows, or "python3 on other platforms. */
+ wchar_t *program_name;
_PyWstrList xoptions; /* Command line -X options */
_PyWstrList warnoptions; /* Warnings options */
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index b1872ace8a6..4012a389d75 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -306,7 +306,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'program_name': GET_DEFAULT_CONFIG,
'parse_argv': 1,
'argv': [""],
- 'program': '',
'xoptions': [],
'warnoptions': [],
@@ -586,7 +585,6 @@ def test_init_from_config(self):
'pycache_prefix': 'conf_pycache_prefix',
'program_name': './conf_program_name',
'argv': ['-c', 'arg2'],
- 'program': 'conf_program',
'xoptions': ['core_xoption1=3', 'core_xoption2=', 'core_xoption3'],
'warnoptions': ['error::ResourceWarning', 'default::BytesWarning'],
'run_command': 'pass\n',
@@ -704,7 +702,6 @@ def test_init_run_main(self):
'print(json.dumps(_testinternalcapi.get_configs()))')
core_config = {
'argv': ['-c', 'arg2'],
- 'program': 'python3',
'program_name': './python3',
'run_command': code + '\n',
}
@@ -716,7 +713,6 @@ def test_init_main(self):
'print(json.dumps(_testinternalcapi.get_configs()))')
core_config = {
'argv': ['-c', 'arg2'],
- 'program': 'python3',
'program_name': './python3',
'run_command': code + '\n',
'_init_main': 0,
@@ -728,7 +724,6 @@ def test_init_dont_parse_argv(self):
core_config = {
'argv': ['-v', '-c', 'arg1', '-W', 'arg2'],
'parse_argv': 0,
- 'program': 'program',
}
self.check_config("init_dont_parse_argv", core_config, {})
diff --git a/Modules/main.c b/Modules/main.c
index b47ac70d62c..bb103c28a3e 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -283,7 +283,7 @@ pymain_run_file(_PyCoreConfig *config, PyCompilerFlags *cf)
else
cfilename = "";
fprintf(stderr, "%ls: can't open file '%s': [Errno %d] %s\n",
- config->program, cfilename, err, strerror(err));
+ config->program_name, cfilename, err, strerror(err));
PyMem_RawFree(cfilename_buffer);
return 2;
}
@@ -303,7 +303,7 @@ pymain_run_file(_PyCoreConfig *config, PyCompilerFlags *cf)
if (_Py_fstat_noraise(fileno(fp), &sb) == 0 && S_ISDIR(sb.st_mode)) {
fprintf(stderr,
"%ls: '%ls' is a directory, cannot continue\n",
- config->program, filename);
+ config->program_name, filename);
fclose(fp);
return 1;
}
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 87d159fe721..b1b7c6e0ffc 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -433,8 +433,6 @@ static int test_init_from_config(void)
config.argv.length = Py_ARRAY_LENGTH(argv);
config.argv.items = argv;
- config.program = L"conf_program";
-
static wchar_t* xoptions[3] = {
L"core_xoption1=3",
L"core_xoption2=",
@@ -532,7 +530,6 @@ static int test_init_dont_parse_argv(void)
L"arg2",
};
- config.program = L"program";
config.program_name = L"./_testembed";
config.argv.length = Py_ARRAY_LENGTH(argv);
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index ce778a640d3..c20ae2151c9 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -492,7 +492,6 @@ _PyCoreConfig_Clear(_PyCoreConfig *config)
CLEAR(config->module_search_path_env);
CLEAR(config->home);
CLEAR(config->program_name);
- CLEAR(config->program);
_PyWstrList_Clear(&config->argv);
_PyWstrList_Clear(&config->warnoptions);
@@ -626,7 +625,6 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
COPY_WSTR_ATTR(module_search_path_env);
COPY_WSTR_ATTR(home);
COPY_WSTR_ATTR(program_name);
- COPY_WSTR_ATTR(program);
COPY_ATTR(parse_argv);
COPY_WSTRLIST(argv);
@@ -732,7 +730,6 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config)
SET_ITEM_WSTR(program_name);
SET_ITEM_INT(parse_argv);
SET_ITEM_WSTRLIST(argv);
- SET_ITEM_WSTR(program);
SET_ITEM_WSTRLIST(xoptions);
SET_ITEM_WSTRLIST(warnoptions);
SET_ITEM_WSTR(module_search_path_env);
@@ -918,7 +915,6 @@ static _PyInitError
config_init_program_name(_PyCoreConfig *config)
{
_PyInitError err;
- assert(config->program_name == NULL);
/* If Py_SetProgramName() was called, use its value */
const wchar_t *program_name = _Py_path_config.program_name;
@@ -967,16 +963,17 @@ config_init_program_name(_PyCoreConfig *config)
#endif /* WITH_NEXT_FRAMEWORK */
#endif /* __APPLE__ */
- /* Use argv[0] by default, if available */
- if (config->program != NULL) {
- err = _PyCoreConfig_SetString(&config->program_name, config->program);
- if (_Py_INIT_FAILED(err)) {
- return err;
+ /* Use argv[0] if available and non-empty */
+ const _PyWstrList *argv = &config->argv;
+ if (argv->length >= 1 && argv->items[0][0] != L'\0') {
+ config->program_name = _PyMem_RawWcsdup(argv->items[0]);
+ if (config->program_name == NULL) {
+ return _Py_INIT_NO_MEMORY();
}
return _Py_INIT_OK();
}
- /* Last fall back: hardcoded string */
+ /* Last fall back: hardcoded name */
#ifdef MS_WINDOWS
const wchar_t *default_program_name = L"python";
#else
@@ -1518,13 +1515,6 @@ config_read(_PyCoreConfig *config)
}
}
- if (config->program_name == NULL) {
- err = config_init_program_name(config);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
- }
-
if (config->executable == NULL) {
err = config_init_executable(config);
if (_Py_INIT_FAILED(err)) {
@@ -1678,6 +1668,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions,
_PyInitError err;
const _PyWstrList *argv = &config->argv;
int print_version = 0;
+ const wchar_t* program = config->program_name;
_PyOS_ResetGetOpt();
do {
@@ -1734,7 +1725,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions,
} else {
fprintf(stderr, "--check-hash-based-pycs must be one of "
"'default', 'always', or 'never'\n");
- config_usage(1, config->program);
+ config_usage(1, program);
return _Py_INIT_EXIT(2);
}
break;
@@ -1794,7 +1785,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions,
case 'h':
case '?':
- config_usage(0, config->program);
+ config_usage(0, program);
return _Py_INIT_EXIT(0);
case 'V':
@@ -1819,7 +1810,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions,
default:
/* unknown argument: parsing failed */
- config_usage(1, config->program);
+ config_usage(1, program);
return _Py_INIT_EXIT(2);
}
} while (1);
@@ -1892,26 +1883,6 @@ config_init_env_warnoptions(const _PyCoreConfig *config, _PyWstrList *warnoption
}
-static _PyInitError
-config_init_program(_PyCoreConfig *config)
-{
- const _PyWstrList *argv = &config->argv;
- wchar_t *program;
- if (argv->length >= 1) {
- program = argv->items[0];
- }
- else {
- program = L"";
- }
- config->program = _PyMem_RawWcsdup(program);
- if (config->program == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
-
- return _Py_INIT_OK();
-}
-
-
static int
config_add_warnoption(_PyCoreConfig *config, const wchar_t *option)
{
@@ -2084,10 +2055,10 @@ config_read_cmdline(_PyCoreConfig *config)
config->parse_argv = 1;
}
- if (config->program == NULL) {
- err = config_init_program(config);
+ if (config->program_name == NULL) {
+ err = config_init_program_name(config);
if (_Py_INIT_FAILED(err)) {
- goto done;
+ return err;
}
}
@@ -2218,6 +2189,8 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
goto done;
}
+ /* precmdline.argv is a copy of config.argv which is modified
+ by config_read_cmdline() */
const _PyWstrList *argv = &precmdline.argv;
if (_Py_SetArgcArgv(argv->length, argv->items) < 0) {
err = _Py_INIT_NO_MEMORY();
@@ -2246,7 +2219,6 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
assert(config->configure_c_stdio >= 0);
assert(config->buffered_stdio >= 0);
assert(config->program_name != NULL);
- assert(config->program != NULL);
assert(_PyWstrList_CheckConsistency(&config->argv));
/* sys.argv must be non-empty: empty argv is replaced with [''] */
assert(config->argv.length >= 1);
From cbb6484573ae2058e55614b28d73b0c8478f9a70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Wirtel?=
Date: Fri, 17 May 2019 11:55:34 +0200
Subject: [PATCH 082/199] Doc: Replace the deprecated highlightlang directive
by highlight. (#13377)
highlightlang is deprecated since April 2018 in Sphinx.
See https://github.com/sphinx-doc/sphinx/pull/4845
---
Doc/c-api/abstract.rst | 2 +-
Doc/c-api/allocation.rst | 2 +-
Doc/c-api/apiabiversion.rst | 2 +-
Doc/c-api/arg.rst | 2 +-
Doc/c-api/bool.rst | 2 +-
Doc/c-api/buffer.rst | 2 +-
Doc/c-api/bytearray.rst | 2 +-
Doc/c-api/bytes.rst | 2 +-
Doc/c-api/capsule.rst | 2 +-
Doc/c-api/cell.rst | 2 +-
Doc/c-api/code.rst | 2 +-
Doc/c-api/complex.rst | 2 +-
Doc/c-api/concrete.rst | 2 +-
Doc/c-api/contextvars.rst | 2 +-
Doc/c-api/conversion.rst | 2 +-
Doc/c-api/coro.rst | 2 +-
Doc/c-api/datetime.rst | 2 +-
Doc/c-api/descriptor.rst | 2 +-
Doc/c-api/dict.rst | 2 +-
Doc/c-api/exceptions.rst | 2 +-
Doc/c-api/file.rst | 2 +-
Doc/c-api/float.rst | 2 +-
Doc/c-api/function.rst | 2 +-
Doc/c-api/gcsupport.rst | 2 +-
Doc/c-api/gen.rst | 2 +-
Doc/c-api/import.rst | 2 +-
Doc/c-api/init.rst | 2 +-
Doc/c-api/intro.rst | 2 +-
Doc/c-api/iter.rst | 2 +-
Doc/c-api/iterator.rst | 2 +-
Doc/c-api/list.rst | 2 +-
Doc/c-api/long.rst | 2 +-
Doc/c-api/mapping.rst | 2 +-
Doc/c-api/marshal.rst | 2 +-
Doc/c-api/memory.rst | 2 +-
Doc/c-api/memoryview.rst | 2 +-
Doc/c-api/method.rst | 2 +-
Doc/c-api/module.rst | 2 +-
Doc/c-api/none.rst | 2 +-
Doc/c-api/number.rst | 2 +-
Doc/c-api/objbuffer.rst | 2 +-
Doc/c-api/object.rst | 2 +-
Doc/c-api/objimpl.rst | 2 +-
Doc/c-api/refcounting.rst | 2 +-
Doc/c-api/reflection.rst | 2 +-
Doc/c-api/sequence.rst | 2 +-
Doc/c-api/set.rst | 2 +-
Doc/c-api/slice.rst | 2 +-
Doc/c-api/stable.rst | 2 +-
Doc/c-api/structures.rst | 2 +-
Doc/c-api/sys.rst | 2 +-
Doc/c-api/tuple.rst | 2 +-
Doc/c-api/type.rst | 2 +-
Doc/c-api/typeobj.rst | 2 +-
Doc/c-api/unicode.rst | 2 +-
Doc/c-api/utilities.rst | 2 +-
Doc/c-api/veryhigh.rst | 2 +-
Doc/c-api/weakref.rst | 2 +-
Doc/extending/building.rst | 6 +++---
Doc/extending/embedding.rst | 2 +-
Doc/extending/extending.rst | 2 +-
Doc/extending/newtypes.rst | 2 +-
Doc/extending/newtypes_tutorial.rst | 2 +-
Doc/extending/windows.rst | 2 +-
Doc/faq/windows.rst | 2 +-
Doc/howto/clinic.rst | 2 +-
Doc/howto/cporting.rst | 2 +-
Doc/install/index.rst | 2 +-
Doc/installing/index.rst | 2 +-
Doc/library/site.rst | 2 +-
Doc/license.rst | 2 +-
Doc/using/cmdline.rst | 2 +-
Doc/using/unix.rst | 2 +-
Doc/using/windows.rst | 2 +-
74 files changed, 76 insertions(+), 76 deletions(-)
diff --git a/Doc/c-api/abstract.rst b/Doc/c-api/abstract.rst
index ad538811127..0edd1d5f624 100644
--- a/Doc/c-api/abstract.rst
+++ b/Doc/c-api/abstract.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _abstract:
diff --git a/Doc/c-api/allocation.rst b/Doc/c-api/allocation.rst
index 25a867f139c..8e8a92003c5 100644
--- a/Doc/c-api/allocation.rst
+++ b/Doc/c-api/allocation.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _allocating-objects:
diff --git a/Doc/c-api/apiabiversion.rst b/Doc/c-api/apiabiversion.rst
index 890a0383931..b8a8f2ff886 100644
--- a/Doc/c-api/apiabiversion.rst
+++ b/Doc/c-api/apiabiversion.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _apiabiversion:
diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst
index b41130ede41..ba9ca5e0d30 100644
--- a/Doc/c-api/arg.rst
+++ b/Doc/c-api/arg.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _arg-parsing:
diff --git a/Doc/c-api/bool.rst b/Doc/c-api/bool.rst
index a9fb342f7c0..ce8de6e22f4 100644
--- a/Doc/c-api/bool.rst
+++ b/Doc/c-api/bool.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _boolobjects:
diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst
index c7c1e3cc745..72d965053cf 100644
--- a/Doc/c-api/buffer.rst
+++ b/Doc/c-api/buffer.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. index::
single: buffer protocol
diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst
index 41b6e3c71be..b4a9660a916 100644
--- a/Doc/c-api/bytearray.rst
+++ b/Doc/c-api/bytearray.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _bytearrayobjects:
diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst
index 5b9ebf6b6af..9a62fb682d6 100644
--- a/Doc/c-api/bytes.rst
+++ b/Doc/c-api/bytes.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _bytesobjects:
diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst
index 8eb6695e22d..3c921bbde34 100644
--- a/Doc/c-api/capsule.rst
+++ b/Doc/c-api/capsule.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _capsules:
diff --git a/Doc/c-api/cell.rst b/Doc/c-api/cell.rst
index 427259cc24d..8514afe928e 100644
--- a/Doc/c-api/cell.rst
+++ b/Doc/c-api/cell.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _cell-objects:
diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst
index 10d89f297c8..27d3f76d7a3 100644
--- a/Doc/c-api/code.rst
+++ b/Doc/c-api/code.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _codeobjects:
diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst
index fc63b57a855..675bd013e89 100644
--- a/Doc/c-api/complex.rst
+++ b/Doc/c-api/complex.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _complexobjects:
diff --git a/Doc/c-api/concrete.rst b/Doc/c-api/concrete.rst
index 9558a4a583c..f83d711795c 100644
--- a/Doc/c-api/concrete.rst
+++ b/Doc/c-api/concrete.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _concrete:
diff --git a/Doc/c-api/contextvars.rst b/Doc/c-api/contextvars.rst
index c344c8d71ae..a7cde7fb195 100644
--- a/Doc/c-api/contextvars.rst
+++ b/Doc/c-api/contextvars.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _contextvarsobjects:
diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst
index c46722d782a..ed101c791ec 100644
--- a/Doc/c-api/conversion.rst
+++ b/Doc/c-api/conversion.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _string-conversion:
diff --git a/Doc/c-api/coro.rst b/Doc/c-api/coro.rst
index 2fe50b5d8c4..50428c7eb43 100644
--- a/Doc/c-api/coro.rst
+++ b/Doc/c-api/coro.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _coro-objects:
diff --git a/Doc/c-api/datetime.rst b/Doc/c-api/datetime.rst
index 77b1b216744..44a04373d19 100644
--- a/Doc/c-api/datetime.rst
+++ b/Doc/c-api/datetime.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _datetimeobjects:
diff --git a/Doc/c-api/descriptor.rst b/Doc/c-api/descriptor.rst
index c8f6fa5bcd7..1005140c7ac 100644
--- a/Doc/c-api/descriptor.rst
+++ b/Doc/c-api/descriptor.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _descriptor-objects:
diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst
index 0ced5a5fd00..e970771893e 100644
--- a/Doc/c-api/dict.rst
+++ b/Doc/c-api/dict.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _dictobjects:
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index 13f0aff1cf9..00ef00526bc 100644
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _exceptionhandling:
diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst
index 6f2ecee51fd..defc859dd5c 100644
--- a/Doc/c-api/file.rst
+++ b/Doc/c-api/file.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _fileobjects:
diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst
index 27a75e3e0c2..8a996422ce4 100644
--- a/Doc/c-api/float.rst
+++ b/Doc/c-api/float.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _floatobjects:
diff --git a/Doc/c-api/function.rst b/Doc/c-api/function.rst
index 17279c732ae..02c4ebdbed4 100644
--- a/Doc/c-api/function.rst
+++ b/Doc/c-api/function.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _function-objects:
diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst
index b739aacea8d..b3f30b2ed9e 100644
--- a/Doc/c-api/gcsupport.rst
+++ b/Doc/c-api/gcsupport.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _supporting-cycle-detection:
diff --git a/Doc/c-api/gen.rst b/Doc/c-api/gen.rst
index 1efbae4fcba..8d54021c181 100644
--- a/Doc/c-api/gen.rst
+++ b/Doc/c-api/gen.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _gen-objects:
diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst
index 8cdc256e7c9..86cc4031610 100644
--- a/Doc/c-api/import.rst
+++ b/Doc/c-api/import.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _importing:
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index b30649498a9..a0ac4d21d13 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _initialization:
diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst
index 69aef0da04f..b003bbaeff2 100644
--- a/Doc/c-api/intro.rst
+++ b/Doc/c-api/intro.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _api-intro:
diff --git a/Doc/c-api/iter.rst b/Doc/c-api/iter.rst
index 2ba444d1de6..546efb518a7 100644
--- a/Doc/c-api/iter.rst
+++ b/Doc/c-api/iter.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _iterator:
diff --git a/Doc/c-api/iterator.rst b/Doc/c-api/iterator.rst
index 82cb4eba8ab..4d91e4a224f 100644
--- a/Doc/c-api/iterator.rst
+++ b/Doc/c-api/iterator.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _iterator-objects:
diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst
index 5b263a7b1cd..279783a243a 100644
--- a/Doc/c-api/list.rst
+++ b/Doc/c-api/list.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _listobjects:
diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
index 8093f4b627a..6be29f9cd32 100644
--- a/Doc/c-api/long.rst
+++ b/Doc/c-api/long.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _longobjects:
diff --git a/Doc/c-api/mapping.rst b/Doc/c-api/mapping.rst
index e37dec9949a..4244b47af75 100644
--- a/Doc/c-api/mapping.rst
+++ b/Doc/c-api/mapping.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _mapping:
diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst
index 17ec621610b..b086830feb1 100644
--- a/Doc/c-api/marshal.rst
+++ b/Doc/c-api/marshal.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _marshalling-utils:
diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst
index 65a207691b8..ab49e48782d 100644
--- a/Doc/c-api/memory.rst
+++ b/Doc/c-api/memory.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _memory:
diff --git a/Doc/c-api/memoryview.rst b/Doc/c-api/memoryview.rst
index 9f6bfd751ad..77afb020405 100644
--- a/Doc/c-api/memoryview.rst
+++ b/Doc/c-api/memoryview.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _memoryview-objects:
diff --git a/Doc/c-api/method.rst b/Doc/c-api/method.rst
index 7a2a84fe110..1ad805e269a 100644
--- a/Doc/c-api/method.rst
+++ b/Doc/c-api/method.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _instancemethod-objects:
diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst
index 017b656854a..68cbda2938f 100644
--- a/Doc/c-api/module.rst
+++ b/Doc/c-api/module.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _moduleobjects:
diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst
index 45568fe657b..26d2b7aab20 100644
--- a/Doc/c-api/none.rst
+++ b/Doc/c-api/none.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _noneobject:
diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst
index 9fb220b192b..74932f6e744 100644
--- a/Doc/c-api/number.rst
+++ b/Doc/c-api/number.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _number:
diff --git a/Doc/c-api/objbuffer.rst b/Doc/c-api/objbuffer.rst
index 3572564b13e..6b82a642d7e 100644
--- a/Doc/c-api/objbuffer.rst
+++ b/Doc/c-api/objbuffer.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
Old Buffer Protocol
-------------------
diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst
index a64ff2e6b58..ffc35241e7a 100644
--- a/Doc/c-api/object.rst
+++ b/Doc/c-api/object.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _object:
diff --git a/Doc/c-api/objimpl.rst b/Doc/c-api/objimpl.rst
index 7023e519eda..8bd8c107c98 100644
--- a/Doc/c-api/objimpl.rst
+++ b/Doc/c-api/objimpl.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _newtypes:
diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst
index 225a1feb250..6b07c87d62e 100644
--- a/Doc/c-api/refcounting.rst
+++ b/Doc/c-api/refcounting.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _countingrefs:
diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index 96893652f73..080ea3222cf 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _reflection:
diff --git a/Doc/c-api/sequence.rst b/Doc/c-api/sequence.rst
index 6d22f35e22b..d11a2dde54d 100644
--- a/Doc/c-api/sequence.rst
+++ b/Doc/c-api/sequence.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _sequence:
diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst
index 64b6dde3b74..074fcb877e1 100644
--- a/Doc/c-api/set.rst
+++ b/Doc/c-api/set.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _setobjects:
diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst
index 8ad9a29b256..d924308890b 100644
--- a/Doc/c-api/slice.rst
+++ b/Doc/c-api/slice.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _slice-objects:
diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst
index 5b771dd4adc..9c05cb3c82d 100644
--- a/Doc/c-api/stable.rst
+++ b/Doc/c-api/stable.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _stable:
diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst
index da45da1d3c7..5e0cfd0264f 100644
--- a/Doc/c-api/structures.rst
+++ b/Doc/c-api/structures.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _common-structs:
diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst
index c8ea78363df..04e169a00dc 100644
--- a/Doc/c-api/sys.rst
+++ b/Doc/c-api/sys.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _os:
diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst
index 20bf9f0b080..259ec4fb485 100644
--- a/Doc/c-api/tuple.rst
+++ b/Doc/c-api/tuple.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _tupleobjects:
diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 4dfd53fb9f0..2474df2c90b 100644
--- a/Doc/c-api/type.rst
+++ b/Doc/c-api/type.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _typeobjects:
diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
index 0647a493303..b1d96db7f53 100644
--- a/Doc/c-api/typeobj.rst
+++ b/Doc/c-api/typeobj.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _type-structs:
diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst
index 724c798456f..a150a9c39d8 100644
--- a/Doc/c-api/unicode.rst
+++ b/Doc/c-api/unicode.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _unicodeobjects:
diff --git a/Doc/c-api/utilities.rst b/Doc/c-api/utilities.rst
index d4484fb2712..a805b564763 100644
--- a/Doc/c-api/utilities.rst
+++ b/Doc/c-api/utilities.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _utilities:
diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst
index 317093e9561..a7ff08cfb6b 100644
--- a/Doc/c-api/veryhigh.rst
+++ b/Doc/c-api/veryhigh.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _veryhigh:
diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst
index 6cb3e33fe84..7a4f8615b9c 100644
--- a/Doc/c-api/weakref.rst
+++ b/Doc/c-api/weakref.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _weakrefobjects:
diff --git a/Doc/extending/building.rst b/Doc/extending/building.rst
index 9bfad7fc318..753b5511ed9 100644
--- a/Doc/extending/building.rst
+++ b/Doc/extending/building.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _building:
@@ -20,7 +20,7 @@ The initialization function has the signature:
It returns either a fully-initialized module, or a :c:type:`PyModuleDef`
instance. See :ref:`initializing-modules` for details.
-.. highlightlang:: python
+.. highlight:: python
For modules with ASCII-only names, the function must be named
``PyInit_``, with ```` replaced by the name of the
@@ -43,7 +43,7 @@ function corresponding to the filename is found.
See the *"Multiple modules in one library"* section in :pep:`489` for details.
-.. highlightlang:: c
+.. highlight:: c
Building C and C++ Extensions with distutils
============================================
diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst
index 13d83b72f82..483bc852f6c 100644
--- a/Doc/extending/embedding.rst
+++ b/Doc/extending/embedding.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _embedding:
diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst
index 433178ab64d..e459514b2b5 100644
--- a/Doc/extending/extending.rst
+++ b/Doc/extending/extending.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _extending-intro:
diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst
index 8b9549d7e39..308c06705e8 100644
--- a/Doc/extending/newtypes.rst
+++ b/Doc/extending/newtypes.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _new-types-topics:
diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst
index b4bf9b9e6f7..59c8cc01222 100644
--- a/Doc/extending/newtypes_tutorial.rst
+++ b/Doc/extending/newtypes_tutorial.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _defining-new-types:
diff --git a/Doc/extending/windows.rst b/Doc/extending/windows.rst
index 67bdd475aeb..c7b92c6ea24 100644
--- a/Doc/extending/windows.rst
+++ b/Doc/extending/windows.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _building-on-windows:
diff --git a/Doc/faq/windows.rst b/Doc/faq/windows.rst
index ad97cd0932a..a181086e9ce 100644
--- a/Doc/faq/windows.rst
+++ b/Doc/faq/windows.rst
@@ -1,6 +1,6 @@
:tocdepth: 2
-.. highlightlang:: none
+.. highlight:: none
.. _windows-faq:
diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst
index 5b2457a1682..cfd9f2e4075 100644
--- a/Doc/howto/clinic.rst
+++ b/Doc/howto/clinic.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
**********************
Argument Clinic How-To
diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst
index b638e32f5d0..ce7700fc599 100644
--- a/Doc/howto/cporting.rst
+++ b/Doc/howto/cporting.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: c
+.. highlight:: c
.. _cporting-howto:
diff --git a/Doc/install/index.rst b/Doc/install/index.rst
index e14232415be..a91606c0f38 100644
--- a/Doc/install/index.rst
+++ b/Doc/install/index.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: none
+.. highlight:: none
.. _install-index:
diff --git a/Doc/installing/index.rst b/Doc/installing/index.rst
index 747b9223b62..dc44aa64b8e 100644
--- a/Doc/installing/index.rst
+++ b/Doc/installing/index.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: none
+.. highlight:: none
.. _installing-index:
diff --git a/Doc/library/site.rst b/Doc/library/site.rst
index dfc40d17944..9e4d402c1f5 100644
--- a/Doc/library/site.rst
+++ b/Doc/library/site.rst
@@ -8,7 +8,7 @@
--------------
-.. highlightlang:: none
+.. highlight:: none
**This module is automatically imported during initialization.** The automatic
import can be suppressed using the interpreter's :option:`-S` option.
diff --git a/Doc/license.rst b/Doc/license.rst
index bf2e4c522ce..d877f456775 100644
--- a/Doc/license.rst
+++ b/Doc/license.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: none
+.. highlight:: none
.. _history-and-license:
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index 5ae3cc808b3..87af7e8be13 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: sh
+.. highlight:: sh
.. ATTENTION: You probably should update Misc/python.man, too, if you modify
this file.
diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst
index 31cf87c66f5..021f0d35a8e 100644
--- a/Doc/using/unix.rst
+++ b/Doc/using/unix.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: sh
+.. highlight:: sh
.. _using-on-unix:
diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst
index 1f8eb16e505..44b646fddfc 100644
--- a/Doc/using/windows.rst
+++ b/Doc/using/windows.rst
@@ -1,4 +1,4 @@
-.. highlightlang:: none
+.. highlight:: none
.. _using-on-windows:
From 6faad355db6c2bd4a0ade7868f245b42c04f5337 Mon Sep 17 00:00:00 2001
From: Ned Batchelder
Date: Fri, 17 May 2019 05:59:14 -0400
Subject: [PATCH 083/199] bpo-36908: 'This module is always available' isn't
helpful. (#13297)
Makes the documentation of math and cmath module
more helpful for the beginners.
---
Doc/library/cmath.rst | 13 ++++++-------
Doc/library/math.rst | 4 ++--
Modules/cmathmodule.c | 4 ++--
Modules/mathmodule.c | 4 ++--
4 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst
index 9d81730f201..28cd96b0e12 100644
--- a/Doc/library/cmath.rst
+++ b/Doc/library/cmath.rst
@@ -6,13 +6,12 @@
--------------
-This module is always available. It provides access to mathematical functions
-for complex numbers. The functions in this module accept integers,
-floating-point numbers or complex numbers as arguments. They will also accept
-any Python object that has either a :meth:`__complex__` or a :meth:`__float__`
-method: these methods are used to convert the object to a complex or
-floating-point number, respectively, and the function is then applied to the
-result of the conversion.
+This module provides access to mathematical functions for complex numbers. The
+functions in this module accept integers, floating-point numbers or complex
+numbers as arguments. They will also accept any Python object that has either a
+:meth:`__complex__` or a :meth:`__float__` method: these methods are used to
+convert the object to a complex or floating-point number, respectively, and
+the function is then applied to the result of the conversion.
.. note::
diff --git a/Doc/library/math.rst b/Doc/library/math.rst
index 7129525c788..49f932d0384 100644
--- a/Doc/library/math.rst
+++ b/Doc/library/math.rst
@@ -10,8 +10,8 @@
--------------
-This module is always available. It provides access to the mathematical
-functions defined by the C standard.
+This module provides access to the mathematical functions defined by the C
+standard.
These functions cannot be used with complex numbers; use the functions of the
same name from the :mod:`cmath` module if you require support for complex
diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c
index 8319767b8a9..b421f04fa60 100644
--- a/Modules/cmathmodule.c
+++ b/Modules/cmathmodule.c
@@ -1232,8 +1232,8 @@ cmath_isclose_impl(PyObject *module, Py_complex a, Py_complex b,
}
PyDoc_STRVAR(module_doc,
-"This module is always available. It provides access to mathematical\n"
-"functions for complex numbers.");
+"This module provides access to mathematical functions for complex\n"
+"numbers.");
static PyMethodDef cmath_methods[] = {
CMATH_ACOS_METHODDEF
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index ba8423211c2..8f6a303cc4d 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -2759,8 +2759,8 @@ static PyMethodDef math_methods[] = {
PyDoc_STRVAR(module_doc,
-"This module is always available. It provides access to the\n"
-"mathematical functions defined by the C standard.");
+"This module provides access to the mathematical functions\n"
+"defined by the C standard.");
static struct PyModuleDef mathmodule = {
From a8b46944d72bba6dc76260ed61da5c78d3f9d9c0 Mon Sep 17 00:00:00 2001
From: Jeroen Demeyer
Date: Fri, 17 May 2019 12:21:35 +0200
Subject: [PATCH 084/199] Fix typo in _PyMethodDef_RawFastCallKeywords error
message (GH-13343)
---
Objects/call.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Objects/call.c b/Objects/call.c
index 68f9e879fa7..337ca811080 100644
--- a/Objects/call.c
+++ b/Objects/call.c
@@ -701,7 +701,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self,
default:
PyErr_SetString(PyExc_SystemError,
- "Bad call flags in _PyCFunction_FastCallKeywords. "
+ "Bad call flags in _PyMethodDef_RawFastCallKeywords. "
"METH_OLDARGS is no longer supported!");
goto exit;
}
From af8646c8054d0f4180a2013383039b6a472f9698 Mon Sep 17 00:00:00 2001
From: Pablo Galindo
Date: Fri, 17 May 2019 11:37:08 +0100
Subject: [PATCH 085/199] bpo-1875: Raise SyntaxError in invalid blocks that
will be optimised away (GH-13332)
Move the check for dead conditionals (if 0) to the peephole optimizer
and make sure that the code block is still compiled to report any
existing syntax errors within.
---
Lib/test/test_syntax.py | 14 ++++++++++++++
.../2019-05-15-01-29-29.bpo-1875.9oxXFX.rst | 3 +++
Python/compile.c | 9 ++++-----
Python/peephole.c | 16 ++++++++++++----
4 files changed, 33 insertions(+), 9 deletions(-)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-05-15-01-29-29.bpo-1875.9oxXFX.rst
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 4a2899ebca3..8451c072f64 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -696,6 +696,20 @@ def error2():
def test_break_outside_loop(self):
self._check_error("break", "outside loop")
+ def test_yield_outside_function(self):
+ self._check_error("if 0: yield", "outside function")
+ self._check_error("class C:\n if 0: yield", "outside function")
+
+ def test_return_outside_function(self):
+ self._check_error("if 0: return", "outside function")
+ self._check_error("class C:\n if 0: return", "outside function")
+
+ def test_break_outside_loop(self):
+ self._check_error("if 0: break", "outside loop")
+
+ def test_continue_outside_loop(self):
+ self._check_error("if 0: continue", "not properly in loop")
+
def test_unexpected_indent(self):
self._check_error("foo()\n bar()\n", "unexpected indent",
subclass=IndentationError)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-15-01-29-29.bpo-1875.9oxXFX.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-15-01-29-29.bpo-1875.9oxXFX.rst
new file mode 100644
index 00000000000..8f095ed9f16
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-15-01-29-29.bpo-1875.9oxXFX.rst
@@ -0,0 +1,3 @@
+A :exc:`SyntaxError` is now raised if a code blocks that will be optimized
+away (e.g. if conditions that are always false) contains syntax errors.
+Patch by Pablo Galindo.
diff --git a/Python/compile.c b/Python/compile.c
index 91ce04b02e5..2a086a509f4 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -2546,13 +2546,12 @@ compiler_if(struct compiler *c, stmt_ty s)
return 0;
constant = expr_constant(s->v.If.test);
- /* constant = 0: "if 0"
+ /* constant = 0: "if 0" Leave the optimizations to
+ * the pephole optimizer to check for syntax errors
+ * in the block.
* constant = 1: "if 1", "if 2", ...
* constant = -1: rest */
- if (constant == 0) {
- if (s->v.If.orelse)
- VISIT_SEQ(c, stmt, s->v.If.orelse);
- } else if (constant == 1) {
+ if (constant == 1) {
VISIT_SEQ(c, stmt, s->v.If.body);
} else {
if (asdl_seq_LEN(s->v.If.orelse)) {
diff --git a/Python/peephole.c b/Python/peephole.c
index cc244aa433e..1ce3535626e 100644
--- a/Python/peephole.c
+++ b/Python/peephole.c
@@ -302,11 +302,19 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case LOAD_CONST:
cumlc = lastlc + 1;
if (nextop != POP_JUMP_IF_FALSE ||
- !ISBASICBLOCK(blocks, op_start, i + 1) ||
- !PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
+ !ISBASICBLOCK(blocks, op_start, i + 1)) {
break;
- fill_nops(codestr, op_start, nexti + 1);
- cumlc = 0;
+ }
+ PyObject* cnt = PyList_GET_ITEM(consts, get_arg(codestr, i));
+ int is_true = PyObject_IsTrue(cnt);
+ if (is_true == 1) {
+ fill_nops(codestr, op_start, nexti + 1);
+ cumlc = 0;
+ } else if (is_true == 0) {
+ h = get_arg(codestr, nexti) / sizeof(_Py_CODEUNIT);
+ tgt = find_op(codestr, codelen, h);
+ fill_nops(codestr, op_start, tgt);
+ }
break;
/* Try to fold tuples of constants.
From f98c3c59c0930ee41175d8935f72bfeed5fee17a Mon Sep 17 00:00:00 2001
From: redshiftzero
Date: Fri, 17 May 2019 03:44:18 -0700
Subject: [PATCH 086/199] docs 36789: resolve incorrect note regarding UTF-8
(GH-13111)
---
Doc/howto/unicode.rst | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/Doc/howto/unicode.rst b/Doc/howto/unicode.rst
index 7b2d7b8abf8..24c3235e4ad 100644
--- a/Doc/howto/unicode.rst
+++ b/Doc/howto/unicode.rst
@@ -135,17 +135,22 @@ used than UTF-8.) UTF-8 uses the following rules:
UTF-8 has several convenient properties:
1. It can handle any Unicode code point.
-2. A Unicode string is turned into a sequence of bytes containing no embedded zero
- bytes. This avoids byte-ordering issues, and means UTF-8 strings can be
- processed by C functions such as ``strcpy()`` and sent through protocols that
- can't handle zero bytes.
+2. A Unicode string is turned into a sequence of bytes that contains embedded
+ zero bytes only where they represent the null character (U+0000). This means
+ that UTF-8 strings can be processed by C functions such as ``strcpy()`` and sent
+ through protocols that can't handle zero bytes for anything other than
+ end-of-string markers.
3. A string of ASCII text is also valid UTF-8 text.
4. UTF-8 is fairly compact; the majority of commonly used characters can be
represented with one or two bytes.
5. If bytes are corrupted or lost, it's possible to determine the start of the
next UTF-8-encoded code point and resynchronize. It's also unlikely that
random 8-bit data will look like valid UTF-8.
-
+6. UTF-8 is a byte oriented encoding. The encoding specifies that each
+ character is represented by a specific sequence of one or more bytes. This
+ avoids the byte-ordering issues that can occur with integer and word oriented
+ encodings, like UTF-16 and UTF-32, where the sequence of bytes varies depending
+ on the hardware on which the string was encoded.
References
From 80ed353329ef01ca6ab2056051fb999818a86215 Mon Sep 17 00:00:00 2001
From: Christian Heimes
Date: Fri, 17 May 2019 13:08:14 +0200
Subject: [PATCH 087/199] Simplify SSLSocket / SSLObject doc string (GH-9972)
Instead of maintaining the same doc string two times, let's copy common
doc strings from SSLObject methods and properties to SSLSocket.
Signed-off-by: Christian Heimes
---
Lib/ssl.py | 37 +++++++++++++++++++++----------------
1 file changed, 21 insertions(+), 16 deletions(-)
diff --git a/Lib/ssl.py b/Lib/ssl.py
index e6e3a6d0fa8..793ed496c77 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -781,6 +781,12 @@ def verify_client_post_handshake(self):
return self._sslobj.verify_client_post_handshake()
+def _sslcopydoc(func):
+ """Copy docstring from SSLObject to SSLSocket"""
+ func.__doc__ = getattr(SSLObject, func.__name__).__doc__
+ return func
+
+
class SSLSocket(socket):
"""This class implements a subtype of socket.socket that wraps
the underlying OS socket in an SSL context when necessary, and
@@ -857,6 +863,7 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True,
return self
@property
+ @_sslcopydoc
def context(self):
return self._context
@@ -866,8 +873,8 @@ def context(self, ctx):
self._sslobj.context = ctx
@property
+ @_sslcopydoc
def session(self):
- """The SSLSession for client socket."""
if self._sslobj is not None:
return self._sslobj.session
@@ -878,8 +885,8 @@ def session(self, session):
self._sslobj.session = session
@property
+ @_sslcopydoc
def session_reused(self):
- """Was the client session reused during handshake"""
if self._sslobj is not None:
return self._sslobj.session_reused
@@ -929,16 +936,13 @@ def write(self, data):
raise ValueError("Write on closed or unwrapped SSL socket.")
return self._sslobj.write(data)
+ @_sslcopydoc
def getpeercert(self, binary_form=False):
- """Returns a formatted version of the data in the
- certificate provided by the other end of the SSL channel.
- Return None if no certificate was provided, {} if a
- certificate was provided, but not validated."""
-
self._checkClosed()
self._check_connected()
return self._sslobj.getpeercert(binary_form)
+ @_sslcopydoc
def selected_npn_protocol(self):
self._checkClosed()
if self._sslobj is None or not _ssl.HAS_NPN:
@@ -946,6 +950,7 @@ def selected_npn_protocol(self):
else:
return self._sslobj.selected_npn_protocol()
+ @_sslcopydoc
def selected_alpn_protocol(self):
self._checkClosed()
if self._sslobj is None or not _ssl.HAS_ALPN:
@@ -953,6 +958,7 @@ def selected_alpn_protocol(self):
else:
return self._sslobj.selected_alpn_protocol()
+ @_sslcopydoc
def cipher(self):
self._checkClosed()
if self._sslobj is None:
@@ -960,6 +966,7 @@ def cipher(self):
else:
return self._sslobj.cipher()
+ @_sslcopydoc
def shared_ciphers(self):
self._checkClosed()
if self._sslobj is None:
@@ -967,6 +974,7 @@ def shared_ciphers(self):
else:
return self._sslobj.shared_ciphers()
+ @_sslcopydoc
def compression(self):
self._checkClosed()
if self._sslobj is None:
@@ -1077,6 +1085,7 @@ def recvmsg_into(self, *args, **kwargs):
raise NotImplementedError("recvmsg_into not allowed on instances of "
"%s" % self.__class__)
+ @_sslcopydoc
def pending(self):
self._checkClosed()
if self._sslobj is not None:
@@ -1089,6 +1098,7 @@ def shutdown(self, how):
self._sslobj = None
super().shutdown(how)
+ @_sslcopydoc
def unwrap(self):
if self._sslobj:
s = self._sslobj.shutdown()
@@ -1097,6 +1107,7 @@ def unwrap(self):
else:
raise ValueError("No SSL wrapper around " + str(self))
+ @_sslcopydoc
def verify_client_post_handshake(self):
if self._sslobj:
return self._sslobj.verify_client_post_handshake()
@@ -1107,8 +1118,8 @@ def _real_close(self):
self._sslobj = None
super()._real_close()
+ @_sslcopydoc
def do_handshake(self, block=False):
- """Perform a TLS/SSL handshake."""
self._check_connected()
timeout = self.gettimeout()
try:
@@ -1166,11 +1177,8 @@ def accept(self):
server_side=True)
return newsock, addr
+ @_sslcopydoc
def get_channel_binding(self, cb_type="tls-unique"):
- """Get channel binding data for current connection. Raise ValueError
- if the requested `cb_type` is not supported. Return bytes of the data
- or None if the data is not available (e.g. before the handshake).
- """
if self._sslobj is not None:
return self._sslobj.get_channel_binding(cb_type)
else:
@@ -1180,11 +1188,8 @@ def get_channel_binding(self, cb_type="tls-unique"):
)
return None
+ @_sslcopydoc
def version(self):
- """
- Return a string identifying the protocol version used by the
- current SSL channel, or None if there is no established channel.
- """
if self._sslobj is not None:
return self._sslobj.version()
else:
From b16b4e45923f4e4dfd8e970ae4e6a934faf73b79 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Fri, 17 May 2019 15:20:52 +0200
Subject: [PATCH 088/199] bpo-36763: Add PyMemAllocatorName (GH-13387)
* Add PyMemAllocatorName enum
* _PyPreConfig.allocator type becomes PyMemAllocatorName, instead of
char*
* Remove _PyPreConfig_Clear()
* Add _PyMem_GetAllocatorName()
* Rename _PyMem_GetAllocatorsName() to
_PyMem_GetCurrentAllocatorName()
* Remove _PyPreConfig_SetAllocator(): just call
_PyMem_SetupAllocators() directly, we don't have do reallocate the
configuration with the new allocator anymore!
* _PyPreConfig_Write() parameter becomes const, as it should be in
the first place!
---
Include/cpython/coreconfig.h | 6 ++-
Include/cpython/pymem.h | 19 +++++--
Include/internal/pycore_coreconfig.h | 3 +-
Include/internal/pycore_pymem.h | 9 ++++
Lib/test/test_embed.py | 15 +++---
Modules/_testcapimodule.c | 2 +-
Objects/obmalloc.c | 73 +++++++++++++++++++++-----
Programs/_testembed.c | 2 +-
Python/coreconfig.c | 12 ++---
Python/preconfig.c | 76 +++++-----------------------
Python/pylifecycle.c | 12 ++---
Python/pystate.c | 2 -
12 files changed, 119 insertions(+), 112 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index 1ba2663c966..dca41341dfe 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -120,7 +120,9 @@ typedef struct {
int utf8_mode;
int dev_mode; /* Development mode. PYTHONDEVMODE, -X dev */
- char *allocator; /* Memory allocator: PYTHONMALLOC */
+
+ /* Memory allocator: PYTHONMALLOC env var */
+ PyMemAllocatorName allocator;
} _PyPreConfig;
#ifdef MS_WINDOWS
@@ -137,7 +139,7 @@ typedef struct {
.isolated = -1, \
.use_environment = -1, \
.dev_mode = -1, \
- .allocator = NULL}
+ .allocator = PYMEM_ALLOCATOR_NOT_SET}
/* --- _PyCoreConfig ---------------------------------------------- */
diff --git a/Include/cpython/pymem.h b/Include/cpython/pymem.h
index bd66506639a..79f063b1217 100644
--- a/Include/cpython/pymem.h
+++ b/Include/cpython/pymem.h
@@ -11,12 +11,8 @@ PyAPI_FUNC(void *) PyMem_RawCalloc(size_t nelem, size_t elsize);
PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size);
PyAPI_FUNC(void) PyMem_RawFree(void *ptr);
-/* Configure the Python memory allocators. Pass NULL to use default
- allocators. */
-PyAPI_FUNC(int) _PyMem_SetupAllocators(const char *opt);
-
/* Try to get the allocators name set by _PyMem_SetupAllocators(). */
-PyAPI_FUNC(const char*) _PyMem_GetAllocatorsName(void);
+PyAPI_FUNC(const char*) _PyMem_GetCurrentAllocatorName(void);
PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize);
@@ -41,6 +37,19 @@ typedef enum {
PYMEM_DOMAIN_OBJ
} PyMemAllocatorDomain;
+typedef enum {
+ PYMEM_ALLOCATOR_NOT_SET = 0,
+ PYMEM_ALLOCATOR_DEFAULT = 1,
+ PYMEM_ALLOCATOR_DEBUG = 2,
+ PYMEM_ALLOCATOR_MALLOC = 3,
+ PYMEM_ALLOCATOR_MALLOC_DEBUG = 4,
+#ifdef WITH_PYMALLOC
+ PYMEM_ALLOCATOR_PYMALLOC = 5,
+ PYMEM_ALLOCATOR_PYMALLOC_DEBUG = 6,
+#endif
+} PyMemAllocatorName;
+
+
typedef struct {
/* user context passed as the first argument to the 4 functions */
void *ctx;
diff --git a/Include/internal/pycore_coreconfig.h b/Include/internal/pycore_coreconfig.h
index d48904e482a..ccb7948ef4d 100644
--- a/Include/internal/pycore_coreconfig.h
+++ b/Include/internal/pycore_coreconfig.h
@@ -88,7 +88,6 @@ PyAPI_FUNC(_PyInitError) _PyPreCmdline_Read(_PyPreCmdline *cmdline,
/* --- _PyPreConfig ----------------------------------------------- */
-PyAPI_FUNC(void) _PyPreConfig_Clear(_PyPreConfig *config);
PyAPI_FUNC(int) _PyPreConfig_Copy(_PyPreConfig *config,
const _PyPreConfig *config2);
PyAPI_FUNC(PyObject*) _PyPreConfig_AsDict(const _PyPreConfig *config);
@@ -96,7 +95,7 @@ PyAPI_FUNC(void) _PyCoreConfig_GetCoreConfig(_PyPreConfig *config,
const _PyCoreConfig *core_config);
PyAPI_FUNC(_PyInitError) _PyPreConfig_Read(_PyPreConfig *config,
const _PyArgv *args);
-PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(_PyPreConfig *config);
+PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(const _PyPreConfig *config);
/* --- _PyCoreConfig ---------------------------------------------- */
diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h
index 20f3b5e4006..dcc492af017 100644
--- a/Include/internal/pycore_pymem.h
+++ b/Include/internal/pycore_pymem.h
@@ -179,6 +179,15 @@ static inline int _PyMem_IsPtrFreed(void *ptr)
#endif
}
+PyAPI_FUNC(int) _PyMem_GetAllocatorName(
+ const char *name,
+ PyMemAllocatorName *allocator);
+
+/* Configure the Python memory allocators.
+ Pass PYMEM_ALLOCATOR_DEFAULT to use default allocators.
+ PYMEM_ALLOCATOR_NOT_SET does nothing. */
+PyAPI_FUNC(int) _PyMem_SetupAllocators(PyMemAllocatorName allocator);
+
#ifdef __cplusplus
}
#endif
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 4012a389d75..92cc405859c 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -13,6 +13,9 @@
MS_WINDOWS = (os.name == 'nt')
+PYMEM_ALLOCATOR_NOT_SET = 0
+PYMEM_ALLOCATOR_DEBUG = 2
+PYMEM_ALLOCATOR_MALLOC = 3
class EmbeddingTestsMixin:
@@ -272,7 +275,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
# Mark config which should be get by get_default_config()
GET_DEFAULT_CONFIG = object()
DEFAULT_PRE_CONFIG = {
- 'allocator': None,
+ 'allocator': PYMEM_ALLOCATOR_NOT_SET,
'coerce_c_locale': 0,
'coerce_c_locale_warn': 0,
'utf8_mode': 0,
@@ -564,7 +567,7 @@ def test_init_global_config(self):
def test_init_from_config(self):
preconfig = {
- 'allocator': 'malloc',
+ 'allocator': PYMEM_ALLOCATOR_MALLOC,
'utf8_mode': 1,
}
config = {
@@ -608,7 +611,7 @@ def test_init_from_config(self):
self.check_config("init_from_config", config, preconfig)
INIT_ENV_PRECONFIG = {
- 'allocator': 'malloc',
+ 'allocator': PYMEM_ALLOCATOR_MALLOC,
}
INIT_ENV_CONFIG = {
'use_hash_seed': 1,
@@ -633,7 +636,7 @@ def test_init_env(self):
def test_init_env_dev_mode(self):
preconfig = dict(self.INIT_ENV_PRECONFIG,
- allocator='debug')
+ allocator=PYMEM_ALLOCATOR_DEBUG)
config = dict(self.INIT_ENV_CONFIG,
dev_mode=1,
warnoptions=['default'])
@@ -641,7 +644,7 @@ def test_init_env_dev_mode(self):
def test_init_env_dev_mode_alloc(self):
preconfig = dict(self.INIT_ENV_PRECONFIG,
- allocator='malloc')
+ allocator=PYMEM_ALLOCATOR_MALLOC)
config = dict(self.INIT_ENV_CONFIG,
dev_mode=1,
warnoptions=['default'])
@@ -649,7 +652,7 @@ def test_init_env_dev_mode_alloc(self):
def test_init_dev_mode(self):
preconfig = {
- 'allocator': 'debug',
+ 'allocator': PYMEM_ALLOCATOR_DEBUG,
}
config = {
'faulthandler': 1,
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 04d75ace6ec..59b42df279c 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -4297,7 +4297,7 @@ pymem_malloc_without_gil(PyObject *self, PyObject *args)
static PyObject*
test_pymem_getallocatorsname(PyObject *self, PyObject *args)
{
- const char *name = _PyMem_GetAllocatorsName();
+ const char *name = _PyMem_GetCurrentAllocatorName();
if (name == NULL) {
PyErr_SetString(PyExc_RuntimeError, "cannot get allocators name");
return NULL;
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index bd15bcf1363..f54856dcfe7 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -268,26 +268,65 @@ _PyMem_SetDefaultAllocator(PyMemAllocatorDomain domain,
int
-_PyMem_SetupAllocators(const char *opt)
+_PyMem_GetAllocatorName(const char *name, PyMemAllocatorName *allocator)
{
- if (opt == NULL || *opt == '\0') {
+ if (name == NULL || *name == '\0') {
/* PYTHONMALLOC is empty or is not set or ignored (-E/-I command line
- options): use default memory allocators */
- opt = "default";
+ nameions): use default memory allocators */
+ *allocator = PYMEM_ALLOCATOR_DEFAULT;
}
+ else if (strcmp(name, "default") == 0) {
+ *allocator = PYMEM_ALLOCATOR_DEFAULT;
+ }
+ else if (strcmp(name, "debug") == 0) {
+ *allocator = PYMEM_ALLOCATOR_DEBUG;
+ }
+#ifdef WITH_PYMALLOC
+ else if (strcmp(name, "pymalloc") == 0) {
+ *allocator = PYMEM_ALLOCATOR_PYMALLOC;
+ }
+ else if (strcmp(name, "pymalloc_debug") == 0) {
+ *allocator = PYMEM_ALLOCATOR_PYMALLOC_DEBUG;
+ }
+#endif
+ else if (strcmp(name, "malloc") == 0) {
+ *allocator = PYMEM_ALLOCATOR_MALLOC;
+ }
+ else if (strcmp(name, "malloc_debug") == 0) {
+ *allocator = PYMEM_ALLOCATOR_MALLOC_DEBUG;
+ }
+ else {
+ /* unknown allocator */
+ return -1;
+ }
+ return 0;
+}
- if (strcmp(opt, "default") == 0) {
+
+int
+_PyMem_SetupAllocators(PyMemAllocatorName allocator)
+{
+ switch (allocator) {
+ case PYMEM_ALLOCATOR_NOT_SET:
+ /* do nothing */
+ break;
+
+ case PYMEM_ALLOCATOR_DEFAULT:
(void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, NULL);
(void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_MEM, NULL);
(void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_OBJ, NULL);
- }
- else if (strcmp(opt, "debug") == 0) {
+ break;
+
+ case PYMEM_ALLOCATOR_DEBUG:
(void)pymem_set_default_allocator(PYMEM_DOMAIN_RAW, 1, NULL);
(void)pymem_set_default_allocator(PYMEM_DOMAIN_MEM, 1, NULL);
(void)pymem_set_default_allocator(PYMEM_DOMAIN_OBJ, 1, NULL);
- }
+ break;
+
#ifdef WITH_PYMALLOC
- else if (strcmp(opt, "pymalloc") == 0 || strcmp(opt, "pymalloc_debug") == 0) {
+ case PYMEM_ALLOCATOR_PYMALLOC:
+ case PYMEM_ALLOCATOR_PYMALLOC_DEBUG:
+ {
PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC;
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &malloc_alloc);
@@ -295,22 +334,28 @@ _PyMem_SetupAllocators(const char *opt)
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &pymalloc);
PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &pymalloc);
- if (strcmp(opt, "pymalloc_debug") == 0) {
+ if (allocator == PYMEM_ALLOCATOR_PYMALLOC_DEBUG) {
PyMem_SetupDebugHooks();
}
+ break;
}
#endif
- else if (strcmp(opt, "malloc") == 0 || strcmp(opt, "malloc_debug") == 0) {
+
+ case PYMEM_ALLOCATOR_MALLOC:
+ case PYMEM_ALLOCATOR_MALLOC_DEBUG:
+ {
PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC;
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &malloc_alloc);
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &malloc_alloc);
PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &malloc_alloc);
- if (strcmp(opt, "malloc_debug") == 0) {
+ if (allocator == PYMEM_ALLOCATOR_MALLOC_DEBUG) {
PyMem_SetupDebugHooks();
}
+ break;
}
- else {
+
+ default:
/* unknown allocator */
return -1;
}
@@ -326,7 +371,7 @@ pymemallocator_eq(PyMemAllocatorEx *a, PyMemAllocatorEx *b)
const char*
-_PyMem_GetAllocatorsName(void)
+_PyMem_GetCurrentAllocatorName(void)
{
PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC;
#ifdef WITH_PYMALLOC
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index b1b7c6e0ffc..3327c8ce663 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -379,7 +379,7 @@ static int test_init_from_config(void)
_PyPreConfig preconfig = _PyPreConfig_INIT;
putenv("PYTHONMALLOC=malloc_debug");
- preconfig.allocator = "malloc";
+ preconfig.allocator = PYMEM_ALLOCATOR_MALLOC;
putenv("PYTHONUTF8=0");
Py_UTF8Mode = 0;
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index c20ae2151c9..634891ed214 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -2021,26 +2021,22 @@ core_read_precmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
_PyPreConfig preconfig = _PyPreConfig_INIT;
if (_PyPreConfig_Copy(&preconfig, &_PyRuntime.preconfig) < 0) {
err = _Py_INIT_NO_MEMORY();
- goto done;
+ return err;
}
_PyCoreConfig_GetCoreConfig(&preconfig, config);
err = _PyPreCmdline_Read(precmdline, &preconfig);
if (_Py_INIT_FAILED(err)) {
- goto done;
+ return err;
}
if (_PyPreCmdline_SetCoreConfig(precmdline, config) < 0) {
err = _Py_INIT_NO_MEMORY();
- goto done;
+ return err;
}
- err = _Py_INIT_OK();
-
-done:
- _PyPreConfig_Clear(&preconfig);
- return err;
+ return _Py_INIT_OK();
}
diff --git a/Python/preconfig.c b/Python/preconfig.c
index 2d0ace5df29..2bbf8e6fb7f 100644
--- a/Python/preconfig.c
+++ b/Python/preconfig.c
@@ -260,19 +260,9 @@ _PyPreCmdline_Read(_PyPreCmdline *cmdline,
/* --- _PyPreConfig ----------------------------------------------- */
-void
-_PyPreConfig_Clear(_PyPreConfig *config)
-{
- PyMem_RawFree(config->allocator);
- config->allocator = NULL;
-}
-
-
int
_PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
{
- _PyPreConfig_Clear(config);
-
#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
#define COPY_STR_ATTR(ATTR) \
do { \
@@ -293,7 +283,7 @@ _PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
COPY_ATTR(legacy_windows_fs_encoding);
#endif
COPY_ATTR(utf8_mode);
- COPY_STR_ATTR(allocator);
+ COPY_ATTR(allocator);
#undef COPY_ATTR
#undef COPY_STR_ATTR
@@ -341,7 +331,7 @@ _PyPreConfig_AsDict(const _PyPreConfig *config)
SET_ITEM_INT(legacy_windows_fs_encoding);
#endif
SET_ITEM_INT(dev_mode);
- SET_ITEM_STR(allocator);
+ SET_ITEM_INT(allocator);
return dict;
fail:
@@ -616,25 +606,21 @@ preconfig_init_coerce_c_locale(_PyPreConfig *config)
static _PyInitError
preconfig_init_allocator(_PyPreConfig *config)
{
- if (config->allocator == NULL) {
+ if (config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
/* bpo-34247. The PYTHONMALLOC environment variable has the priority
over PYTHONDEV env var and "-X dev" command line option.
For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory
allocators to "malloc" (and not to "debug"). */
- const char *allocator = _Py_GetEnv(config->use_environment, "PYTHONMALLOC");
- if (allocator) {
- config->allocator = _PyMem_RawStrdup(allocator);
- if (config->allocator == NULL) {
- return _Py_INIT_NO_MEMORY();
+ const char *envvar = _Py_GetEnv(config->use_environment, "PYTHONMALLOC");
+ if (envvar) {
+ if (_PyMem_GetAllocatorName(envvar, &config->allocator) < 0) {
+ return _Py_INIT_ERR("PYTHONMALLOC: unknown allocator");
}
}
}
- if (config->dev_mode && config->allocator == NULL) {
- config->allocator = _PyMem_RawStrdup("debug");
- if (config->allocator == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
+ if (config->dev_mode && config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
+ config->allocator = PYMEM_ALLOCATOR_DEBUG;
}
return _Py_INIT_OK();
}
@@ -815,7 +801,6 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
setlocale(LC_CTYPE, init_ctype_locale);
PyMem_RawFree(init_ctype_locale);
}
- _PyPreConfig_Clear(&save_config);
Py_UTF8Mode = init_utf8_mode ;
#ifdef MS_WINDOWS
Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
@@ -825,40 +810,6 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
}
-static _PyInitError
-_PyPreConfig_SetAllocator(_PyPreConfig *config)
-{
- assert(!_PyRuntime.core_initialized);
-
- PyMemAllocatorEx old_alloc;
- PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
- if (_PyMem_SetupAllocators(config->allocator) < 0) {
- return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
- }
-
- /* Copy the pre-configuration with the new allocator */
- _PyPreConfig config2 = _PyPreConfig_INIT;
- if (_PyPreConfig_Copy(&config2, config) < 0) {
- _PyPreConfig_Clear(&config2);
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- return _Py_INIT_NO_MEMORY();
- }
-
- /* Free the old config and replace config with config2. Since config now
- owns the data, don't free config2. */
- PyMemAllocatorEx new_alloc;
- PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- _PyPreConfig_Clear(config);
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
-
- *config = config2;
-
- return _Py_INIT_OK();
-}
-
-
/* Write the pre-configuration:
- set the memory allocators
@@ -872,7 +823,7 @@ _PyPreConfig_SetAllocator(_PyPreConfig *config)
Do nothing if called after Py_Initialize(): ignore the new
pre-configuration. */
_PyInitError
-_PyPreConfig_Write(_PyPreConfig *config)
+_PyPreConfig_Write(const _PyPreConfig *config)
{
if (_PyRuntime.core_initialized) {
/* bpo-34008: Calling this functions after Py_Initialize() ignores
@@ -880,10 +831,9 @@ _PyPreConfig_Write(_PyPreConfig *config)
return _Py_INIT_OK();
}
- if (config->allocator != NULL) {
- _PyInitError err = _PyPreConfig_SetAllocator(config);
- if (_Py_INIT_FAILED(err)) {
- return err;
+ if (config->allocator != PYMEM_ALLOCATOR_NOT_SET) {
+ if (_PyMem_SetupAllocators(config->allocator) < 0) {
+ return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
}
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index e89152637fe..eecb439a11d 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -706,26 +706,22 @@ _Py_PreInitializeFromPyArgv(const _PyPreConfig *src_config, const _PyArgv *args)
if (src_config) {
if (_PyPreConfig_Copy(&config, src_config) < 0) {
err = _Py_INIT_NO_MEMORY();
- goto done;
+ return err;
}
}
err = _PyPreConfig_Read(&config, args);
if (_Py_INIT_FAILED(err)) {
- goto done;
+ return err;
}
err = _PyPreConfig_Write(&config);
if (_Py_INIT_FAILED(err)) {
- goto done;
+ return err;
}
runtime->pre_initialized = 1;
- err = _Py_INIT_OK();
-
-done:
- _PyPreConfig_Clear(&config);
- return err;
+ return _Py_INIT_OK();
}
diff --git a/Python/pystate.c b/Python/pystate.c
index 67315756ab7..8c906ce87ad 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -106,8 +106,6 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime)
runtime->xidregistry.mutex = NULL;
}
- _PyPreConfig_Clear(&runtime->preconfig);
-
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
}
From cab5d0741ee6adf2ae9ff5aaafe06b75b4b5bca3 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Fri, 17 May 2019 19:01:14 +0200
Subject: [PATCH 089/199] bpo-36763: Add _PyCoreConfig_InitPythonConfig()
(GH-13388)
Add new functions to get the Python interpreter behavior:
* _PyPreConfig_InitPythonConfig()
* _PyCoreConfig_InitPythonConfig()
Add new functions to get an isolated configuration:
* _PyPreConfig_InitIsolatedConfig()
* _PyCoreConfig_InitIsolatedConfig()
Replace _PyPreConfig_INIT and _PyCoreConfig_INIT with new functions
_PyPreConfig_Init() and _PyCoreConfig_Init().
_PyCoreConfig: set configure_c_stdio and parse_argv to 0 by default
to behave as Python 3.6 in the default configuration.
_PyCoreConfig_Read() no longer sets coerce_c_locale_warn to 1 if it's
equal to 0. coerce_c_locale_warn must now be set to -1 (ex: using
_PyCoreConfig_InitPythonConfig()) to enable C locale coercion
warning.
Add unit tests for _PyCoreConfig_InitPythonConfig()
and _PyCoreConfig_InitIsolatedConfig().
Changes:
* Rename _PyCoreConfig_GetCoreConfig() to _PyPreConfig_GetCoreConfig()
* Fix core_read_precmdline(): handle parse_argv=0
* Fix _Py_PreInitializeFromCoreConfig(): pass coreconfig.argv
to _Py_PreInitializeFromPyArgv(), except if parse_argv=0
---
Include/cpython/coreconfig.h | 32 ++++--
Include/internal/pycore_coreconfig.h | 7 +-
Lib/test/test_embed.py | 46 ++++++--
Modules/main.c | 19 ++--
Programs/_freeze_importlib.c | 3 +-
Programs/_testembed.c | 151 ++++++++++++++++++++++-----
Python/coreconfig.c | 79 ++++++++++++--
Python/frozenmain.c | 3 +-
Python/pathconfig.c | 3 +-
Python/preconfig.c | 78 ++++++++++----
Python/pylifecycle.c | 28 +++--
Python/pystate.c | 4 +-
12 files changed, 362 insertions(+), 91 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index dca41341dfe..7d561ceb3ee 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -86,12 +86,18 @@ typedef struct {
If it is equal to 1, LC_CTYPE locale is read to decide it it should be
coerced or not (ex: PYTHONCOERCECLOCALE=1). Internally, it is set to 2
- if the LC_CTYPE locale must be coerced. */
+ if the LC_CTYPE locale must be coerced.
+
+ Disable by default (set to 0). Set it to -1 to let Python decides if it
+ should be enabled or not. */
int coerce_c_locale;
/* Emit a warning if the LC_CTYPE locale is coerced?
- Disabled by default. Set to 1 by PYTHONCOERCECLOCALE=warn. */
+ Set to 1 by PYTHONCOERCECLOCALE=warn.
+
+ Disable by default (set to 0). Set it to -1 to let Python decides if it
+ should be enabled or not. */
int coerce_c_locale_warn;
#ifdef MS_WINDOWS
@@ -116,7 +122,10 @@ typedef struct {
Set to 0 by "-X utf8=0" and PYTHONUTF8=0.
If equals to -1, it is set to 1 if the LC_CTYPE locale is "C" or
- "POSIX", otherwise inherit Py_UTF8Mode value. */
+ "POSIX", otherwise it is set to 0.
+
+ If equals to -2, inherit Py_UTF8Mode value value (which is equal to 0
+ by default). */
int utf8_mode;
int dev_mode; /* Development mode. PYTHONDEVMODE, -X dev */
@@ -138,9 +147,14 @@ typedef struct {
._config_version = _Py_CONFIG_VERSION, \
.isolated = -1, \
.use_environment = -1, \
+ .utf8_mode = -2, \
.dev_mode = -1, \
.allocator = PYMEM_ALLOCATOR_NOT_SET}
+PyAPI_FUNC(void) _PyPreConfig_Init(_PyPreConfig *config);
+PyAPI_FUNC(void) _PyPreConfig_InitPythonConfig(_PyPreConfig *config);
+PyAPI_FUNC(void) _PyPreConfig_InitIsolateConfig(_PyPreConfig *config);
+
/* --- _PyCoreConfig ---------------------------------------------- */
@@ -213,8 +227,8 @@ typedef struct {
/* Command line arguments (sys.argv).
- By default, Python command line arguments are parsed and then stripped
- from argv. Set parse_argv to 0 to avoid that.
+ Set parse_argv to 1 to parse argv as Python command line arguments
+ and then strip Python arguments from argv.
If argv is empty, an empty string is added to ensure that sys.argv
always exists and is never empty. */
@@ -442,7 +456,7 @@ typedef struct {
.faulthandler = -1, \
.tracemalloc = -1, \
.use_module_search_paths = 0, \
- .parse_argv = 1, \
+ .parse_argv = 0, \
.site_import = -1, \
.bytes_warning = -1, \
.inspect = -1, \
@@ -453,7 +467,7 @@ typedef struct {
.verbose = -1, \
.quiet = -1, \
.user_site_directory = -1, \
- .configure_c_stdio = 1, \
+ .configure_c_stdio = 0, \
.buffered_stdio = -1, \
._install_importlib = 1, \
.check_hash_pycs_mode = NULL, \
@@ -461,6 +475,10 @@ typedef struct {
._init_main = 1}
/* Note: _PyCoreConfig_INIT sets other fields to 0/NULL */
+PyAPI_FUNC(void) _PyCoreConfig_Init(_PyCoreConfig *config);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPythonConfig(_PyCoreConfig *config);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitIsolateConfig(_PyCoreConfig *config);
+
#ifdef __cplusplus
}
#endif
diff --git a/Include/internal/pycore_coreconfig.h b/Include/internal/pycore_coreconfig.h
index ccb7948ef4d..e9c6d9fee81 100644
--- a/Include/internal/pycore_coreconfig.h
+++ b/Include/internal/pycore_coreconfig.h
@@ -88,10 +88,13 @@ PyAPI_FUNC(_PyInitError) _PyPreCmdline_Read(_PyPreCmdline *cmdline,
/* --- _PyPreConfig ----------------------------------------------- */
+PyAPI_FUNC(void) _PyPreConfig_Init(_PyPreConfig *config);
+PyAPI_FUNC(void) _PyPreConfig_InitPythonConfig(_PyPreConfig *config);
+PyAPI_FUNC(void) _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config);
PyAPI_FUNC(int) _PyPreConfig_Copy(_PyPreConfig *config,
const _PyPreConfig *config2);
PyAPI_FUNC(PyObject*) _PyPreConfig_AsDict(const _PyPreConfig *config);
-PyAPI_FUNC(void) _PyCoreConfig_GetCoreConfig(_PyPreConfig *config,
+PyAPI_FUNC(void) _PyPreConfig_GetCoreConfig(_PyPreConfig *config,
const _PyCoreConfig *core_config);
PyAPI_FUNC(_PyInitError) _PyPreConfig_Read(_PyPreConfig *config,
const _PyArgv *args);
@@ -101,6 +104,8 @@ PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(const _PyPreConfig *config);
/* --- _PyCoreConfig ---------------------------------------------- */
PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPythonConfig(_PyCoreConfig *config);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitIsolatedConfig(_PyCoreConfig *config);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Copy(
_PyCoreConfig *config,
const _PyCoreConfig *config2);
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 92cc405859c..50badd8e585 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -307,7 +307,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'pycache_prefix': None,
'program_name': GET_DEFAULT_CONFIG,
- 'parse_argv': 1,
+ 'parse_argv': 0,
'argv': [""],
'xoptions': [],
@@ -333,7 +333,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'verbose': 0,
'quiet': 0,
'user_site_directory': 1,
- 'configure_c_stdio': 1,
+ 'configure_c_stdio': 0,
'buffered_stdio': 1,
'stdio_encoding': GET_DEFAULT_CONFIG,
@@ -588,6 +588,7 @@ def test_init_from_config(self):
'pycache_prefix': 'conf_pycache_prefix',
'program_name': './conf_program_name',
'argv': ['-c', 'arg2'],
+ 'parse_argv': 1,
'xoptions': ['core_xoption1=3', 'core_xoption2=', 'core_xoption3'],
'warnoptions': ['error::ResourceWarning', 'default::BytesWarning'],
'run_command': 'pass\n',
@@ -600,7 +601,7 @@ def test_init_from_config(self):
'write_bytecode': 0,
'verbose': 1,
'quiet': 1,
- 'configure_c_stdio': 0,
+ 'configure_c_stdio': 1,
'buffered_stdio': 0,
'user_site_directory': 0,
'faulthandler': 1,
@@ -661,14 +662,14 @@ def test_init_dev_mode(self):
}
self.check_config("init_dev_mode", config, preconfig)
- def test_init_isolated(self):
+ def test_init_isolated_flag(self):
preconfig = {}
config = {
'isolated': 1,
'use_environment': 0,
'user_site_directory': 0,
}
- self.check_config("init_isolated", config, preconfig)
+ self.check_config("init_isolated_flag", config, preconfig)
def test_preinit_isolated1(self):
# _PyPreConfig.isolated=1, _PyCoreConfig.isolated not set
@@ -690,6 +691,25 @@ def test_preinit_isolated2(self):
}
self.check_config("preinit_isolated2", config, preconfig)
+ def test_init_isolated_config(self):
+ preconfig = {}
+ config = {
+ 'isolated': 1,
+ 'use_environment': 0,
+ 'user_site_directory': 0,
+ 'install_signal_handlers': 0,
+ 'pathconfig_warnings': 0,
+ }
+ self.check_config("init_isolated_config", config, preconfig)
+
+ def test_init_python_config(self):
+ preconfig = {}
+ config = {
+ 'configure_c_stdio': 1,
+ 'parse_argv': 1,
+ }
+ self.check_config("init_python_config", config, preconfig)
+
def test_init_read_set(self):
preconfig = {}
core_config = {
@@ -707,6 +727,7 @@ def test_init_run_main(self):
'argv': ['-c', 'arg2'],
'program_name': './python3',
'run_command': code + '\n',
+ 'parse_argv': 1,
}
self.check_config("init_run_main", core_config, preconfig)
@@ -718,15 +739,26 @@ def test_init_main(self):
'argv': ['-c', 'arg2'],
'program_name': './python3',
'run_command': code + '\n',
+ 'parse_argv': 1,
'_init_main': 0,
}
self.check_config("init_main", core_config, preconfig,
stderr="Run Python code before _Py_InitializeMain")
+ def test_init_parse_argv(self):
+ core_config = {
+ 'argv': ['-c', 'arg1', '-v', 'arg3'],
+ 'program_name': './argv0',
+ 'parse_argv': 1,
+ 'run_command': 'pass\n',
+ 'use_environment': 0,
+ }
+ self.check_config("init_parse_argv", core_config, {})
+
def test_init_dont_parse_argv(self):
core_config = {
- 'argv': ['-v', '-c', 'arg1', '-W', 'arg2'],
- 'parse_argv': 0,
+ 'argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'],
+ 'program_name': './argv0',
}
self.check_config("init_dont_parse_argv", core_config, {})
diff --git a/Modules/main.c b/Modules/main.c
index bb103c28a3e..72546a21cac 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -52,23 +52,28 @@ pymain_init(const _PyArgv *args)
fedisableexcept(FE_OVERFLOW);
#endif
- _PyPreConfig preconfig = _PyPreConfig_INIT;
- /* Set to -1 to enable them depending on the LC_CTYPE locale and the
- environment variables (PYTHONUTF8 and PYTHONCOERCECLOCALE) */
- preconfig.coerce_c_locale = -1;
- preconfig.utf8_mode = -1;
+ _PyPreConfig preconfig;
+ _PyPreConfig_InitPythonConfig(&preconfig);
err = _Py_PreInitializeFromPyArgv(&preconfig, args);
if (_Py_INIT_FAILED(err)) {
return err;
}
+ _PyCoreConfig config;
+ err = _PyCoreConfig_InitPythonConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
/* pass NULL as the config: config is read from command line arguments,
environment variables, configuration files */
if (args->use_bytes_argv) {
- return _Py_InitializeFromArgs(NULL, args->argc, args->bytes_argv);
+ return _Py_InitializeFromArgs(&config,
+ args->argc, args->bytes_argv);
}
else {
- return _Py_InitializeFromWideArgs(NULL, args->argc, args->wchar_argv);
+ return _Py_InitializeFromWideArgs(&config,
+ args->argc, args->wchar_argv);
}
}
diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c
index 8cbbe17cfaf..bc29297a6b9 100644
--- a/Programs/_freeze_importlib.c
+++ b/Programs/_freeze_importlib.c
@@ -76,7 +76,8 @@ main(int argc, char *argv[])
}
text[text_size] = '\0';
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
config.use_environment = 0;
config.user_site_directory = 0;
config.site_import = 0;
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 3327c8ce663..e6896966f53 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -291,7 +291,9 @@ static int test_initialize_twice(void)
static int test_initialize_pymain(void)
{
wchar_t *argv[] = {L"PYTHON", L"-c",
- L"import sys; print(f'Py_Main() after Py_Initialize: sys.argv={sys.argv}')",
+ (L"import sys; "
+ L"print(f'Py_Main() after Py_Initialize: "
+ L"sys.argv={sys.argv}')"),
L"arg2"};
_testembed_Py_Initialize();
@@ -376,7 +378,8 @@ static int test_init_from_config(void)
{
_PyInitError err;
- _PyPreConfig preconfig = _PyPreConfig_INIT;
+ _PyPreConfig preconfig;
+ _PyPreConfig_Init(&preconfig);
putenv("PYTHONMALLOC=malloc_debug");
preconfig.allocator = PYMEM_ALLOCATOR_MALLOC;
@@ -391,7 +394,8 @@ static int test_init_from_config(void)
}
/* Test _Py_InitializeFromConfig() */
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
config.install_signal_handlers = 0;
/* FIXME: test use_environment */
@@ -400,7 +404,7 @@ static int test_init_from_config(void)
config.use_hash_seed = 1;
config.hash_seed = 123;
- /* dev_mode=1 is tested in test_init_dev_mode() */
+ /* dev_mode=1 is tested in init_dev_mode() */
putenv("PYTHONFAULTHANDLER=");
config.faulthandler = 1;
@@ -432,6 +436,7 @@ static int test_init_from_config(void)
};
config.argv.length = Py_ARRAY_LENGTH(argv);
config.argv.items = argv;
+ config.parse_argv = 1;
static wchar_t* xoptions[3] = {
L"core_xoption1=3",
@@ -481,7 +486,7 @@ static int test_init_from_config(void)
Py_QuietFlag = 0;
config.quiet = 1;
- config.configure_c_stdio = 0;
+ config.configure_c_stdio = 1;
putenv("PYTHONUNBUFFERED=");
Py_UnbufferedStdioFlag = 0;
@@ -516,25 +521,26 @@ static int test_init_from_config(void)
}
-static int test_init_dont_parse_argv(void)
+static int test_init_parse_argv(int parse_argv)
{
_PyInitError err;
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
static wchar_t* argv[] = {
- L"-v",
+ L"./argv0",
+ L"-E",
L"-c",
+ L"pass",
L"arg1",
- L"-W",
- L"arg2",
+ L"-v",
+ L"arg3",
};
- config.program_name = L"./_testembed";
-
config.argv.length = Py_ARRAY_LENGTH(argv);
config.argv.items = argv;
- config.parse_argv = 0;
+ config.parse_argv = parse_argv;
err = _Py_InitializeFromConfig(&config);
if (_Py_INIT_FAILED(err)) {
@@ -546,6 +552,18 @@ static int test_init_dont_parse_argv(void)
}
+static int init_parse_argv(void)
+{
+ return test_init_parse_argv(1);
+}
+
+
+static int init_dont_parse_argv(void)
+{
+ return test_init_parse_argv(0);
+}
+
+
static void test_init_env_putenvs(void)
{
putenv("PYTHONHASHSEED=42");
@@ -619,12 +637,13 @@ static int test_init_env_dev_mode_alloc(void)
}
-static int test_init_isolated(void)
+static int init_isolated_flag(void)
{
_PyInitError err;
/* Test _PyCoreConfig.isolated=1 */
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
Py_IsolatedFlag = 0;
config.isolated = 1;
@@ -648,7 +667,8 @@ static int test_preinit_isolated1(void)
{
_PyInitError err;
- _PyPreConfig preconfig = _PyPreConfig_INIT;
+ _PyPreConfig preconfig;
+ _PyPreConfig_Init(&preconfig);
preconfig.isolated = 1;
err = _Py_PreInitialize(&preconfig);
@@ -656,7 +676,8 @@ static int test_preinit_isolated1(void)
_Py_ExitInitError(err);
}
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
config.program_name = L"./_testembed";
test_init_env_dev_mode_putenvs();
@@ -675,7 +696,8 @@ static int test_preinit_isolated2(void)
{
_PyInitError err;
- _PyPreConfig preconfig = _PyPreConfig_INIT;
+ _PyPreConfig preconfig;
+ _PyPreConfig_Init(&preconfig);
preconfig.isolated = 0;
err = _Py_PreInitialize(&preconfig);
@@ -684,7 +706,8 @@ static int test_preinit_isolated2(void)
}
/* Test _PyCoreConfig.isolated=1 */
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
Py_IsolatedFlag = 0;
config.isolated = 1;
@@ -703,9 +726,72 @@ static int test_preinit_isolated2(void)
}
-static int test_init_dev_mode(void)
+static int init_isolated_config(void)
{
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyInitError err;
+
+ _PyPreConfig preconfig;
+ _PyPreConfig_InitIsolatedConfig(&preconfig);
+
+ err = _Py_PreInitialize(&preconfig);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+
+ _PyPreConfig *rt_preconfig = &_PyRuntime.preconfig;
+ assert(rt_preconfig->isolated == 1);
+ assert(rt_preconfig->use_environment == 0);
+
+ _PyCoreConfig config;
+ err = _PyCoreConfig_InitIsolatedConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+ config.program_name = L"./_testembed";
+
+ err = _Py_InitializeFromConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+ dump_config();
+ Py_Finalize();
+ return 0;
+}
+
+
+static int init_python_config(void)
+{
+ _PyInitError err;
+
+ _PyPreConfig preconfig;
+ _PyPreConfig_InitPythonConfig(&preconfig);
+
+ err = _Py_PreInitialize(&preconfig);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+
+ _PyCoreConfig config;
+ err = _PyCoreConfig_InitPythonConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+ config.program_name = L"./_testembed";
+
+ err = _Py_InitializeFromConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+ dump_config();
+ Py_Finalize();
+ return 0;
+}
+
+
+static int init_dev_mode(void)
+{
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
putenv("PYTHONFAULTHANDLER=");
putenv("PYTHONMALLOC=");
config.dev_mode = 1;
@@ -723,7 +809,8 @@ static int test_init_dev_mode(void)
static int test_init_read_set(void)
{
_PyInitError err;
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
err = _PyCoreConfig_DecodeLocale(&config.program_name, "./init_read_set");
if (_Py_INIT_FAILED(err)) {
@@ -772,13 +859,15 @@ static void configure_init_main(_PyCoreConfig *config)
{
config->argv.length = Py_ARRAY_LENGTH(init_main_argv);
config->argv.items = init_main_argv;
+ config->parse_argv = 1;
config->program_name = L"./python3";
}
static int test_init_run_main(void)
{
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
configure_init_main(&config);
_PyInitError err = _Py_InitializeFromConfig(&config);
@@ -792,7 +881,8 @@ static int test_init_run_main(void)
static int test_init_main(void)
{
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
configure_init_main(&config);
config._init_main = 0;
@@ -821,7 +911,8 @@ static int test_init_main(void)
static int test_run_main(void)
{
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
wchar_t *argv[] = {L"python3", L"-c",
(L"import sys; "
@@ -829,6 +920,7 @@ static int test_run_main(void)
L"arg2"};
config.argv.length = Py_ARRAY_LENGTH(argv);
config.argv.items = argv;
+ config.parse_argv = 1;
config.program_name = L"./python3";
_PyInitError err = _Py_InitializeFromConfig(&config);
@@ -869,12 +961,15 @@ static struct TestCase TestCases[] = {
{ "init_default_config", test_init_default_config },
{ "init_global_config", test_init_global_config },
{ "init_from_config", test_init_from_config },
- { "init_dont_parse_argv", test_init_dont_parse_argv },
+ { "init_parse_argv", init_parse_argv },
+ { "init_dont_parse_argv", init_dont_parse_argv },
{ "init_env", test_init_env },
{ "init_env_dev_mode", test_init_env_dev_mode },
{ "init_env_dev_mode_alloc", test_init_env_dev_mode_alloc },
- { "init_dev_mode", test_init_dev_mode },
- { "init_isolated", test_init_isolated },
+ { "init_dev_mode", init_dev_mode },
+ { "init_isolated_flag", init_isolated_flag },
+ { "init_isolated_config", init_isolated_config },
+ { "init_python_config", init_python_config },
{ "preinit_isolated1", test_preinit_isolated1 },
{ "preinit_isolated2", test_preinit_isolated2 },
{ "init_read_set", test_init_read_set },
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index 634891ed214..2e8f4cf6f10 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -109,7 +109,7 @@ static const char usage_6[] =
/* UTF-8 mode (PEP 540): if equals to 1, use the UTF-8 encoding, and change
stdin and stdout error handler to "surrogateescape". It is equal to
-1 by default: unknown, will be set by Py_Main() */
-int Py_UTF8Mode = -1;
+int Py_UTF8Mode = 0;
int Py_DebugFlag = 0; /* Needed by parser.c */
int Py_VerboseFlag = 0; /* Needed by import.c */
int Py_QuietFlag = 0; /* Needed by sysmodule.c */
@@ -520,6 +520,61 @@ _PyCoreConfig_Clear(_PyCoreConfig *config)
}
+void
+_PyCoreConfig_Init(_PyCoreConfig *config)
+{
+ *config = _PyCoreConfig_INIT;
+}
+
+
+_PyInitError
+_PyCoreConfig_InitPythonConfig(_PyCoreConfig *config)
+{
+ _PyCoreConfig_Init(config);
+
+ config->configure_c_stdio = 1;
+ config->parse_argv = 1;
+
+ return _Py_INIT_OK();
+}
+
+
+_PyInitError
+_PyCoreConfig_InitIsolatedConfig(_PyCoreConfig *config)
+{
+ _PyCoreConfig_Init(config);
+
+ /* set to 1 */
+ config->isolated = 1;
+ config->site_import = 1;
+ config->write_bytecode = 1;
+ config->buffered_stdio = 1;
+
+ /* set to 0 */
+ config->use_environment = 0;
+ config->dev_mode = 0;
+ config->install_signal_handlers = 0;
+ config->use_hash_seed = 0;
+ config->faulthandler = 0;
+ config->tracemalloc = 0;
+ config->bytes_warning = 0;
+ config->inspect = 0;
+ config->interactive = 0;
+ config->optimization_level = 0;
+ config->parser_debug = 0;
+ config->verbose = 0;
+ config->quiet = 0;
+ config->user_site_directory = 0;
+ config->configure_c_stdio = 0;
+ config->pathconfig_warnings = 0;
+#ifdef MS_WINDOWS
+ config->legacy_windows_stdio = 0;
+#endif
+
+ return _Py_INIT_OK();
+}
+
+
/* Copy str into *config_str (duplicate the string) */
_PyInitError
_PyCoreConfig_SetString(wchar_t **config_str, const wchar_t *str)
@@ -2014,17 +2069,20 @@ core_read_precmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
{
_PyInitError err;
- if (_PyWstrList_Copy(&precmdline->argv, &config->argv) < 0) {
- return _Py_INIT_NO_MEMORY();
+ if (config->parse_argv) {
+ if (_PyWstrList_Copy(&precmdline->argv, &config->argv) < 0) {
+ return _Py_INIT_NO_MEMORY();
+ }
}
- _PyPreConfig preconfig = _PyPreConfig_INIT;
+ _PyPreConfig preconfig;
+ _PyPreConfig_Init(&preconfig);
if (_PyPreConfig_Copy(&preconfig, &_PyRuntime.preconfig) < 0) {
err = _Py_INIT_NO_MEMORY();
return err;
}
- _PyCoreConfig_GetCoreConfig(&preconfig, config);
+ _PyPreConfig_GetCoreConfig(&preconfig, config);
err = _PyPreCmdline_Read(precmdline, &preconfig);
if (_Py_INIT_FAILED(err)) {
@@ -2155,6 +2213,7 @@ _PyInitError
_PyCoreConfig_Read(_PyCoreConfig *config)
{
_PyInitError err;
+ _PyWstrList orig_argv = _PyWstrList_INIT;
err = _Py_PreInitializeFromCoreConfig(config, NULL);
if (_Py_INIT_FAILED(err)) {
@@ -2163,6 +2222,10 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
_PyCoreConfig_GetGlobalConfig(config);
+ if (_PyWstrList_Copy(&orig_argv, &config->argv) < 0) {
+ return _Py_INIT_NO_MEMORY();
+ }
+
_PyPreCmdline precmdline = _PyPreCmdline_INIT;
err = core_read_precmdline(config, &precmdline);
if (_Py_INIT_FAILED(err)) {
@@ -2185,10 +2248,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
goto done;
}
- /* precmdline.argv is a copy of config.argv which is modified
- by config_read_cmdline() */
- const _PyWstrList *argv = &precmdline.argv;
- if (_Py_SetArgcArgv(argv->length, argv->items) < 0) {
+ if (_Py_SetArgcArgv(orig_argv.length, orig_argv.items) < 0) {
err = _Py_INIT_NO_MEMORY();
goto done;
}
@@ -2249,6 +2309,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
err = _Py_INIT_OK();
done:
+ _PyWstrList_Clear(&orig_argv);
_PyPreCmdline_Clear(&precmdline);
return err;
}
diff --git a/Python/frozenmain.c b/Python/frozenmain.c
index f2499ef84cd..0175e42596b 100644
--- a/Python/frozenmain.c
+++ b/Python/frozenmain.c
@@ -39,7 +39,8 @@ Py_FrozenMain(int argc, char **argv)
}
}
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
config.pathconfig_warnings = 0; /* Suppress errors from getpath.c */
if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
diff --git a/Python/pathconfig.c b/Python/pathconfig.c
index 2fcb8160580..c8c69ebad6a 100644
--- a/Python/pathconfig.c
+++ b/Python/pathconfig.c
@@ -392,7 +392,8 @@ pathconfig_global_init(void)
}
_PyInitError err;
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
err = _PyCoreConfig_Read(&config);
if (_Py_INIT_FAILED(err)) {
diff --git a/Python/preconfig.c b/Python/preconfig.c
index 2bbf8e6fb7f..7814ee08a63 100644
--- a/Python/preconfig.c
+++ b/Python/preconfig.c
@@ -260,6 +260,42 @@ _PyPreCmdline_Read(_PyPreCmdline *cmdline,
/* --- _PyPreConfig ----------------------------------------------- */
+void
+_PyPreConfig_Init(_PyPreConfig *config)
+{
+ *config = _PyPreConfig_INIT;
+}
+
+
+void
+_PyPreConfig_InitPythonConfig(_PyPreConfig *config)
+{
+ _PyPreConfig_Init(config);
+
+ /* Set to -1 to enable C locale coercion (PEP 538) and UTF-8 Mode (PEP 540)
+ depending on the LC_CTYPE locale, PYTHONUTF8 and PYTHONCOERCECLOCALE
+ environment variables. */
+ config->coerce_c_locale = -1;
+ config->coerce_c_locale_warn = -1;
+ config->utf8_mode = -1;
+}
+
+
+void
+_PyPreConfig_InitIsolatedConfig(_PyPreConfig *config)
+{
+ _PyPreConfig_Init(config);
+
+ config->isolated = 1;
+ config->use_environment = 0;
+#ifdef MS_WINDOWS
+ config->legacy_windows_fs_encoding = 0;
+#endif
+ config->utf8_mode = 0;
+ config->dev_mode = 0;
+}
+
+
int
_PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
{
@@ -346,7 +382,7 @@ _PyPreConfig_AsDict(const _PyPreConfig *config)
void
-_PyCoreConfig_GetCoreConfig(_PyPreConfig *config,
+_PyPreConfig_GetCoreConfig(_PyPreConfig *config,
const _PyCoreConfig *core_config)
{
#define COPY_ATTR(ATTR) \
@@ -366,11 +402,11 @@ static void
_PyPreConfig_GetGlobalConfig(_PyPreConfig *config)
{
#define COPY_FLAG(ATTR, VALUE) \
- if (config->ATTR == -1) { \
+ if (config->ATTR < 0) { \
config->ATTR = VALUE; \
}
#define COPY_NOT_FLAG(ATTR, VALUE) \
- if (config->ATTR == -1) { \
+ if (config->ATTR < 0) { \
config->ATTR = !(VALUE); \
}
@@ -379,8 +415,8 @@ _PyPreConfig_GetGlobalConfig(_PyPreConfig *config)
#ifdef MS_WINDOWS
COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
#endif
- if (Py_UTF8Mode > 0) {
- config->utf8_mode = 1;
+ if (config->utf8_mode == -2) {
+ config->utf8_mode = Py_UTF8Mode;
}
#undef COPY_FLAG
@@ -392,11 +428,11 @@ static void
_PyPreConfig_SetGlobalConfig(const _PyPreConfig *config)
{
#define COPY_FLAG(ATTR, VAR) \
- if (config->ATTR != -1) { \
+ if (config->ATTR >= 0) { \
VAR = config->ATTR; \
}
#define COPY_NOT_FLAG(ATTR, VAR) \
- if (config->ATTR != -1) { \
+ if (config->ATTR >= 0) { \
VAR = !config->ATTR; \
}
@@ -575,7 +611,9 @@ preconfig_init_coerce_c_locale(_PyPreConfig *config)
}
}
else if (strcmp(env, "warn") == 0) {
- config->coerce_c_locale_warn = 1;
+ if (config->coerce_c_locale_warn < 0) {
+ config->coerce_c_locale_warn = 1;
+ }
}
else {
if (config->coerce_c_locale < 0) {
@@ -587,19 +625,19 @@ preconfig_init_coerce_c_locale(_PyPreConfig *config)
/* Test if coerce_c_locale equals to -1 or equals to 1:
PYTHONCOERCECLOCALE=1 doesn't imply that the C locale is always coerced.
It is only coerced if if the LC_CTYPE locale is "C". */
- if (config->coerce_c_locale == 0 || config->coerce_c_locale == 2) {
- return;
+ if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) {
+ /* The C locale enables the C locale coercion (PEP 538) */
+ if (_Py_LegacyLocaleDetected()) {
+ config->coerce_c_locale = 2;
+ }
+ else {
+ config->coerce_c_locale = 0;
+ }
}
- /* The C locale enables the C locale coercion (PEP 538) */
- if (_Py_LegacyLocaleDetected()) {
- config->coerce_c_locale = 2;
+ if (config->coerce_c_locale_warn < 0) {
+ config->coerce_c_locale_warn = 0;
}
- else {
- config->coerce_c_locale = 0;
- }
-
- assert(config->coerce_c_locale >= 0);
}
@@ -659,6 +697,7 @@ preconfig_read(_PyPreConfig *config, _PyPreCmdline *cmdline)
}
assert(config->coerce_c_locale >= 0);
+ assert(config->coerce_c_locale_warn >= 0);
#ifdef MS_WINDOWS
assert(config->legacy_windows_fs_encoding >= 0);
#endif
@@ -700,7 +739,8 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
}
/* Save the config to be able to restore it if encodings change */
- _PyPreConfig save_config = _PyPreConfig_INIT;
+ _PyPreConfig save_config;
+ _PyPreConfig_Init(&save_config);
if (_PyPreConfig_Copy(&save_config, config) < 0) {
return _Py_INIT_NO_MEMORY();
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index eecb439a11d..231706d2ab6 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -701,7 +701,8 @@ _Py_PreInitializeFromPyArgv(const _PyPreConfig *src_config, const _PyArgv *args)
return _Py_INIT_OK();
}
- _PyPreConfig config = _PyPreConfig_INIT;
+ _PyPreConfig config;
+ _PyPreConfig_Init(&config);
if (src_config) {
if (_PyPreConfig_Copy(&config, src_config) < 0) {
@@ -752,13 +753,22 @@ _PyInitError
_Py_PreInitializeFromCoreConfig(const _PyCoreConfig *coreconfig,
const _PyArgv *args)
{
- _PyPreConfig config = _PyPreConfig_INIT;
+ _PyPreConfig config;
+ _PyPreConfig_Init(&config);
if (coreconfig != NULL) {
- _PyCoreConfig_GetCoreConfig(&config, coreconfig);
+ _PyPreConfig_GetCoreConfig(&config, coreconfig);
+ }
+
+ if (args == NULL && coreconfig != NULL && coreconfig->parse_argv) {
+ _PyArgv config_args = {
+ .use_bytes_argv = 0,
+ .argc = coreconfig->argv.length,
+ .wchar_argv = coreconfig->argv.items};
+ return _Py_PreInitializeFromPyArgv(&config, &config_args);
+ }
+ else {
+ return _Py_PreInitializeFromPyArgv(&config, args);
}
- return _Py_PreInitializeFromPyArgv(&config, args);
- /* No need to clear config:
- _PyCoreConfig_GetCoreConfig() doesn't allocate memory */
}
@@ -829,7 +839,8 @@ _Py_InitializeCore(_PyRuntimeState *runtime,
return err;
}
- _PyCoreConfig local_config = _PyCoreConfig_INIT;
+ _PyCoreConfig local_config;
+ _PyCoreConfig_Init(&local_config);
err = pyinit_coreconfig(runtime, &local_config, src_config, args, interp_p);
_PyCoreConfig_Clear(&local_config);
return err;
@@ -1051,7 +1062,8 @@ Py_InitializeEx(int install_sigs)
return;
}
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_Init(&config);
config.install_signal_handlers = install_sigs;
err = _Py_InitializeFromConfig(&config);
diff --git a/Python/pystate.c b/Python/pystate.c
index 8c906ce87ad..2f80aa253b5 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -49,7 +49,7 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime)
_PyGC_Initialize(&runtime->gc);
_PyEval_Initialize(&runtime->ceval);
- runtime->preconfig = _PyPreConfig_INIT;
+ _PyPreConfig_Init(&runtime->preconfig);
runtime->gilstate.check_enabled = 1;
@@ -189,7 +189,7 @@ PyInterpreterState_New(void)
memset(interp, 0, sizeof(*interp));
interp->id_refcount = -1;
interp->check_interval = 100;
- interp->core_config = _PyCoreConfig_INIT;
+ _PyCoreConfig_Init(&interp->core_config);
interp->eval_frame = _PyEval_EvalFrameDefault;
#ifdef HAVE_DLOPEN
#if HAVE_DECL_RTLD_NOW
From f96e7fd9240c1ce13f52bd3ba81f58b2511d89c3 Mon Sep 17 00:00:00 2001
From: Paul Monson
Date: Fri, 17 May 2019 10:07:24 -0700
Subject: [PATCH 090/199] bpo-36941: Windows build changes for Windows ARM64
(GH-13365)
---
.gitignore | 1 +
PCbuild/_asyncio.vcxproj | 16 ++
PCbuild/_bz2.vcxproj | 16 ++
PCbuild/_ctypes.vcxproj | 16 ++
PCbuild/_ctypes_test.vcxproj | 16 ++
PCbuild/_decimal.vcxproj | 18 ++
PCbuild/_elementtree.vcxproj | 16 ++
PCbuild/_freeze_importlib.vcxproj | 16 ++
PCbuild/_hashlib.vcxproj | 16 ++
PCbuild/_lzma.vcxproj | 16 ++
PCbuild/_msi.vcxproj | 16 ++
PCbuild/_multiprocessing.vcxproj | 16 ++
PCbuild/_overlapped.vcxproj | 16 ++
PCbuild/_queue.vcxproj | 16 ++
PCbuild/_socket.vcxproj | 16 ++
PCbuild/_sqlite3.vcxproj | 16 ++
PCbuild/_ssl.vcxproj | 16 ++
PCbuild/_testbuffer.vcxproj | 16 ++
PCbuild/_testcapi.vcxproj | 16 ++
PCbuild/_testconsole.vcxproj | 16 ++
PCbuild/_testembed.vcxproj | 16 ++
PCbuild/_testimportmultiple.vcxproj | 16 ++
PCbuild/_testinternalcapi.vcxproj | 16 ++
PCbuild/_testmultiphase.vcxproj | 16 ++
PCbuild/_tkinter.vcxproj | 16 ++
PCbuild/build.bat | 6 +-
PCbuild/liblzma.vcxproj | 16 ++
PCbuild/pcbuild.proj | 6 +-
PCbuild/pcbuild.sln | 344 +++++++++++++++++++++++++++-
PCbuild/prepare_libffi.bat | 24 +-
PCbuild/pyexpat.vcxproj | 16 ++
PCbuild/pylauncher.vcxproj | 16 ++
PCbuild/pyproject.props | 1 +
PCbuild/pyshellext.vcxproj | 16 ++
PCbuild/python.props | 9 +
PCbuild/python.vcxproj | 18 +-
PCbuild/python3dll.vcxproj | 17 ++
PCbuild/pythoncore.vcxproj | 16 ++
PCbuild/pythonw.vcxproj | 16 ++
PCbuild/pywlauncher.vcxproj | 16 ++
PCbuild/select.vcxproj | 16 ++
PCbuild/sqlite3.vcxproj | 16 ++
PCbuild/unicodedata.vcxproj | 16 ++
PCbuild/venvlauncher.vcxproj | 16 ++
PCbuild/venvwlauncher.vcxproj | 16 ++
PCbuild/winsound.vcxproj | 16 ++
PCbuild/xxlimited.vcxproj | 16 ++
47 files changed, 1029 insertions(+), 7 deletions(-)
diff --git a/.gitignore b/.gitignore
index 9e60f5a2069..e3c58095792 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,6 +70,7 @@ PCbuild/*.VC.opendb
PCbuild/.vs/
PCbuild/amd64/
PCbuild/arm32/
+PCbuild/arm64/
PCbuild/obj/
PCbuild/win32/
.purify
diff --git a/PCbuild/_asyncio.vcxproj b/PCbuild/_asyncio.vcxproj
index 86590dd2a8c..ed1e1bc0a42 100644
--- a/PCbuild/_asyncio.vcxproj
+++ b/PCbuild/_asyncio.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_bz2.vcxproj b/PCbuild/_bz2.vcxproj
index 4d6683807d1..3fe95fbf839 100644
--- a/PCbuild/_bz2.vcxproj
+++ b/PCbuild/_bz2.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_ctypes.vcxproj b/PCbuild/_ctypes.vcxproj
index a265427a656..69e4271a9bd 100644
--- a/PCbuild/_ctypes.vcxproj
+++ b/PCbuild/_ctypes.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_ctypes_test.vcxproj b/PCbuild/_ctypes_test.vcxproj
index 97a45ebbb30..8a01e743a4d 100644
--- a/PCbuild/_ctypes_test.vcxproj
+++ b/PCbuild/_ctypes_test.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_decimal.vcxproj b/PCbuild/_decimal.vcxproj
index fa4bb8d0316..465a7ade9a0 100644
--- a/PCbuild/_decimal.vcxproj
+++ b/PCbuild/_decimal.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
@@ -80,6 +96,7 @@
_CRT_SECURE_NO_WARNINGS;MASM;%(PreprocessorDefinitions)CONFIG_32;PPRO;%(PreprocessorDefinitions)CONFIG_32;ANSI;%(PreprocessorDefinitions)
+ CONFIG_64;ANSI;%(PreprocessorDefinitions)CONFIG_64;%(PreprocessorDefinitions)..\Modules\_decimal;..\Modules\_decimal\libmpdec;%(AdditionalIncludeDirectories)
@@ -124,6 +141,7 @@
truetrue
+ trueml64 /nologo /c /Zi /Fo "$(IntDir)vcdiv64.obj" "%(FullPath)"$(IntDir)vcdiv64.obj;%(Outputs)
diff --git a/PCbuild/_elementtree.vcxproj b/PCbuild/_elementtree.vcxproj
index 46259913bc0..33a01732718 100644
--- a/PCbuild/_elementtree.vcxproj
+++ b/PCbuild/_elementtree.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_freeze_importlib.vcxproj b/PCbuild/_freeze_importlib.vcxproj
index 76885d8b354..a0fe49c464d 100644
--- a/PCbuild/_freeze_importlib.vcxproj
+++ b/PCbuild/_freeze_importlib.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_hashlib.vcxproj b/PCbuild/_hashlib.vcxproj
index 0f0223a5ff9..6dad8183c57 100644
--- a/PCbuild/_hashlib.vcxproj
+++ b/PCbuild/_hashlib.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_lzma.vcxproj b/PCbuild/_lzma.vcxproj
index 61fe6b7601b..fe076a6fc57 100644
--- a/PCbuild/_lzma.vcxproj
+++ b/PCbuild/_lzma.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_msi.vcxproj b/PCbuild/_msi.vcxproj
index 1362902d991..9f089ac7f52 100644
--- a/PCbuild/_msi.vcxproj
+++ b/PCbuild/_msi.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM4
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_multiprocessing.vcxproj b/PCbuild/_multiprocessing.vcxproj
index 0c8d06d1135..77b6bfc8e1e 100644
--- a/PCbuild/_multiprocessing.vcxproj
+++ b/PCbuild/_multiprocessing.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_overlapped.vcxproj b/PCbuild/_overlapped.vcxproj
index 66e976b216c..9e60d3b5db3 100644
--- a/PCbuild/_overlapped.vcxproj
+++ b/PCbuild/_overlapped.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_queue.vcxproj b/PCbuild/_queue.vcxproj
index 095de0aa459..8065b235851 100644
--- a/PCbuild/_queue.vcxproj
+++ b/PCbuild/_queue.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_socket.vcxproj b/PCbuild/_socket.vcxproj
index adeaf60b570..9498abf8fb5 100644
--- a/PCbuild/_socket.vcxproj
+++ b/PCbuild/_socket.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_sqlite3.vcxproj b/PCbuild/_sqlite3.vcxproj
index 558dc475045..7e0062692b8 100644
--- a/PCbuild/_sqlite3.vcxproj
+++ b/PCbuild/_sqlite3.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_ssl.vcxproj b/PCbuild/_ssl.vcxproj
index 522f80ab02f..4907f49b662 100644
--- a/PCbuild/_ssl.vcxproj
+++ b/PCbuild/_ssl.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_testbuffer.vcxproj b/PCbuild/_testbuffer.vcxproj
index 17f47e7134f..917d7ae50fe 100644
--- a/PCbuild/_testbuffer.vcxproj
+++ b/PCbuild/_testbuffer.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj
index 68149a9a5f0..c1a19437253 100644
--- a/PCbuild/_testcapi.vcxproj
+++ b/PCbuild/_testcapi.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_testconsole.vcxproj b/PCbuild/_testconsole.vcxproj
index c457e8e6bd2..5d7e14eff10 100644
--- a/PCbuild/_testconsole.vcxproj
+++ b/PCbuild/_testconsole.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_testembed.vcxproj b/PCbuild/_testembed.vcxproj
index 668acbe3647..a7ea8787e0c 100644
--- a/PCbuild/_testembed.vcxproj
+++ b/PCbuild/_testembed.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_testimportmultiple.vcxproj b/PCbuild/_testimportmultiple.vcxproj
index 5d825b39761..6d80d5779f2 100644
--- a/PCbuild/_testimportmultiple.vcxproj
+++ b/PCbuild/_testimportmultiple.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_testinternalcapi.vcxproj b/PCbuild/_testinternalcapi.vcxproj
index 116d193a39c..6c5b12cd40e 100644
--- a/PCbuild/_testinternalcapi.vcxproj
+++ b/PCbuild/_testinternalcapi.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_testmultiphase.vcxproj b/PCbuild/_testmultiphase.vcxproj
index 8a185435f36..430eb528cc3 100644
--- a/PCbuild/_testmultiphase.vcxproj
+++ b/PCbuild/_testmultiphase.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/_tkinter.vcxproj b/PCbuild/_tkinter.vcxproj
index 2e2a3ecb413..fdfa59648aa 100644
--- a/PCbuild/_tkinter.vcxproj
+++ b/PCbuild/_tkinter.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/build.bat b/PCbuild/build.bat
index cd0c07abbf3..6f0c85e4a45 100644
--- a/PCbuild/build.bat
+++ b/PCbuild/build.bat
@@ -35,13 +35,14 @@ echo. --test-marker Enable the test marker within the build.
echo.
echo.Available flags to avoid building certain modules.
echo.These flags have no effect if '-e' is not given:
+echo. --no-ctypes Do not attempt to build _ctypes
echo. --no-ssl Do not attempt to build _ssl
echo. --no-tkinter Do not attempt to build Tkinter
echo.
echo.Available arguments:
echo. -c Release ^| Debug ^| PGInstrument ^| PGUpdate
echo. Set the configuration (default: Release)
-echo. -p x64 ^| Win32 ^| ARM
+echo. -p x64 ^| Win32 ^| ARM ^| ARM64
echo. Set the platform (default: Win32)
echo. -t Build ^| Rebuild ^| Clean ^| CleanAll
echo. Set the target manually
@@ -81,10 +82,12 @@ rem them in through the environment, but we specify them on the command line
rem anyway for visibility so set defaults after this
if "%~1"=="-e" (set IncludeExternals=true) & shift & goto CheckOpts
if "%~1"=="-E" (set IncludeExternals=false) & shift & goto CheckOpts
+if "%~1"=="--no-ctypes" (set IncludeCTypes=false) & shift & goto CheckOpts
if "%~1"=="--no-ssl" (set IncludeSSL=false) & shift & goto CheckOpts
if "%~1"=="--no-tkinter" (set IncludeTkinter=false) & shift & goto CheckOpts
if "%IncludeExternals%"=="" set IncludeExternals=true
+if "%IncludeCTypes%"=="" set IncludeCTypes=true
if "%IncludeSSL%"=="" set IncludeSSL=true
if "%IncludeTkinter%"=="" set IncludeTkinter=true
@@ -139,6 +142,7 @@ echo on
%MSBUILD% "%dir%pcbuild.proj" /t:%target% %parallel% %verbose%^
/p:Configuration=%conf% /p:Platform=%platf%^
/p:IncludeExternals=%IncludeExternals%^
+ /p:IncludeCTypes=%IncludeCTypes%^
/p:IncludeSSL=%IncludeSSL% /p:IncludeTkinter=%IncludeTkinter%^
/p:UseTestMarker=%UseTestMarker% %GITProperty%^
%1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/PCbuild/liblzma.vcxproj b/PCbuild/liblzma.vcxproj
index c2a4a720d1f..9ec062e5255 100644
--- a/PCbuild/liblzma.vcxproj
+++ b/PCbuild/liblzma.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -21,6 +25,18 @@
ReleaseARM
+
+ PGInstrument
+ ARM64
+
+
+ PGUpdate
+ ARM64
+
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/pcbuild.proj b/PCbuild/pcbuild.proj
index d16ddef89f6..35f173ff864 100644
--- a/PCbuild/pcbuild.proj
+++ b/PCbuild/pcbuild.proj
@@ -7,6 +7,7 @@
truetruetrue
+ truetruetruefalse
@@ -50,7 +51,8 @@
-
+
+
@@ -70,7 +72,7 @@
-
+
diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln
index 66be9ac7a4a..dea6799a5e5 100644
--- a/PCbuild/pcbuild.sln
+++ b/PCbuild/pcbuild.sln
@@ -106,981 +106,1323 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
+ Debug|ARM64 = Debug|ARM64
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
PGInstrument|ARM = PGInstrument|ARM
+ PGInstrument|ARM64 = PGInstrument|ARM64
PGInstrument|Win32 = PGInstrument|Win32
PGInstrument|x64 = PGInstrument|x64
PGUpdate|ARM = PGUpdate|ARM
+ PGUpdate|ARM64 = PGUpdate|ARM64
PGUpdate|Win32 = PGUpdate|Win32
PGUpdate|x64 = PGUpdate|x64
Release|ARM = Release|ARM
+ Release|ARM64 = Release|ARM64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Debug|ARM.ActiveCfg = Debug|ARM
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Debug|ARM.Build.0 = Debug|ARM
+ {B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Debug|ARM64.Build.0 = Debug|ARM64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Debug|Win32.ActiveCfg = Debug|Win32
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Debug|Win32.Build.0 = Debug|Win32
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Debug|x64.ActiveCfg = Debug|x64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Debug|x64.Build.0 = Debug|x64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGInstrument|x64.Build.0 = PGInstrument|x64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.PGUpdate|x64.Build.0 = PGUpdate|x64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Release|ARM.ActiveCfg = Release|ARM
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Release|ARM.Build.0 = Release|ARM
+ {B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Release|ARM64.ActiveCfg = Release|ARM64
+ {B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Release|ARM64.Build.0 = Release|ARM64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Release|Win32.ActiveCfg = Release|Win32
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Release|Win32.Build.0 = Release|Win32
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Release|x64.ActiveCfg = Release|x64
{B11D750F-CD1F-4A96-85CE-E69A5C5259F9}.Release|x64.Build.0 = Release|x64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Debug|ARM.ActiveCfg = Debug|ARM
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Debug|ARM.Build.0 = Debug|ARM
+ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Debug|ARM64.Build.0 = Debug|ARM64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Debug|Win32.ActiveCfg = Debug|Win32
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Debug|Win32.Build.0 = Debug|Win32
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Debug|x64.ActiveCfg = Debug|x64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Debug|x64.Build.0 = Debug|x64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGInstrument|x64.Build.0 = PGInstrument|x64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.PGUpdate|x64.Build.0 = PGUpdate|x64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Release|ARM.ActiveCfg = Release|ARM
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Release|ARM.Build.0 = Release|ARM
+ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Release|ARM64.ActiveCfg = Release|ARM64
+ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Release|ARM64.Build.0 = Release|ARM64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Release|Win32.ActiveCfg = Release|Win32
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Release|Win32.Build.0 = Release|Win32
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Release|x64.ActiveCfg = Release|x64
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}.Release|x64.Build.0 = Release|x64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|ARM.ActiveCfg = Debug|ARM
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|ARM.Build.0 = Debug|ARM
+ {F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|ARM64.Build.0 = Debug|ARM64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|Win32.ActiveCfg = Debug|Win32
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|Win32.Build.0 = Debug|Win32
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|x64.ActiveCfg = Debug|x64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|x64.Build.0 = Debug|x64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|Win32.ActiveCfg = Release|Win32
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|Win32.Build.0 = Release|Win32
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|x64.ActiveCfg = Release|x64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|x64.Build.0 = Release|x64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGUpdate|Win32.ActiveCfg = Release|Win32
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGUpdate|Win32.Build.0 = Release|Win32
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGUpdate|x64.ActiveCfg = Release|x64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGUpdate|x64.Build.0 = Release|x64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Release|ARM.ActiveCfg = Release|ARM
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Release|ARM.Build.0 = Release|ARM
+ {F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Release|ARM64.Build.0 = Release|ARM64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Release|Win32.ActiveCfg = Release|Win32
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Release|Win32.Build.0 = Release|Win32
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Release|x64.ActiveCfg = Release|x64
{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Release|x64.Build.0 = Release|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|ARM.ActiveCfg = Debug|ARM
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|ARM.Build.0 = Debug|ARM
+ {28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|ARM64.Build.0 = Debug|ARM64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|Win32.ActiveCfg = Debug|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|Win32.Build.0 = Debug|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|x64.ActiveCfg = Debug|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|x64.Build.0 = Debug|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|x64.Build.0 = PGInstrument|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {28B5D777-DDF2-4B6B-B34F-31D938813856}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {28B5D777-DDF2-4B6B-B34F-31D938813856}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGUpdate|x64.Build.0 = PGUpdate|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|ARM.ActiveCfg = Release|ARM
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|ARM.Build.0 = Release|ARM
+ {28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|ARM64.ActiveCfg = Release|ARM64
+ {28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|ARM64.Build.0 = Release|ARM64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|Win32.ActiveCfg = Release|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|Win32.Build.0 = Release|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.ActiveCfg = Release|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.Build.0 = Release|x64
{0E9791DB-593A-465F-98BC-681011311617}.Debug|ARM.ActiveCfg = Debug|ARM
{0E9791DB-593A-465F-98BC-681011311617}.Debug|ARM.Build.0 = Debug|ARM
+ {0E9791DB-593A-465F-98BC-681011311617}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {0E9791DB-593A-465F-98BC-681011311617}.Debug|ARM64.Build.0 = Debug|ARM64
{0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.ActiveCfg = Debug|Win32
{0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.Build.0 = Debug|Win32
{0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.ActiveCfg = Debug|x64
{0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.Build.0 = Debug|x64
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.Build.0 = PGInstrument|x64
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.Build.0 = PGUpdate|x64
{0E9791DB-593A-465F-98BC-681011311617}.Release|ARM.ActiveCfg = Release|ARM
{0E9791DB-593A-465F-98BC-681011311617}.Release|ARM.Build.0 = Release|ARM
+ {0E9791DB-593A-465F-98BC-681011311617}.Release|ARM64.ActiveCfg = Release|ARM64
+ {0E9791DB-593A-465F-98BC-681011311617}.Release|ARM64.Build.0 = Release|ARM64
{0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.ActiveCfg = Release|Win32
{0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.Build.0 = Release|Win32
{0E9791DB-593A-465F-98BC-681011311617}.Release|x64.ActiveCfg = Release|x64
{0E9791DB-593A-465F-98BC-681011311617}.Release|x64.Build.0 = Release|x64
{0E9791DB-593A-465F-98BC-681011311618}.Debug|ARM.ActiveCfg = Debug|ARM
{0E9791DB-593A-465F-98BC-681011311618}.Debug|ARM.Build.0 = Debug|ARM
+ {0E9791DB-593A-465F-98BC-681011311618}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {0E9791DB-593A-465F-98BC-681011311618}.Debug|ARM64.Build.0 = Debug|ARM64
{0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.ActiveCfg = Debug|Win32
{0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.Build.0 = Debug|Win32
{0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.ActiveCfg = Debug|x64
{0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.Build.0 = Debug|x64
{0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|x64.Build.0 = PGInstrument|x64
{0E9791DB-593A-465F-98BC-681011311618}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{0E9791DB-593A-465F-98BC-681011311618}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {0E9791DB-593A-465F-98BC-681011311618}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {0E9791DB-593A-465F-98BC-681011311618}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{0E9791DB-593A-465F-98BC-681011311618}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{0E9791DB-593A-465F-98BC-681011311618}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{0E9791DB-593A-465F-98BC-681011311618}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{0E9791DB-593A-465F-98BC-681011311618}.PGUpdate|x64.Build.0 = PGUpdate|x64
{0E9791DB-593A-465F-98BC-681011311618}.Release|ARM.ActiveCfg = Release|ARM
{0E9791DB-593A-465F-98BC-681011311618}.Release|ARM.Build.0 = Release|ARM
+ {0E9791DB-593A-465F-98BC-681011311618}.Release|ARM64.ActiveCfg = Release|ARM64
+ {0E9791DB-593A-465F-98BC-681011311618}.Release|ARM64.Build.0 = Release|ARM64
{0E9791DB-593A-465F-98BC-681011311618}.Release|Win32.ActiveCfg = Release|Win32
{0E9791DB-593A-465F-98BC-681011311618}.Release|Win32.Build.0 = Release|Win32
{0E9791DB-593A-465F-98BC-681011311618}.Release|x64.ActiveCfg = Release|x64
{0E9791DB-593A-465F-98BC-681011311618}.Release|x64.Build.0 = Release|x64
{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|ARM.ActiveCfg = Debug|ARM
{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|ARM.Build.0 = Debug|ARM
+ {9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|ARM64.Build.0 = Debug|ARM64
{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|Win32.ActiveCfg = Debug|Win32
{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|Win32.Build.0 = Debug|Win32
{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|x64.ActiveCfg = Debug|x64
{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|x64.Build.0 = Debug|x64
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|Win32.ActiveCfg = Release|Win32
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|Win32.Build.0 = Release|Win32
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|x64.ActiveCfg = Release|x64
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|x64.Build.0 = Release|x64
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {9EC7190A-249F-4180-A900-548FDCF3055F}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {9EC7190A-249F-4180-A900-548FDCF3055F}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGUpdate|Win32.ActiveCfg = Release|Win32
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGUpdate|Win32.Build.0 = Release|Win32
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGUpdate|x64.ActiveCfg = Release|x64
{9EC7190A-249F-4180-A900-548FDCF3055F}.PGUpdate|x64.Build.0 = Release|x64
{9EC7190A-249F-4180-A900-548FDCF3055F}.Release|ARM.ActiveCfg = Release|ARM
{9EC7190A-249F-4180-A900-548FDCF3055F}.Release|ARM.Build.0 = Release|ARM
+ {9EC7190A-249F-4180-A900-548FDCF3055F}.Release|ARM64.ActiveCfg = Release|ARM64
+ {9EC7190A-249F-4180-A900-548FDCF3055F}.Release|ARM64.Build.0 = Release|ARM64
{9EC7190A-249F-4180-A900-548FDCF3055F}.Release|Win32.ActiveCfg = Release|Win32
{9EC7190A-249F-4180-A900-548FDCF3055F}.Release|Win32.Build.0 = Release|Win32
{9EC7190A-249F-4180-A900-548FDCF3055F}.Release|x64.ActiveCfg = Release|x64
{9EC7190A-249F-4180-A900-548FDCF3055F}.Release|x64.Build.0 = Release|x64
{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|ARM.ActiveCfg = Debug|ARM
{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|ARM.Build.0 = Debug|ARM
+ {17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|ARM64.Build.0 = Debug|ARM64
{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|Win32.ActiveCfg = Debug|Win32
{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|Win32.Build.0 = Debug|Win32
{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|x64.ActiveCfg = Debug|x64
{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|x64.Build.0 = Debug|x64
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|x64.Build.0 = PGInstrument|x64
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {17E1E049-C309-4D79-843F-AE483C264AEA}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {17E1E049-C309-4D79-843F-AE483C264AEA}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{17E1E049-C309-4D79-843F-AE483C264AEA}.PGUpdate|x64.Build.0 = PGUpdate|x64
{17E1E049-C309-4D79-843F-AE483C264AEA}.Release|ARM.ActiveCfg = Release|ARM
{17E1E049-C309-4D79-843F-AE483C264AEA}.Release|ARM.Build.0 = Release|ARM
+ {17E1E049-C309-4D79-843F-AE483C264AEA}.Release|ARM64.ActiveCfg = Release|ARM64
+ {17E1E049-C309-4D79-843F-AE483C264AEA}.Release|ARM64.Build.0 = Release|ARM64
{17E1E049-C309-4D79-843F-AE483C264AEA}.Release|Win32.ActiveCfg = Release|Win32
{17E1E049-C309-4D79-843F-AE483C264AEA}.Release|Win32.Build.0 = Release|Win32
{17E1E049-C309-4D79-843F-AE483C264AEA}.Release|x64.ActiveCfg = Release|x64
{17E1E049-C309-4D79-843F-AE483C264AEA}.Release|x64.Build.0 = Release|x64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|ARM.ActiveCfg = Debug|ARM
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|ARM.Build.0 = Debug|ARM
+ {31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|ARM64.Build.0 = Debug|ARM64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|Win32.ActiveCfg = Debug|Win32
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|Win32.Build.0 = Debug|Win32
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|x64.ActiveCfg = Debug|x64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|x64.Build.0 = Debug|x64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|x64.Build.0 = PGInstrument|x64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGUpdate|x64.Build.0 = PGUpdate|x64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Release|ARM.ActiveCfg = Release|ARM
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Release|ARM.Build.0 = Release|ARM
+ {31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Release|ARM64.ActiveCfg = Release|ARM64
+ {31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Release|ARM64.Build.0 = Release|ARM64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Release|Win32.ActiveCfg = Release|Win32
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Release|Win32.Build.0 = Release|Win32
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Release|x64.ActiveCfg = Release|x64
{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Release|x64.Build.0 = Release|x64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Debug|ARM.ActiveCfg = Debug|ARM
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Debug|ARM.Build.0 = Debug|ARM
+ {86937F53-C189-40EF-8CE8-8759D8E7D480}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {86937F53-C189-40EF-8CE8-8759D8E7D480}.Debug|ARM64.Build.0 = Debug|ARM64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Debug|Win32.ActiveCfg = Debug|Win32
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Debug|Win32.Build.0 = Debug|Win32
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Debug|x64.ActiveCfg = Debug|x64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Debug|x64.Build.0 = Debug|x64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {86937F53-C189-40EF-8CE8-8759D8E7D480}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {86937F53-C189-40EF-8CE8-8759D8E7D480}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGInstrument|x64.Build.0 = PGInstrument|x64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {86937F53-C189-40EF-8CE8-8759D8E7D480}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {86937F53-C189-40EF-8CE8-8759D8E7D480}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.PGUpdate|x64.Build.0 = PGUpdate|x64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Release|ARM.ActiveCfg = Release|ARM
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Release|ARM.Build.0 = Release|ARM
+ {86937F53-C189-40EF-8CE8-8759D8E7D480}.Release|ARM64.ActiveCfg = Release|ARM64
+ {86937F53-C189-40EF-8CE8-8759D8E7D480}.Release|ARM64.Build.0 = Release|ARM64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Release|Win32.ActiveCfg = Release|Win32
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Release|Win32.Build.0 = Release|Win32
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Release|x64.ActiveCfg = Release|x64
{86937F53-C189-40EF-8CE8-8759D8E7D480}.Release|x64.Build.0 = Release|x64
{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|ARM.ActiveCfg = Debug|ARM
{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|ARM.Build.0 = Debug|ARM
+ {13CECB97-4119-4316-9D42-8534019A5A44}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {13CECB97-4119-4316-9D42-8534019A5A44}.Debug|ARM64.Build.0 = Debug|ARM64
{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|Win32.ActiveCfg = Debug|Win32
{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|Win32.Build.0 = Debug|Win32
{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|x64.ActiveCfg = Debug|x64
{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|x64.Build.0 = Debug|x64
{13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|x64.Build.0 = PGInstrument|x64
{13CECB97-4119-4316-9D42-8534019A5A44}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{13CECB97-4119-4316-9D42-8534019A5A44}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {13CECB97-4119-4316-9D42-8534019A5A44}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {13CECB97-4119-4316-9D42-8534019A5A44}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{13CECB97-4119-4316-9D42-8534019A5A44}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{13CECB97-4119-4316-9D42-8534019A5A44}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{13CECB97-4119-4316-9D42-8534019A5A44}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{13CECB97-4119-4316-9D42-8534019A5A44}.PGUpdate|x64.Build.0 = PGUpdate|x64
{13CECB97-4119-4316-9D42-8534019A5A44}.Release|ARM.ActiveCfg = Release|ARM
{13CECB97-4119-4316-9D42-8534019A5A44}.Release|ARM.Build.0 = Release|ARM
+ {13CECB97-4119-4316-9D42-8534019A5A44}.Release|ARM64.ActiveCfg = Release|ARM64
+ {13CECB97-4119-4316-9D42-8534019A5A44}.Release|ARM64.Build.0 = Release|ARM64
{13CECB97-4119-4316-9D42-8534019A5A44}.Release|Win32.ActiveCfg = Release|Win32
{13CECB97-4119-4316-9D42-8534019A5A44}.Release|Win32.Build.0 = Release|Win32
{13CECB97-4119-4316-9D42-8534019A5A44}.Release|x64.ActiveCfg = Release|x64
{13CECB97-4119-4316-9D42-8534019A5A44}.Release|x64.Build.0 = Release|x64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|ARM.ActiveCfg = Debug|ARM
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|ARM.Build.0 = Debug|ARM
+ {C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|ARM64.ActiveCfg = Debug|ARM64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|Win32.ActiveCfg = Debug|Win32
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|Win32.Build.0 = Debug|Win32
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|x64.ActiveCfg = Debug|x64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|x64.Build.0 = Debug|x64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|x64.Build.0 = PGInstrument|x64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {C6E20F84-3247-4AD6-B051-B073268F73BA}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {C6E20F84-3247-4AD6-B051-B073268F73BA}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGUpdate|x64.Build.0 = PGUpdate|x64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Release|ARM.ActiveCfg = Release|ARM
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Release|ARM.Build.0 = Release|ARM
+ {C6E20F84-3247-4AD6-B051-B073268F73BA}.Release|ARM64.ActiveCfg = Release|ARM64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Release|Win32.ActiveCfg = Release|Win32
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Release|Win32.Build.0 = Release|Win32
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Release|x64.ActiveCfg = Release|x64
{C6E20F84-3247-4AD6-B051-B073268F73BA}.Release|x64.Build.0 = Release|x64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|ARM.ActiveCfg = Debug|ARM
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|ARM.Build.0 = Debug|ARM
+ {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|ARM64.Build.0 = Debug|ARM64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|Win32.ActiveCfg = Debug|Win32
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|Win32.Build.0 = Debug|Win32
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|x64.ActiveCfg = Debug|x64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|x64.Build.0 = Debug|x64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|x64.Build.0 = PGInstrument|x64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGUpdate|x64.Build.0 = PGUpdate|x64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|ARM.ActiveCfg = Release|ARM
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|ARM.Build.0 = Release|ARM
+ {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|ARM64.Build.0 = Release|ARM64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|Win32.ActiveCfg = Release|Win32
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|Win32.Build.0 = Release|Win32
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|x64.ActiveCfg = Release|x64
{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|x64.Build.0 = Release|x64
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|ARM.ActiveCfg = Debug|ARM
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|ARM.Build.0 = Debug|ARM
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|ARM64.ActiveCfg = Debug|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|Win32.Build.0 = Debug|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|x64.ActiveCfg = Debug|x64
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|x64.Build.0 = Debug|x64
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGInstrument|ARM64.ActiveCfg = PGInstrument|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGInstrument|x64.Build.0 = PGInstrument|x64
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGUpdate|ARM64.ActiveCfg = PGUpdate|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.PGUpdate|x64.Build.0 = PGUpdate|x64
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Release|ARM.ActiveCfg = Release|ARM
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Release|ARM.Build.0 = Release|ARM
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Release|ARM64.ActiveCfg = Release|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Release|Win32.ActiveCfg = Release|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Release|Win32.Build.0 = Release|Win32
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Release|x64.ActiveCfg = Release|x64
+ {900342D7-516A-4469-B1AD-59A66E49A25F}.Release|x64.Build.0 = Release|x64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|ARM.ActiveCfg = Debug|ARM
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|ARM.Build.0 = Debug|ARM
+ {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|ARM64.Build.0 = Debug|ARM64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|Win32.ActiveCfg = Debug|Win32
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|Win32.Build.0 = Debug|Win32
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|x64.ActiveCfg = Debug|x64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|x64.Build.0 = Debug|x64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|Win32.ActiveCfg = Release|Win32
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|Win32.Build.0 = Release|Win32
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|x64.ActiveCfg = Release|x64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|x64.Build.0 = Release|x64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|Win32.ActiveCfg = Release|Win32
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|Win32.Build.0 = Release|Win32
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|x64.ActiveCfg = Release|x64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGUpdate|x64.Build.0 = Release|x64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|ARM.ActiveCfg = Release|ARM
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|ARM.Build.0 = Release|ARM
+ {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|ARM64.ActiveCfg = Release|ARM64
+ {36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|ARM64.Build.0 = Release|ARM64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|Win32.ActiveCfg = Release|Win32
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|Win32.Build.0 = Release|Win32
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|x64.ActiveCfg = Release|x64
{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Release|x64.Build.0 = Release|x64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|ARM.ActiveCfg = Debug|ARM
+ {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|ARM64.ActiveCfg = Debug|ARM64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|Win32.ActiveCfg = Debug|Win32
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|Win32.Build.0 = Debug|Win32
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|x64.ActiveCfg = Debug|x64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|x64.Build.0 = Debug|x64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|x64.Build.0 = PGInstrument|x64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGUpdate|x64.Build.0 = PGUpdate|x64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Release|ARM.ActiveCfg = Release|ARM
+ {4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Release|ARM64.ActiveCfg = Release|ARM64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Release|Win32.ActiveCfg = Release|Win32
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Release|Win32.Build.0 = Release|Win32
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Release|x64.ActiveCfg = Release|x64
{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Release|x64.Build.0 = Release|x64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|ARM.ActiveCfg = Debug|ARM
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|ARM.Build.0 = Debug|ARM
+ {73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|ARM64.Build.0 = Debug|ARM64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|Win32.ActiveCfg = Debug|Win32
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|Win32.Build.0 = Debug|Win32
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|x64.ActiveCfg = Debug|x64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|x64.Build.0 = Debug|x64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|x64.Build.0 = PGInstrument|x64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGUpdate|x64.Build.0 = PGUpdate|x64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Release|ARM.ActiveCfg = Release|ARM
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Release|ARM.Build.0 = Release|ARM
+ {73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Release|ARM64.ActiveCfg = Release|ARM64
+ {73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Release|ARM64.Build.0 = Release|ARM64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Release|Win32.ActiveCfg = Release|Win32
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Release|Win32.Build.0 = Release|Win32
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Release|x64.ActiveCfg = Release|x64
{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Release|x64.Build.0 = Release|x64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|ARM.ActiveCfg = Debug|ARM
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|ARM.Build.0 = Debug|ARM
+ {18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|ARM64.Build.0 = Debug|ARM64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|Win32.ActiveCfg = Debug|Win32
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|Win32.Build.0 = Debug|Win32
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|x64.ActiveCfg = Debug|x64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|x64.Build.0 = Debug|x64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|x64.Build.0 = PGInstrument|x64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {18CAE28C-B454-46C1-87A0-493D91D97F03}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {18CAE28C-B454-46C1-87A0-493D91D97F03}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGUpdate|x64.Build.0 = PGUpdate|x64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Release|ARM.ActiveCfg = Release|ARM
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Release|ARM.Build.0 = Release|ARM
+ {18CAE28C-B454-46C1-87A0-493D91D97F03}.Release|ARM64.ActiveCfg = Release|ARM64
+ {18CAE28C-B454-46C1-87A0-493D91D97F03}.Release|ARM64.Build.0 = Release|ARM64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Release|Win32.ActiveCfg = Release|Win32
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Release|Win32.Build.0 = Release|Win32
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Release|x64.ActiveCfg = Release|x64
{18CAE28C-B454-46C1-87A0-493D91D97F03}.Release|x64.Build.0 = Release|x64
{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|ARM.ActiveCfg = Debug|ARM
{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|ARM.Build.0 = Debug|ARM
+ {F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|ARM64.Build.0 = Debug|ARM64
{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32
{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32
{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64
{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|x64.Build.0 = Debug|x64
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|x64.Build.0 = PGInstrument|x64
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {F9D71780-F393-11E0-BE50-0800200C9A66}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {F9D71780-F393-11E0-BE50-0800200C9A66}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{F9D71780-F393-11E0-BE50-0800200C9A66}.PGUpdate|x64.Build.0 = PGUpdate|x64
{F9D71780-F393-11E0-BE50-0800200C9A66}.Release|ARM.ActiveCfg = Release|ARM
{F9D71780-F393-11E0-BE50-0800200C9A66}.Release|ARM.Build.0 = Release|ARM
+ {F9D71780-F393-11E0-BE50-0800200C9A66}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F9D71780-F393-11E0-BE50-0800200C9A66}.Release|ARM64.Build.0 = Release|ARM64
{F9D71780-F393-11E0-BE50-0800200C9A66}.Release|Win32.ActiveCfg = Release|Win32
{F9D71780-F393-11E0-BE50-0800200C9A66}.Release|Win32.Build.0 = Release|Win32
{F9D71780-F393-11E0-BE50-0800200C9A66}.Release|x64.ActiveCfg = Release|x64
{F9D71780-F393-11E0-BE50-0800200C9A66}.Release|x64.Build.0 = Release|x64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|ARM.ActiveCfg = Debug|ARM
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|ARM.Build.0 = Debug|ARM
+ {ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|ARM64.Build.0 = Debug|ARM64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|Win32.ActiveCfg = Debug|Win32
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|Win32.Build.0 = Debug|Win32
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|x64.ActiveCfg = Debug|x64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|x64.Build.0 = Debug|x64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|x64.Build.0 = PGInstrument|x64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGUpdate|x64.Build.0 = PGUpdate|x64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Release|ARM.ActiveCfg = Release|ARM
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Release|ARM.Build.0 = Release|ARM
+ {ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Release|ARM64.ActiveCfg = Release|ARM64
+ {ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Release|ARM64.Build.0 = Release|ARM64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Release|Win32.ActiveCfg = Release|Win32
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Release|Win32.Build.0 = Release|Win32
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Release|x64.ActiveCfg = Release|x64
{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Release|x64.Build.0 = Release|x64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|ARM.ActiveCfg = Debug|ARM
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|ARM.Build.0 = Debug|ARM
+ {D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|ARM64.Build.0 = Debug|ARM64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|Win32.ActiveCfg = Debug|Win32
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|Win32.Build.0 = Debug|Win32
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|x64.ActiveCfg = Debug|x64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|x64.Build.0 = Debug|x64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|x64.Build.0 = PGInstrument|x64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {D06B6426-4762-44CC-8BAD-D79052507F2F}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {D06B6426-4762-44CC-8BAD-D79052507F2F}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGUpdate|x64.Build.0 = PGUpdate|x64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|ARM.ActiveCfg = Release|ARM
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|ARM.Build.0 = Release|ARM
+ {D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|ARM64.ActiveCfg = Release|ARM64
+ {D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|ARM64.Build.0 = Release|ARM64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|Win32.ActiveCfg = Release|Win32
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|Win32.Build.0 = Release|Win32
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|x64.ActiveCfg = Release|x64
{D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|x64.Build.0 = Release|x64
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|ARM.ActiveCfg = Debug|ARM
+ {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|ARM64.ActiveCfg = Debug|Win32
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|Win32.ActiveCfg = Debug|Win32
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|x64.ActiveCfg = Release|x64
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
+ {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|ARM64.ActiveCfg = PGInstrument|Win32
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|Win32.ActiveCfg = Release|Win32
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|x64.ActiveCfg = Release|x64
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
+ {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGUpdate|ARM64.ActiveCfg = PGUpdate|Win32
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGUpdate|Win32.ActiveCfg = Release|Win32
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGUpdate|x64.ActiveCfg = Release|x64
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Release|ARM.ActiveCfg = Release|ARM
+ {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Release|ARM64.ActiveCfg = Release|Win32
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Release|Win32.ActiveCfg = Release|Win32
{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Release|x64.ActiveCfg = Release|x64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|ARM.ActiveCfg = Debug|ARM
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|ARM.Build.0 = Debug|ARM
+ {447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|ARM64.Build.0 = Debug|ARM64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|Win32.ActiveCfg = Debug|Win32
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|Win32.Build.0 = Debug|Win32
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|x64.ActiveCfg = Debug|x64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|x64.Build.0 = Debug|x64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|x64.Build.0 = PGInstrument|x64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {447F05A8-F581-4CAC-A466-5AC7936E207E}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {447F05A8-F581-4CAC-A466-5AC7936E207E}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGUpdate|x64.Build.0 = PGUpdate|x64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Release|ARM.ActiveCfg = Release|ARM
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Release|ARM.Build.0 = Release|ARM
+ {447F05A8-F581-4CAC-A466-5AC7936E207E}.Release|ARM64.ActiveCfg = Release|ARM64
+ {447F05A8-F581-4CAC-A466-5AC7936E207E}.Release|ARM64.Build.0 = Release|ARM64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Release|Win32.ActiveCfg = Release|Win32
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Release|Win32.Build.0 = Release|Win32
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Release|x64.ActiveCfg = Release|x64
{447F05A8-F581-4CAC-A466-5AC7936E207E}.Release|x64.Build.0 = Release|x64
{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|ARM.ActiveCfg = Debug|ARM
{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|ARM.Build.0 = Debug|ARM
+ {A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|ARM64.Build.0 = Debug|ARM64
{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|Win32.ActiveCfg = Debug|Win32
{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|Win32.Build.0 = Debug|Win32
{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|x64.ActiveCfg = Debug|x64
{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|x64.Build.0 = Debug|x64
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|x64.Build.0 = PGInstrument|x64
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {A1A295E5-463C-437F-81CA-1F32367685DA}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {A1A295E5-463C-437F-81CA-1F32367685DA}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{A1A295E5-463C-437F-81CA-1F32367685DA}.PGUpdate|x64.Build.0 = PGUpdate|x64
{A1A295E5-463C-437F-81CA-1F32367685DA}.Release|ARM.ActiveCfg = Release|ARM
{A1A295E5-463C-437F-81CA-1F32367685DA}.Release|ARM.Build.0 = Release|ARM
+ {A1A295E5-463C-437F-81CA-1F32367685DA}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A1A295E5-463C-437F-81CA-1F32367685DA}.Release|ARM64.Build.0 = Release|ARM64
{A1A295E5-463C-437F-81CA-1F32367685DA}.Release|Win32.ActiveCfg = Release|Win32
{A1A295E5-463C-437F-81CA-1F32367685DA}.Release|Win32.Build.0 = Release|Win32
{A1A295E5-463C-437F-81CA-1F32367685DA}.Release|x64.ActiveCfg = Release|x64
{A1A295E5-463C-437F-81CA-1F32367685DA}.Release|x64.Build.0 = Release|x64
{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|ARM.ActiveCfg = Debug|ARM
{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|ARM.Build.0 = Debug|ARM
+ {9E48B300-37D1-11DD-8C41-005056C00008}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {9E48B300-37D1-11DD-8C41-005056C00008}.Debug|ARM64.Build.0 = Debug|ARM64
{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|Win32.ActiveCfg = Debug|Win32
{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|Win32.Build.0 = Debug|Win32
{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|x64.ActiveCfg = Debug|x64
{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|x64.Build.0 = Debug|x64
{9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|x64.Build.0 = PGInstrument|x64
{9E48B300-37D1-11DD-8C41-005056C00008}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{9E48B300-37D1-11DD-8C41-005056C00008}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {9E48B300-37D1-11DD-8C41-005056C00008}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {9E48B300-37D1-11DD-8C41-005056C00008}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{9E48B300-37D1-11DD-8C41-005056C00008}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{9E48B300-37D1-11DD-8C41-005056C00008}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{9E48B300-37D1-11DD-8C41-005056C00008}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{9E48B300-37D1-11DD-8C41-005056C00008}.PGUpdate|x64.Build.0 = PGUpdate|x64
{9E48B300-37D1-11DD-8C41-005056C00008}.Release|ARM.ActiveCfg = Release|ARM
{9E48B300-37D1-11DD-8C41-005056C00008}.Release|ARM.Build.0 = Release|ARM
+ {9E48B300-37D1-11DD-8C41-005056C00008}.Release|ARM64.ActiveCfg = Release|ARM64
+ {9E48B300-37D1-11DD-8C41-005056C00008}.Release|ARM64.Build.0 = Release|ARM64
{9E48B300-37D1-11DD-8C41-005056C00008}.Release|Win32.ActiveCfg = Release|Win32
{9E48B300-37D1-11DD-8C41-005056C00008}.Release|Win32.Build.0 = Release|Win32
{9E48B300-37D1-11DD-8C41-005056C00008}.Release|x64.ActiveCfg = Release|x64
{9E48B300-37D1-11DD-8C41-005056C00008}.Release|x64.Build.0 = Release|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|ARM.ActiveCfg = Debug|ARM
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|ARM.Build.0 = Debug|ARM
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|ARM64.Build.0 = Debug|ARM64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|Win32.ActiveCfg = Debug|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|Win32.Build.0 = Debug|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = Debug|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = Debug|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.ActiveCfg = Debug|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.Build.0 = Debug|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = Debug|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = Debug|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.ActiveCfg = Debug|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.Build.0 = Debug|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = Debug|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = Debug|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|ARM.ActiveCfg = Release|ARM
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|ARM.Build.0 = Release|ARM
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|ARM64.ActiveCfg = Release|ARM64
+ {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|ARM64.Build.0 = Release|ARM64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.ActiveCfg = Release|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.Build.0 = Release|Win32
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.ActiveCfg = Release|x64
{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.Build.0 = Release|x64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|ARM.ActiveCfg = Debug|ARM
+ {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|Win32.ActiveCfg = Release|Win32
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|x64.ActiveCfg = Release|x64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
+ {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|x64.Build.0 = PGInstrument|x64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
+ {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|x64.ActiveCfg = Release|x64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|x64.Build.0 = Release|x64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|ARM.ActiveCfg = Release|ARM
+ {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|ARM64.ActiveCfg = Release|ARM64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|Win32.ActiveCfg = Release|Win32
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|Win32.Build.0 = Release|Win32
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|x64.ActiveCfg = Release|x64
{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|x64.Build.0 = Release|x64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|ARM.ActiveCfg = Debug|ARM
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|ARM.Build.0 = Debug|ARM
+ {A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|ARM64.Build.0 = Debug|ARM64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|Win32.ActiveCfg = Debug|Win32
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|Win32.Build.0 = Debug|Win32
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|x64.ActiveCfg = Debug|x64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|x64.Build.0 = Debug|x64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|Win32.ActiveCfg = Release|Win32
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|Win32.Build.0 = Release|Win32
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|x64.ActiveCfg = Release|x64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|x64.Build.0 = Release|x64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGUpdate|Win32.ActiveCfg = Release|Win32
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGUpdate|Win32.Build.0 = Release|Win32
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGUpdate|x64.ActiveCfg = Release|x64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGUpdate|x64.Build.0 = Release|x64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Release|ARM.ActiveCfg = Release|ARM
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Release|ARM.Build.0 = Release|ARM
+ {A2697BD3-28C1-4AEC-9106-8B748639FD16}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A2697BD3-28C1-4AEC-9106-8B748639FD16}.Release|ARM64.Build.0 = Release|ARM64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Release|Win32.ActiveCfg = Release|Win32
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Release|Win32.Build.0 = Release|Win32
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Release|x64.ActiveCfg = Release|x64
{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Release|x64.Build.0 = Release|x64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|ARM.ActiveCfg = Debug|ARM
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|ARM.Build.0 = Debug|ARM
+ {7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|ARM64.Build.0 = Debug|ARM64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|Win32.ActiveCfg = Debug|Win32
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|Win32.Build.0 = Debug|Win32
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|x64.ActiveCfg = Debug|x64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|x64.Build.0 = Debug|x64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|Win32.ActiveCfg = Release|Win32
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|Win32.Build.0 = Release|Win32
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|x64.ActiveCfg = Release|x64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|x64.Build.0 = Release|x64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGUpdate|Win32.ActiveCfg = Release|Win32
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGUpdate|Win32.Build.0 = Release|Win32
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGUpdate|x64.ActiveCfg = Release|x64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGUpdate|x64.Build.0 = Release|x64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Release|ARM.ActiveCfg = Release|ARM
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Release|ARM.Build.0 = Release|ARM
+ {7B2727B5-5A3F-40EE-A866-43A13CD31446}.Release|ARM64.ActiveCfg = Release|ARM64
+ {7B2727B5-5A3F-40EE-A866-43A13CD31446}.Release|ARM64.Build.0 = Release|ARM64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Release|Win32.ActiveCfg = Release|Win32
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Release|Win32.Build.0 = Release|Win32
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Release|x64.ActiveCfg = Release|x64
{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Release|x64.Build.0 = Release|x64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|ARM.ActiveCfg = Debug|ARM
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|ARM.Build.0 = Debug|ARM
+ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|ARM64.Build.0 = Debug|ARM64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|Win32.ActiveCfg = Debug|Win32
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|Win32.Build.0 = Debug|Win32
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|x64.ActiveCfg = Debug|x64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|x64.Build.0 = Debug|x64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|Win32.ActiveCfg = Release|Win32
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|Win32.Build.0 = Release|Win32
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|x64.ActiveCfg = Release|x64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|x64.Build.0 = Release|x64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGUpdate|Win32.ActiveCfg = Release|Win32
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGUpdate|Win32.Build.0 = Release|Win32
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGUpdate|x64.ActiveCfg = Release|x64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGUpdate|x64.Build.0 = Release|x64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|ARM.ActiveCfg = Release|ARM
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|ARM.Build.0 = Release|ARM
+ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|ARM64.ActiveCfg = Release|ARM64
+ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|ARM64.Build.0 = Release|ARM64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|Win32.ActiveCfg = Release|Win32
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|Win32.Build.0 = Release|Win32
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|x64.ActiveCfg = Release|x64
{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|x64.Build.0 = Release|x64
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|ARM.ActiveCfg = Debug|ARM
+ {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|ARM64.ActiveCfg = Debug|ARM64
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|Win32.ActiveCfg = Debug|Win32
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|x64.ActiveCfg = Debug|x64
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
+ {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|Win32.ActiveCfg = Release|Win32
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|x64.ActiveCfg = Release|Win32
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
+ {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|Win32.ActiveCfg = Release|Win32
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|x64.ActiveCfg = Release|Win32
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|ARM.ActiveCfg = Release|ARM
+ {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|ARM64.ActiveCfg = Release|ARM64
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|Win32.ActiveCfg = Release|Win32
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|Win32.Build.0 = Release|Win32
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|x64.ActiveCfg = Release|x64
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|x64.Build.0 = Release|x64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Debug|ARM.ActiveCfg = Debug|ARM
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Debug|ARM.Build.0 = Debug|ARM
+ {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Debug|ARM64.Build.0 = Debug|ARM64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Debug|Win32.ActiveCfg = Debug|Win32
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Debug|Win32.Build.0 = Debug|Win32
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Debug|x64.ActiveCfg = Debug|x64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Debug|x64.Build.0 = Debug|x64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGInstrument|x64.Build.0 = PGInstrument|x64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.PGUpdate|x64.Build.0 = PGUpdate|x64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|ARM.ActiveCfg = Release|ARM
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|ARM.Build.0 = Release|ARM
+ {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|ARM64.ActiveCfg = Release|ARM64
+ {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|ARM64.Build.0 = Release|ARM64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|Win32.ActiveCfg = Release|Win32
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|Win32.Build.0 = Release|Win32
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|x64.ActiveCfg = Release|x64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|x64.Build.0 = Release|x64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Debug|ARM.ActiveCfg = Debug|ARM
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Debug|ARM.Build.0 = Debug|ARM
+ {6DAC66D9-E703-4624-BE03-49112AB5AA62}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {6DAC66D9-E703-4624-BE03-49112AB5AA62}.Debug|ARM64.Build.0 = Debug|ARM64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Debug|Win32.ActiveCfg = Debug|Win32
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Debug|Win32.Build.0 = Debug|Win32
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Debug|x64.ActiveCfg = Debug|x64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Debug|x64.Build.0 = Debug|x64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGInstrument|Win32.ActiveCfg = Release|Win32
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGInstrument|x64.ActiveCfg = Release|x64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGUpdate|Win32.ActiveCfg = Release|Win32
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGUpdate|Win32.Build.0 = Release|Win32
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGUpdate|x64.ActiveCfg = Release|x64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.PGUpdate|x64.Build.0 = Release|x64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Release|ARM.ActiveCfg = Release|ARM
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Release|ARM.Build.0 = Release|ARM
+ {6DAC66D9-E703-4624-BE03-49112AB5AA62}.Release|ARM64.ActiveCfg = Release|ARM64
+ {6DAC66D9-E703-4624-BE03-49112AB5AA62}.Release|ARM64.Build.0 = Release|ARM64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Release|Win32.ActiveCfg = Release|Win32
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Release|Win32.Build.0 = Release|Win32
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Release|x64.ActiveCfg = Release|x64
{6DAC66D9-E703-4624-BE03-49112AB5AA62}.Release|x64.Build.0 = Release|x64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Debug|ARM.ActiveCfg = Debug|ARM
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Debug|ARM.Build.0 = Debug|ARM
+ {16BFE6F0-22EF-40B5-B831-7E937119EF10}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {16BFE6F0-22EF-40B5-B831-7E937119EF10}.Debug|ARM64.Build.0 = Debug|ARM64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Debug|Win32.ActiveCfg = Debug|Win32
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Debug|Win32.Build.0 = Debug|Win32
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Debug|x64.ActiveCfg = Debug|x64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Debug|x64.Build.0 = Debug|x64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGInstrument|Win32.ActiveCfg = Release|Win32
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGInstrument|x64.ActiveCfg = Release|x64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGUpdate|Win32.ActiveCfg = Release|Win32
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGUpdate|Win32.Build.0 = Release|Win32
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGUpdate|x64.ActiveCfg = Release|x64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.PGUpdate|x64.Build.0 = Release|x64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Release|ARM.ActiveCfg = Release|ARM
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Release|ARM.Build.0 = Release|ARM
+ {16BFE6F0-22EF-40B5-B831-7E937119EF10}.Release|ARM64.ActiveCfg = Release|ARM64
+ {16BFE6F0-22EF-40B5-B831-7E937119EF10}.Release|ARM64.Build.0 = Release|ARM64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Release|Win32.ActiveCfg = Release|Win32
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Release|Win32.Build.0 = Release|Win32
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Release|x64.ActiveCfg = Release|x64
{16BFE6F0-22EF-40B5-B831-7E937119EF10}.Release|x64.Build.0 = Release|x64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|ARM.ActiveCfg = Debug|ARM
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|ARM.Build.0 = Debug|ARM
+ {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|ARM64.Build.0 = Debug|ARM64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|Win32.ActiveCfg = Debug|Win32
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|Win32.Build.0 = Debug|Win32
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|x64.ActiveCfg = Debug|x64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|x64.Build.0 = Debug|x64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|x64.Build.0 = PGInstrument|x64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|x64.Build.0 = PGUpdate|x64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|ARM.ActiveCfg = Release|ARM
- {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|ARM.Build.0 = Release|ARM
+ {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|ARM64.ActiveCfg = Release|ARM64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|Win32.ActiveCfg = Release|Win32
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|Win32.Build.0 = Release|Win32
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|x64.ActiveCfg = Release|x64
{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|x64.Build.0 = Release|x64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|ARM.ActiveCfg = Debug|ARM
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|ARM.Build.0 = Debug|ARM
+ {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|ARM64.Build.0 = Debug|ARM64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|Win32.ActiveCfg = Debug|Win32
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|Win32.Build.0 = Debug|Win32
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|x64.ActiveCfg = Debug|x64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Debug|x64.Build.0 = Debug|x64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|Win32.ActiveCfg = Release|Win32
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|Win32.Build.0 = Release|Win32
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|x64.ActiveCfg = Release|x64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGInstrument|x64.Build.0 = Release|x64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|Win32.ActiveCfg = Release|Win32
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|Win32.Build.0 = Release|Win32
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|x64.ActiveCfg = Release|x64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.PGUpdate|x64.Build.0 = Release|x64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|ARM.ActiveCfg = Release|ARM
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|ARM.Build.0 = Release|ARM
+ {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|ARM64.ActiveCfg = Release|ARM64
+ {B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|ARM64.Build.0 = Release|ARM64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|Win32.ActiveCfg = Release|Win32
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|Win32.Build.0 = Release|Win32
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|x64.ActiveCfg = Release|x64
{B244E787-C445-441C-BDF4-5A4F1A3A1E51}.Release|x64.Build.0 = Release|x64
{384C224A-7474-476E-A01B-750EA7DE918C}.Debug|ARM.ActiveCfg = Debug|ARM
{384C224A-7474-476E-A01B-750EA7DE918C}.Debug|ARM.Build.0 = Debug|ARM
+ {384C224A-7474-476E-A01B-750EA7DE918C}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {384C224A-7474-476E-A01B-750EA7DE918C}.Debug|ARM64.Build.0 = Debug|ARM64
{384C224A-7474-476E-A01B-750EA7DE918C}.Debug|Win32.ActiveCfg = Debug|Win32
{384C224A-7474-476E-A01B-750EA7DE918C}.Debug|Win32.Build.0 = Debug|Win32
{384C224A-7474-476E-A01B-750EA7DE918C}.Debug|x64.ActiveCfg = Debug|x64
{384C224A-7474-476E-A01B-750EA7DE918C}.Debug|x64.Build.0 = Debug|x64
{384C224A-7474-476E-A01B-750EA7DE918C}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{384C224A-7474-476E-A01B-750EA7DE918C}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {384C224A-7474-476E-A01B-750EA7DE918C}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {384C224A-7474-476E-A01B-750EA7DE918C}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{384C224A-7474-476E-A01B-750EA7DE918C}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{384C224A-7474-476E-A01B-750EA7DE918C}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{384C224A-7474-476E-A01B-750EA7DE918C}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{384C224A-7474-476E-A01B-750EA7DE918C}.PGInstrument|x64.Build.0 = PGInstrument|x64
{384C224A-7474-476E-A01B-750EA7DE918C}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{384C224A-7474-476E-A01B-750EA7DE918C}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {384C224A-7474-476E-A01B-750EA7DE918C}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {384C224A-7474-476E-A01B-750EA7DE918C}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{384C224A-7474-476E-A01B-750EA7DE918C}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{384C224A-7474-476E-A01B-750EA7DE918C}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{384C224A-7474-476E-A01B-750EA7DE918C}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{384C224A-7474-476E-A01B-750EA7DE918C}.PGUpdate|x64.Build.0 = PGUpdate|x64
{384C224A-7474-476E-A01B-750EA7DE918C}.Release|ARM.ActiveCfg = Release|ARM
{384C224A-7474-476E-A01B-750EA7DE918C}.Release|ARM.Build.0 = Release|ARM
+ {384C224A-7474-476E-A01B-750EA7DE918C}.Release|ARM64.ActiveCfg = Release|ARM64
+ {384C224A-7474-476E-A01B-750EA7DE918C}.Release|ARM64.Build.0 = Release|ARM64
{384C224A-7474-476E-A01B-750EA7DE918C}.Release|Win32.ActiveCfg = Release|Win32
{384C224A-7474-476E-A01B-750EA7DE918C}.Release|Win32.Build.0 = Release|Win32
{384C224A-7474-476E-A01B-750EA7DE918C}.Release|x64.ActiveCfg = Release|x64
{384C224A-7474-476E-A01B-750EA7DE918C}.Release|x64.Build.0 = Release|x64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Debug|ARM.ActiveCfg = Debug|ARM
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Debug|ARM.Build.0 = Debug|ARM
+ {78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Debug|ARM64.Build.0 = Debug|ARM64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Debug|Win32.ActiveCfg = Debug|Win32
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Debug|Win32.Build.0 = Debug|Win32
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Debug|x64.ActiveCfg = Debug|x64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Debug|x64.Build.0 = Debug|x64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGInstrument|x64.Build.0 = PGInstrument|x64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.PGUpdate|x64.Build.0 = PGUpdate|x64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Release|ARM.ActiveCfg = Release|ARM
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Release|ARM.Build.0 = Release|ARM
+ {78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Release|ARM64.ActiveCfg = Release|ARM64
+ {78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Release|ARM64.Build.0 = Release|ARM64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Release|Win32.ActiveCfg = Release|Win32
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Release|Win32.Build.0 = Release|Win32
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Release|x64.ActiveCfg = Release|x64
{78D80A15-BD8C-44E2-B49E-1F05B0A0A687}.Release|x64.Build.0 = Release|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|ARM.ActiveCfg = Debug|ARM
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|ARM.Build.0 = Debug|ARM
+ {12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|ARM64.Build.0 = Debug|ARM64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|Win32.ActiveCfg = Debug|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|Win32.Build.0 = Debug|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|x64.ActiveCfg = Debug|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Debug|x64.Build.0 = Debug|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {12728250-16EC-4DC6-94D7-E21DD88947F8}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {12728250-16EC-4DC6-94D7-E21DD88947F8}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGInstrument|x64.Build.0 = PGInstrument|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {12728250-16EC-4DC6-94D7-E21DD88947F8}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {12728250-16EC-4DC6-94D7-E21DD88947F8}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.PGUpdate|x64.Build.0 = PGUpdate|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|ARM.ActiveCfg = Release|ARM
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|ARM.Build.0 = Release|ARM
+ {12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|ARM64.ActiveCfg = Release|ARM64
+ {12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|ARM64.Build.0 = Release|ARM64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|Win32.ActiveCfg = Release|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|Win32.Build.0 = Release|Win32
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.ActiveCfg = Release|x64
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.Build.0 = Release|x64
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|ARM.ActiveCfg = Debug|Win32
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|ARM64.ActiveCfg = Debug|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|Win32.ActiveCfg = Debug|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|Win32.Build.0 = Debug|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|x64.ActiveCfg = Debug|x64
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|x64.Build.0 = Debug|x64
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|ARM.ActiveCfg = PGInstrument|Win32
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|ARM64.ActiveCfg = PGInstrument|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|x64.Build.0 = PGInstrument|x64
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|ARM.ActiveCfg = PGUpdate|Win32
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|ARM64.ActiveCfg = PGUpdate|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|x64.Build.0 = PGUpdate|x64
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|ARM.ActiveCfg = Release|Win32
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|ARM64.ActiveCfg = Release|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|Win32.ActiveCfg = Release|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|Win32.Build.0 = Release|Win32
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|x64.ActiveCfg = Release|x64
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|x64.Build.0 = Release|x64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|ARM.ActiveCfg = Debug|ARM
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|ARM.Build.0 = Debug|ARM
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|ARM64.Build.0 = Debug|ARM64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|Win32.ActiveCfg = Debug|Win32
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|Win32.Build.0 = Debug|Win32
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|x64.ActiveCfg = Debug|x64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|x64.Build.0 = Debug|x64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|x64.Build.0 = PGInstrument|x64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|x64.Build.0 = PGUpdate|x64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|ARM.ActiveCfg = Release|ARM
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|ARM.Build.0 = Release|ARM
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|ARM64.Build.0 = Release|ARM64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|Win32.ActiveCfg = Release|Win32
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|Win32.Build.0 = Release|Win32
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|x64.ActiveCfg = Release|x64
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|x64.Build.0 = Release|x64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|ARM.ActiveCfg = Debug|ARM
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|ARM.Build.0 = Debug|ARM
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|ARM64.Build.0 = Debug|ARM64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|Win32.ActiveCfg = Debug|Win32
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|Win32.Build.0 = Debug|Win32
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|x64.ActiveCfg = Debug|x64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|x64.Build.0 = Debug|x64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|ARM.Build.0 = PGInstrument|ARM
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|x64.Build.0 = PGInstrument|x64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|ARM.Build.0 = PGUpdate|ARM
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|x64.Build.0 = PGUpdate|x64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|ARM.ActiveCfg = Release|ARM
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|ARM.Build.0 = Release|ARM
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|ARM64.Build.0 = Release|ARM64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|Win32.ActiveCfg = Release|Win32
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|Win32.Build.0 = Release|Win32
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|x64.ActiveCfg = Release|x64
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|x64.Build.0 = Release|x64
{AB603547-1E2A-45B3-9E09-B04596006393}.Debug|ARM.ActiveCfg = Debug|Win32
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Debug|ARM64.ActiveCfg = Debug|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.Debug|Win32.ActiveCfg = Debug|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.Debug|Win32.Build.0 = Debug|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.Debug|x64.ActiveCfg = Debug|x64
{AB603547-1E2A-45B3-9E09-B04596006393}.Debug|x64.Build.0 = Debug|x64
{AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|ARM.ActiveCfg = PGInstrument|Win32
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|ARM64.ActiveCfg = PGInstrument|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
{AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|x64.Build.0 = PGInstrument|x64
{AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|ARM.ActiveCfg = PGUpdate|Win32
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|ARM64.ActiveCfg = PGUpdate|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
{AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|x64.Build.0 = PGUpdate|x64
{AB603547-1E2A-45B3-9E09-B04596006393}.Release|ARM.ActiveCfg = Release|Win32
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Release|ARM64.ActiveCfg = Release|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.Release|Win32.ActiveCfg = Release|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.Release|Win32.Build.0 = Release|Win32
{AB603547-1E2A-45B3-9E09-B04596006393}.Release|x64.ActiveCfg = Release|x64
diff --git a/PCbuild/prepare_libffi.bat b/PCbuild/prepare_libffi.bat
index 307739d874a..c65a5f7010b 100644
--- a/PCbuild/prepare_libffi.bat
+++ b/PCbuild/prepare_libffi.bat
@@ -25,6 +25,7 @@ echo.Available flags:
echo. -x64 build for x64
echo. -x86 build for x86
echo. -arm32 build for arm32
+echo. -arm64 build for arm64
echo. -? this help
echo. --install-cygwin install cygwin to c:\cygwin
exit /b 127
@@ -34,6 +35,9 @@ exit /b 127
set BUILD_X64=
set BUILD_X86=
set BUILD_ARM32=
+set BUILD_ARM64=
+set BUILD_PDB=
+set BUILD_NOOPT=
set INSTALL_CYGWIN=
:CheckOpts
@@ -41,16 +45,20 @@ if "%1"=="" goto :CheckOptsDone
if /I "%1"=="-x64" (set BUILD_X64=1) & shift & goto :CheckOpts
if /I "%1"=="-x86" (set BUILD_X86=1) & shift & goto :CheckOpts
if /I "%1"=="-arm32" (set BUILD_ARM32=1) & shift & goto :CheckOpts
+if /I "%1"=="-arm64" (set BUILD_ARM64=1) & shift & goto :CheckOpts
+if /I "%1"=="-pdb" (set BUILD_PDB=-g) & shift & goto :CheckOpts
+if /I "%1"=="-noopt" (set BUILD_NOOPT=CFLAGS='-Od -warn all') & shift & goto :CheckOpts
if /I "%1"=="-?" goto :Usage
if /I "%1"=="--install-cygwin" (set INSTALL_CYGWIN=1) & shift & goto :CheckOpts
goto :Usage
:CheckOptsDone
-if NOT DEFINED BUILD_X64 if NOT DEFINED BUILD_X86 if NOT DEFINED BUILD_ARM32 (
+if NOT DEFINED BUILD_X64 if NOT DEFINED BUILD_X86 if NOT DEFINED BUILD_ARM32 if NOT DEFINED BUILD_ARM64 (
set BUILD_X64=1
set BUILD_X86=1
set BUILD_ARM32=1
+ set BUILD_ARM64=1
)
if "%INSTALL_CYGWIN%"=="1" call :InstallCygwin
@@ -90,6 +98,7 @@ if not exist Makefile.in (%SH% -lc "(cd $LIBFFI_SOURCE; ./autogen.sh;)")
if "%BUILD_X64%"=="1" call :BuildOne x64 x86_64-w64-cygwin x86_64-w64-cygwin
if "%BUILD_X86%"=="1" call :BuildOne x86 i686-pc-cygwin i686-pc-cygwin
if "%BUILD_ARM32%"=="1" call :BuildOne x86_arm i686-pc-cygwin arm-w32-cygwin
+if "%BUILD_ARM64%"=="1" call :BuildOne x86_arm64 i686-pc-cygwin aarch64-w64-cygwin
popd
endlocal
@@ -129,6 +138,12 @@ if /I "%VCVARS_PLATFORM%" EQU "x86_arm" (
set ASSEMBLER=-marm
set SRC_ARCHITECTURE=ARM
)
+if /I "%VCVARS_PLATFORM%" EQU "x86_arm64" (
+ set ARCH=arm64
+ set ARTIFACTS=%LIBFFI_SOURCE%\aarch64-w64-cygwin
+ set ASSEMBLER=-marm64
+ set SRC_ARCHITECTURE=aarch64
+)
if NOT DEFINED LIBFFI_OUT set LIBFFI_OUT=%~dp0\..\externals\libffi
set _LIBFFI_OUT=%LIBFFI_OUT%\%ARCH%
@@ -139,10 +154,14 @@ call %VCVARSALL% %VCVARS_PLATFORM%
echo clean %_LIBFFI_OUT%
if exist %_LIBFFI_OUT% (rd %_LIBFFI_OUT% /s/q)
+echo ================================================================
echo Configure the build to generate fficonfig.h and ffi.h
-%SH% -lc "(cd $OLDPWD; ./configure CC='%MSVCC% %ASSEMBLER%' CXX='%MSVCC% %ASSEMBLER%' LD='link' CPP='cl -nologo -EP' CXXCPP='cl -nologo -EP' CPPFLAGS='-DFFI_BUILDING_DLL' NM='dumpbin -symbols' STRIP=':' --build=$BUILD --host=$HOST;)"
+echo ================================================================
+%SH% -lc "(cd $OLDPWD; ./configure CC='%MSVCC% %ASSEMBLER% %BUILD_PDB%' CXX='%MSVCC% %ASSEMBLER% %BUILD_PDB%' LD='link' CPP='cl -nologo -EP' CXXCPP='cl -nologo -EP' CPPFLAGS='-DFFI_BUILDING_DLL' %BUILD_NOOPT% NM='dumpbin -symbols' STRIP=':' --build=$BUILD --host=$HOST;)"
+echo ================================================================
echo Building libffi
+echo ================================================================
%SH% -lc "(cd $OLDPWD; export PATH=/usr/bin:$PATH; cp src/%SRC_ARCHITECTURE%/ffitarget.h include; make; find .;)"
REM Tests are not needed to produce artifacts
@@ -158,6 +177,7 @@ echo copying files to %_LIBFFI_OUT%
if not exist %_LIBFFI_OUT%\include (md %_LIBFFI_OUT%\include)
copy %ARTIFACTS%\.libs\libffi-7.dll %_LIBFFI_OUT%
copy %ARTIFACTS%\.libs\libffi-7.lib %_LIBFFI_OUT%
+copy %ARTIFACTS%\.libs\libffi-7.pdb %_LIBFFI_OUT%
copy %ARTIFACTS%\fficonfig.h %_LIBFFI_OUT%\include
copy %ARTIFACTS%\include\*.h %_LIBFFI_OUT%\include
diff --git a/PCbuild/pyexpat.vcxproj b/PCbuild/pyexpat.vcxproj
index 5503b6a5e9a..28a11a82936 100644
--- a/PCbuild/pyexpat.vcxproj
+++ b/PCbuild/pyexpat.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/pylauncher.vcxproj b/PCbuild/pylauncher.vcxproj
index aebbfbd36b3..550e0842300 100644
--- a/PCbuild/pylauncher.vcxproj
+++ b/PCbuild/pylauncher.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props
index 847e5f57c4b..12f07dd5128 100644
--- a/PCbuild/pyproject.props
+++ b/PCbuild/pyproject.props
@@ -65,6 +65,7 @@
MachineX86MachineX64MachineARM
+ MachineARM64$(OutDir)$(TargetName).pgdUseLinkTimeCodeGenerationPGInstrument
diff --git a/PCbuild/pyshellext.vcxproj b/PCbuild/pyshellext.vcxproj
index 5b7320b1b81..655054e3723 100644
--- a/PCbuild/pyshellext.vcxproj
+++ b/PCbuild/pyshellext.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/python.props b/PCbuild/python.props
index b3e5b92f292..11638fe348c 100644
--- a/PCbuild/python.props
+++ b/PCbuild/python.props
@@ -40,9 +40,12 @@
$(Py_OutDir)\amd64\$(PySourcePath)PCbuild\arm32\$(Py_OutDir)\arm32\
+ $(PySourcePath)PCbuild\arm64\
+ $(Py_OutDir)\arm64\$(BuildPath32)$(BuildPath64)$(BuildPathArm32)
+ $(BuildPathArm64)$(PySourcePath)PCbuild\$(ArchName)\$(BuildPath)\$(BuildPath)instrumented\
@@ -72,6 +75,7 @@
-32-arm32
+ -arm64$(BuildPath)python$(PyDebugExt).exe
@@ -81,6 +85,10 @@
true
+
+ true
+
+
.cp$(MajorVersionNumber)$(MinorVersionNumber)-win32.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm32
+ .cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm64.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_amd64
diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj
index 77d22ecdabf..919b79d986d 100644
--- a/PCbuild/python.vcxproj
+++ b/PCbuild/python.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM
+ ReleaseWin32
@@ -98,7 +114,7 @@
-
+ ucrtbaseucrtbased
diff --git a/PCbuild/python3dll.vcxproj b/PCbuild/python3dll.vcxproj
index 65afcd38c1d..ef344bed49e 100644
--- a/PCbuild/python3dll.vcxproj
+++ b/PCbuild/python3dll.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
@@ -75,6 +91,7 @@
<_Machine>X86
<_Machine Condition="$(Platform) == 'x64'">X64
<_Machine Condition="$(Platform) == 'ARM'">ARM
+ <_Machine Condition="$(Platform) == 'ARM64'">ARM64
$(ExtensionsToDeleteOnClean);$(IntDir)python3_d.def;$(IntDir)python3stub.def
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 5c5a720ba0c..a71fce6bb60 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/pythonw.vcxproj b/PCbuild/pythonw.vcxproj
index bd711a44860..e7216dec3a1 100644
--- a/PCbuild/pythonw.vcxproj
+++ b/PCbuild/pythonw.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/pywlauncher.vcxproj b/PCbuild/pywlauncher.vcxproj
index d15366cfd72..44e3fc29272 100644
--- a/PCbuild/pywlauncher.vcxproj
+++ b/PCbuild/pywlauncher.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/select.vcxproj b/PCbuild/select.vcxproj
index d264d9ff0d4..750a7139499 100644
--- a/PCbuild/select.vcxproj
+++ b/PCbuild/select.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/sqlite3.vcxproj b/PCbuild/sqlite3.vcxproj
index 8d2d4771389..90b4d3108fa 100644
--- a/PCbuild/sqlite3.vcxproj
+++ b/PCbuild/sqlite3.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/unicodedata.vcxproj b/PCbuild/unicodedata.vcxproj
index f90cccb82d9..addef753359 100644
--- a/PCbuild/unicodedata.vcxproj
+++ b/PCbuild/unicodedata.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/venvlauncher.vcxproj b/PCbuild/venvlauncher.vcxproj
index d8b1b661fda..123e84ec4e3 100644
--- a/PCbuild/venvlauncher.vcxproj
+++ b/PCbuild/venvlauncher.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/venvwlauncher.vcxproj b/PCbuild/venvwlauncher.vcxproj
index 0c7664bf70b..b8504d5d08e 100644
--- a/PCbuild/venvwlauncher.vcxproj
+++ b/PCbuild/venvwlauncher.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/winsound.vcxproj b/PCbuild/winsound.vcxproj
index 557160424ae..56da96a8552 100644
--- a/PCbuild/winsound.vcxproj
+++ b/PCbuild/winsound.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
diff --git a/PCbuild/xxlimited.vcxproj b/PCbuild/xxlimited.vcxproj
index cb1be299a6b..776335a15cb 100644
--- a/PCbuild/xxlimited.vcxproj
+++ b/PCbuild/xxlimited.vcxproj
@@ -5,6 +5,10 @@
DebugARM
+
+ Debug
+ ARM64
+ DebugWin32
@@ -17,6 +21,10 @@
PGInstrumentARM
+
+ PGInstrument
+ ARM64
+ PGInstrumentWin32
@@ -29,6 +37,10 @@
PGUpdateARM
+
+ PGUpdate
+ ARM64
+ PGUpdateWin32
@@ -41,6 +53,10 @@
ReleaseARM
+
+ Release
+ ARM64
+ ReleaseWin32
From 3ea702eca17c4ab5209d823fac2463307dde0633 Mon Sep 17 00:00:00 2001
From: Paul Monson
Date: Fri, 17 May 2019 10:08:55 -0700
Subject: [PATCH 091/199] bpo-36942 Windows build changes for Windows ARM64
(GH-13366)
---
PC/pyconfig.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/PC/pyconfig.h b/PC/pyconfig.h
index 6f8fda66237..a74ee98a753 100644
--- a/PC/pyconfig.h
+++ b/PC/pyconfig.h
@@ -122,6 +122,9 @@ WIN32 is still required for the locale module.
#if defined(_M_X64) || defined(_M_AMD64)
#if defined(__INTEL_COMPILER)
#define COMPILER ("[ICC v." _Py_STRINGIZE(__INTEL_COMPILER) " 64 bit (amd64) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]")
+#elif defined(_M_ARM64)
+#define COMPILER _Py_PASTE_VERSION("64 bit (ARM)")
+#define PYD_PLATFORM_TAG "win_arm64"
#else
#define COMPILER _Py_PASTE_VERSION("64 bit (AMD64)")
#endif /* __INTEL_COMPILER */
From cbe72d842646ded2454784679231e3d1e6252e72 Mon Sep 17 00:00:00 2001
From: Pierre Glaser
Date: Fri, 17 May 2019 20:20:07 +0200
Subject: [PATCH 092/199] bpo-36867: _test_multiprocessing: avoid weak sync
primitive (GH-13292)
Avoid weak sync primitive in multiprocessing resource_tracker test.
---
Lib/test/_test_multiprocessing.py | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index 772c9638337..78ec53beb0f 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -3945,11 +3945,19 @@ def test_shared_memory_cleaned_after_process_termination(self):
# segment should not leak the given memory segment.
p.terminate()
p.wait()
- time.sleep(1.0) # wait for the OS to collect the segment
- # The shared memory file was deleted.
- with self.assertRaises(FileNotFoundError):
- smm = shared_memory.SharedMemory(name, create=False)
+ deadline = time.monotonic() + 60
+ t = 0.1
+ while time.monotonic() < deadline:
+ time.sleep(t)
+ t = min(t*2, 5)
+ try:
+ smm = shared_memory.SharedMemory(name, create=False)
+ except FileNotFoundError:
+ break
+ else:
+ raise AssertionError("A SharedMemory segment was leaked after"
+ " a process was abruptly terminated.")
if os.name == 'posix':
# A warning was emitted by the subprocess' own
From feac6cd7753425fba006e97e2d9b74a0c0c75894 Mon Sep 17 00:00:00 2001
From: Abhilash Raj
Date: Fri, 17 May 2019 12:28:44 -0700
Subject: [PATCH 093/199] bpo-33524: Fix the folding of email header when
max_line_length is 0 or None (#13391)
and there are non-ascii characters in the header.
---
Lib/email/_header_value_parser.py | 3 ++-
Lib/email/policy.py | 3 ++-
Lib/test/test_email/test_policy.py | 13 +++++++++++++
.../2019-05-17-11-44-21.bpo-33524.8y_xUU.rst | 3 +++
4 files changed, 20 insertions(+), 2 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-17-11-44-21.bpo-33524.8y_xUU.rst
diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py
index 60d0d32059f..649f1539fa0 100644
--- a/Lib/email/_header_value_parser.py
+++ b/Lib/email/_header_value_parser.py
@@ -68,6 +68,7 @@
"""
import re
+import sys
import urllib # For urllib.parse.unquote
from string import hexdigits
from operator import itemgetter
@@ -2590,7 +2591,7 @@ def _refold_parse_tree(parse_tree, *, policy):
"""
# max_line_length 0/None means no limit, ie: infinitely long.
- maxlen = policy.max_line_length or float("+inf")
+ maxlen = policy.max_line_length or sys.maxsize
encoding = 'utf-8' if policy.utf8 else 'us-ascii'
lines = ['']
last_ew = None
diff --git a/Lib/email/policy.py b/Lib/email/policy.py
index 5131311ac5e..611deb50bb5 100644
--- a/Lib/email/policy.py
+++ b/Lib/email/policy.py
@@ -3,6 +3,7 @@
"""
import re
+import sys
from email._policybase import Policy, Compat32, compat32, _extend_docstrings
from email.utils import _has_surrogates
from email.headerregistry import HeaderRegistry as HeaderRegistry
@@ -203,7 +204,7 @@ def fold_binary(self, name, value):
def _fold(self, name, value, refold_binary=False):
if hasattr(value, 'name'):
return value.fold(policy=self)
- maxlen = self.max_line_length if self.max_line_length else float('inf')
+ maxlen = self.max_line_length if self.max_line_length else sys.maxsize
lines = value.splitlines()
refold = (self.refold_source == 'all' or
self.refold_source == 'long' and
diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py
index c2c437e6ac2..0aea934df43 100644
--- a/Lib/test/test_email/test_policy.py
+++ b/Lib/test/test_email/test_policy.py
@@ -1,4 +1,5 @@
import io
+import sys
import types
import textwrap
import unittest
@@ -134,6 +135,18 @@ def test_policy_addition(self):
for attr, value in expected.items():
self.assertEqual(getattr(added, attr), value)
+ def test_fold_zero_max_line_length(self):
+ expected = 'Subject: =?utf-8?q?=C3=A1?=\n'
+
+ msg = email.message.EmailMessage()
+ msg['Subject'] = 'á'
+
+ p1 = email.policy.default.clone(max_line_length=0)
+ p2 = email.policy.default.clone(max_line_length=None)
+
+ self.assertEqual(p1.fold('Subject', msg['Subject']), expected)
+ self.assertEqual(p2.fold('Subject', msg['Subject']), expected)
+
def test_register_defect(self):
class Dummy:
def __init__(self):
diff --git a/Misc/NEWS.d/next/Library/2019-05-17-11-44-21.bpo-33524.8y_xUU.rst b/Misc/NEWS.d/next/Library/2019-05-17-11-44-21.bpo-33524.8y_xUU.rst
new file mode 100644
index 00000000000..bfeab7231bd
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-17-11-44-21.bpo-33524.8y_xUU.rst
@@ -0,0 +1,3 @@
+Fix the folding of email header when the max_line_length is 0 or None and the
+header contains non-ascii characters. Contributed by Licht Takeuchi
+(@Licht-T).
From 98ff4d5fb6a9d01b0176b7786db61346952e5295 Mon Sep 17 00:00:00 2001
From: Edison A <20975616+SimiCode@users.noreply.github.com>
Date: Fri, 17 May 2019 13:28:42 -0700
Subject: [PATCH 094/199] bpo-36782: Created C API wrappers and added missing
tests for functions in the PyDateTimeAPI. (#13088)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* created a c API wrapper for pyDate_FromDate and added the test
* 📜🤖 Added by blurb_it.
* fixed auto-alignment by vscode
* made changes as per PEP7
* Update 2019-05-04-21-25-19.bpo-36782.h3oPIb.rst
* Refactored code as per requested changes
* Remove Whitespace to Fix failed travis build
* Update 2019-05-04-21-25-19.bpo-36782.h3oPIb.rst
* Add a new line at end of ACKS
* Added C API function for PyDateTime_FromDateAndTime
* Added a test for the C API wrapper of PyDateTime_FromDateAndTime
* Added C API function for PyDateTime_FromDateAndTime
* Added a test for the C API wrapper of PyDateTime_FromDateAndTimeAndFold
* Remove Whitespace using patchcheck
* Added a C API function for PyTime_FromTime
* Added a test for the C API wrapper of PyTime_FromTime
* Added a C API function for PyTime_FromTimeAndFold
* Added a test for the C API wrapper of PyTime_FromTimeAndFold
* Added a C API function for PyDelta_FromDSU
* Added a test for the C API wrapper of PyDelta_FromDSU
* Refactor code, re-edit lines longer than 80 chars
* Fix Whitespace issues in DatetimeTester
* List all tests that were added in this PR
* Update 2019-05-04-21-25-19.bpo-36782.h3oPIb.rst
* Reformat code as per PEP7 guidelines
* Remove unused varibles from another function
* Added specific tests for the Fold Attribute
* Update 2019-05-04-21-25-19.bpo-36782.h3oPIb.rst
* Reformat code according to requested changes
* Reformat code to PEP7 Guidelines
* Reformat code to PEP7 Guidelines
* Re-add name to blurb
* Added a backtick to blurb file
* Update 2019-05-04-21-25-19.bpo-36782.h3oPIb.rst
* Remove the need to initialize mandatory parameters
* Make the macro parameter mandatory
* Re-arrange the order of unit-test args
* Removed the need to initialize macro
change all the int macro = 0 to int macro; now that macro is required
Co-Authored-By: Paul Ganssle
* Removed the need to initialize macro
change all the `int macro = 0` to `int macro`; now that macro is required
Co-Authored-By: Paul Ganssle
* Removed the need to initialize macro
change all the `int macro = 0` to `int macro`; now that macro is required
Co-Authored-By: Paul Ganssle
* Removed the need to initialize macro
change all the `int macro = 0` to `int macro`; now that macro is required
Co-Authored-By: Paul Ganssle
* Removed the need to initialize macro
change all the `int macro = 0` to `int macro`; now that macro is required
Co-Authored-By: Paul Ganssle
* Removed the need to initialize macro
change all the `int macro = 0` to `int macro`; now that macro is required
Co-Authored-By: Paul Ganssle
---
Lib/test/datetimetester.py | 97 +++++++++-
Misc/ACKS | 1 +
.../2019-05-04-21-25-19.bpo-36782.h3oPIb.rst | 1 +
Modules/_testcapimodule.c | 170 +++++++++++++++++-
4 files changed, 265 insertions(+), 4 deletions(-)
create mode 100644 Misc/NEWS.d/next/Tests/2019-05-04-21-25-19.bpo-36782.h3oPIb.rst
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index af0047fafd8..239a0b5ac83 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -6018,6 +6018,100 @@ class TZInfoSubclass(tzinfo):
with self.subTest(arg=arg, exact=exact):
self.assertFalse(is_tzinfo(arg, exact))
+ def test_date_from_date(self):
+ exp_date = date(1993, 8, 26)
+
+ for macro in [0, 1]:
+ with self.subTest(macro=macro):
+ c_api_date = _testcapi.get_date_fromdate(
+ macro,
+ exp_date.year,
+ exp_date.month,
+ exp_date.day)
+
+ self.assertEqual(c_api_date, exp_date)
+
+ def test_datetime_from_dateandtime(self):
+ exp_date = datetime(1993, 8, 26, 22, 12, 55, 99999)
+
+ for macro in [0, 1]:
+ with self.subTest(macro=macro):
+ c_api_date = _testcapi.get_datetime_fromdateandtime(
+ macro,
+ exp_date.year,
+ exp_date.month,
+ exp_date.day,
+ exp_date.hour,
+ exp_date.minute,
+ exp_date.second,
+ exp_date.microsecond)
+
+ self.assertEqual(c_api_date, exp_date)
+
+ def test_datetime_from_dateandtimeandfold(self):
+ exp_date = datetime(1993, 8, 26, 22, 12, 55, 99999)
+
+ for fold in [0, 1]:
+ for macro in [0, 1]:
+ with self.subTest(macro=macro, fold=fold):
+ c_api_date = _testcapi.get_datetime_fromdateandtimeandfold(
+ macro,
+ exp_date.year,
+ exp_date.month,
+ exp_date.day,
+ exp_date.hour,
+ exp_date.minute,
+ exp_date.second,
+ exp_date.microsecond,
+ exp_date.fold)
+
+ self.assertEqual(c_api_date, exp_date)
+ self.assertEqual(c_api_date.fold, exp_date.fold)
+
+ def test_time_from_time(self):
+ exp_time = time(22, 12, 55, 99999)
+
+ for macro in [0, 1]:
+ with self.subTest(macro=macro):
+ c_api_time = _testcapi.get_time_fromtime(
+ macro,
+ exp_time.hour,
+ exp_time.minute,
+ exp_time.second,
+ exp_time.microsecond)
+
+ self.assertEqual(c_api_time, exp_time)
+
+ def test_time_from_timeandfold(self):
+ exp_time = time(22, 12, 55, 99999)
+
+ for fold in [0, 1]:
+ for macro in [0, 1]:
+ with self.subTest(macro=macro, fold=fold):
+ c_api_time = _testcapi.get_time_fromtimeandfold(
+ macro,
+ exp_time.hour,
+ exp_time.minute,
+ exp_time.second,
+ exp_time.microsecond,
+ exp_time.fold)
+
+ self.assertEqual(c_api_time, exp_time)
+ self.assertEqual(c_api_time.fold, exp_time.fold)
+
+ def test_delta_from_dsu(self):
+ exp_delta = timedelta(26, 55, 99999)
+
+ for macro in [0, 1]:
+ with self.subTest(macro=macro):
+ c_api_delta = _testcapi.get_delta_fromdsu(
+ macro,
+ exp_delta.days,
+ exp_delta.seconds,
+ exp_delta.microseconds)
+
+ self.assertEqual(c_api_delta, exp_delta)
+
def test_date_from_timestamp(self):
ts = datetime(1995, 4, 12).timestamp()
@@ -6028,9 +6122,6 @@ def test_date_from_timestamp(self):
self.assertEqual(d, date(1995, 4, 12))
def test_datetime_from_timestamp(self):
- ts0 = datetime(1995, 4, 12).timestamp()
- ts1 = datetime(1995, 4, 12, 12, 30).timestamp()
-
cases = [
((1995, 4, 12), None, False),
((1995, 4, 12), None, True),
diff --git a/Misc/ACKS b/Misc/ACKS
index 06e288dfcb2..8b3232551e1 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1857,3 +1857,4 @@ Peter Ã…strand
Zheao Li
Carsten Klein
Diego Rojas
+Edison Abahurire
diff --git a/Misc/NEWS.d/next/Tests/2019-05-04-21-25-19.bpo-36782.h3oPIb.rst b/Misc/NEWS.d/next/Tests/2019-05-04-21-25-19.bpo-36782.h3oPIb.rst
new file mode 100644
index 00000000000..222fb386ca7
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2019-05-04-21-25-19.bpo-36782.h3oPIb.rst
@@ -0,0 +1 @@
+Add tests for several C API functions in the :mod:`datetime` module. Patch by Edison Abahurire.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 59b42df279c..2af553960cc 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2340,6 +2340,168 @@ get_timezone_utc_capi(PyObject* self, PyObject *args) {
}
}
+static PyObject *
+get_date_fromdate(PyObject *self, PyObject *args)
+{
+ PyObject *rv = NULL;
+ int macro;
+ int year, month, day;
+
+ if (!PyArg_ParseTuple(args, "piii", ¯o, &year, &month, &day)) {
+ return NULL;
+ }
+
+ if (macro) {
+ rv = PyDate_FromDate(year, month, day);
+ }
+ else {
+ rv = PyDateTimeAPI->Date_FromDate(
+ year, month, day,
+ PyDateTimeAPI->DateType);
+ }
+ return rv;
+}
+
+static PyObject *
+get_datetime_fromdateandtime(PyObject *self, PyObject *args)
+{
+ PyObject *rv = NULL;
+ int macro;
+ int year, month, day;
+ int hour, minute, second, microsecond;
+
+ if (!PyArg_ParseTuple(args, "piiiiiii",
+ ¯o,
+ &year, &month, &day,
+ &hour, &minute, &second, µsecond)) {
+ return NULL;
+ }
+
+ if (macro) {
+ rv = PyDateTime_FromDateAndTime(
+ year, month, day,
+ hour, minute, second, microsecond);
+ }
+ else {
+ rv = PyDateTimeAPI->DateTime_FromDateAndTime(
+ year, month, day,
+ hour, minute, second, microsecond,
+ Py_None,
+ PyDateTimeAPI->DateTimeType);
+ }
+ return rv;
+}
+
+static PyObject *
+get_datetime_fromdateandtimeandfold(PyObject *self, PyObject *args)
+{
+ PyObject *rv = NULL;
+ int macro;
+ int year, month, day;
+ int hour, minute, second, microsecond, fold;
+
+ if (!PyArg_ParseTuple(args, "piiiiiiii",
+ ¯o,
+ &year, &month, &day,
+ &hour, &minute, &second, µsecond,
+ &fold)) {
+ return NULL;
+ }
+
+ if (macro) {
+ rv = PyDateTime_FromDateAndTimeAndFold(
+ year, month, day,
+ hour, minute, second, microsecond,
+ fold);
+ }
+ else {
+ rv = PyDateTimeAPI->DateTime_FromDateAndTimeAndFold(
+ year, month, day,
+ hour, minute, second, microsecond,
+ Py_None,
+ fold,
+ PyDateTimeAPI->DateTimeType);
+ }
+ return rv;
+}
+
+static PyObject *
+get_time_fromtime(PyObject *self, PyObject *args)
+{
+ PyObject *rv = NULL;
+ int macro;
+ int hour, minute, second, microsecond;
+
+ if (!PyArg_ParseTuple(args, "piiii",
+ ¯o,
+ &hour, &minute, &second, µsecond)) {
+ return NULL;
+ }
+
+ if (macro) {
+ rv = PyTime_FromTime(hour, minute, second, microsecond);
+ }
+ else {
+ rv = PyDateTimeAPI->Time_FromTime(
+ hour, minute, second, microsecond,
+ Py_None,
+ PyDateTimeAPI->TimeType);
+ }
+ return rv;
+}
+
+static PyObject *
+get_time_fromtimeandfold(PyObject *self, PyObject *args)
+{
+ PyObject *rv = NULL;
+ int macro;
+ int hour, minute, second, microsecond, fold;
+
+ if (!PyArg_ParseTuple(args, "piiiii",
+ ¯o,
+ &hour, &minute, &second, µsecond,
+ &fold)) {
+ return NULL;
+ }
+
+ if (macro) {
+ rv = PyTime_FromTimeAndFold(hour, minute, second, microsecond, fold);
+ }
+ else {
+ rv = PyDateTimeAPI->Time_FromTimeAndFold(
+ hour, minute, second, microsecond,
+ Py_None,
+ fold,
+ PyDateTimeAPI->TimeType);
+ }
+ return rv;
+}
+
+static PyObject *
+get_delta_fromdsu(PyObject *self, PyObject *args)
+{
+ PyObject *rv = NULL;
+ int macro;
+ int days, seconds, microseconds;
+
+ if (!PyArg_ParseTuple(args, "piii",
+ ¯o,
+ &days, &seconds, µseconds)) {
+ return NULL;
+ }
+
+ if (macro) {
+ rv = PyDelta_FromDSU(days, seconds, microseconds);
+ }
+ else {
+ rv = PyDateTimeAPI->Delta_FromDelta(
+ days, seconds, microseconds, 1,
+ PyDateTimeAPI->DeltaType);
+ }
+
+ return rv;
+}
+
static PyObject *
get_date_fromtimestamp(PyObject* self, PyObject *args)
{
@@ -4826,7 +4988,7 @@ static PyMethodDef TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
{"test_sizeof_c_types", test_sizeof_c_types, METH_NOARGS},
- {"test_datetime_capi", test_datetime_capi, METH_NOARGS},
+ {"test_datetime_capi", test_datetime_capi, METH_NOARGS},
{"datetime_check_date", datetime_check_date, METH_VARARGS},
{"datetime_check_time", datetime_check_time, METH_VARARGS},
{"datetime_check_datetime", datetime_check_datetime, METH_VARARGS},
@@ -4835,6 +4997,12 @@ static PyMethodDef TestMethods[] = {
{"make_timezones_capi", make_timezones_capi, METH_NOARGS},
{"get_timezones_offset_zero", get_timezones_offset_zero, METH_NOARGS},
{"get_timezone_utc_capi", get_timezone_utc_capi, METH_VARARGS},
+ {"get_date_fromdate", get_date_fromdate, METH_VARARGS},
+ {"get_datetime_fromdateandtime", get_datetime_fromdateandtime, METH_VARARGS},
+ {"get_datetime_fromdateandtimeandfold", get_datetime_fromdateandtimeandfold, METH_VARARGS},
+ {"get_time_fromtime", get_time_fromtime, METH_VARARGS},
+ {"get_time_fromtimeandfold", get_time_fromtimeandfold, METH_VARARGS},
+ {"get_delta_fromdsu", get_delta_fromdsu, METH_VARARGS},
{"get_date_fromtimestamp", get_date_fromtimestamp, METH_VARARGS},
{"get_datetime_fromtimestamp", get_datetime_fromtimestamp, METH_VARARGS},
{"test_list_api", test_list_api, METH_NOARGS},
From bcfbbd704646622e919c1306a91fba61d603483d Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Fri, 17 May 2019 22:44:16 +0200
Subject: [PATCH 095/199] bpo-36945: Add _PyPreConfig.configure_locale
(GH-13368)
_PyPreConfig_InitIsolatedConfig() sets configure_locale to 0 to
prevent Python to modify the LC_CTYPE locale. In that case,
coerce_c_locale an coerce_c_locale_warn are set to 0 as well.
---
Include/cpython/coreconfig.h | 5 +++++
Lib/test/test_embed.py | 34 ++++++++++++++++++++++++++++++----
Programs/_testembed.c | 28 ++++++++++++++++++++++++++++
Python/preconfig.c | 25 +++++++++++++++++++------
4 files changed, 82 insertions(+), 10 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index 7d561ceb3ee..73861a96d77 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -79,6 +79,10 @@ typedef struct {
set to !Py_IgnoreEnvironmentFlag. */
int use_environment;
+ /* Set the LC_CTYPE locale to the user preferred locale? If equals to 0,
+ set coerce_c_locale and coerce_c_locale_warn to 0. */
+ int configure_locale;
+
/* Coerce the LC_CTYPE locale if it's equal to "C"? (PEP 538)
Set to 0 by PYTHONCOERCECLOCALE=0. Set to 1 by PYTHONCOERCECLOCALE=1.
@@ -147,6 +151,7 @@ typedef struct {
._config_version = _Py_CONFIG_VERSION, \
.isolated = -1, \
.use_environment = -1, \
+ .configure_locale = 1, \
.utf8_mode = -2, \
.dev_mode = -1, \
.allocator = PYMEM_ALLOCATOR_NOT_SET}
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 50badd8e585..c389df85fb6 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -272,10 +272,15 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
maxDiff = 4096
UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape')
- # Mark config which should be get by get_default_config()
+ # Marker to read the default configuration: get_default_config()
GET_DEFAULT_CONFIG = object()
+
+ # Marker to ignore a configuration parameter
+ IGNORE_CONFIG = object()
+
DEFAULT_PRE_CONFIG = {
'allocator': PYMEM_ALLOCATOR_NOT_SET,
+ 'configure_locale': 1,
'coerce_c_locale': 0,
'coerce_c_locale_warn': 0,
'utf8_mode': 0,
@@ -405,7 +410,7 @@ def main_xoptions(self, xoptions_list):
xoptions[opt] = True
return xoptions
- def get_expected_config(self, expected, env, add_path=None):
+ def get_expected_config(self, expected_preconfig, expected, env, add_path=None):
expected = dict(self.DEFAULT_CORE_CONFIG, **expected)
code = textwrap.dedent('''
@@ -471,6 +476,14 @@ def get_expected_config(self, expected, env, add_path=None):
if add_path is not None:
expected['module_search_paths'].append(add_path)
+
+ if not expected_preconfig['configure_locale']:
+ # there is no easy way to get the locale encoding before
+ # setlocale(LC_CTYPE, "") is called: don't test encodings
+ for key in ('filesystem_encoding', 'filesystem_errors',
+ 'stdio_encoding', 'stdio_errors'):
+ expected[key] = self.IGNORE_CONFIG
+
return expected
def check_pre_config(self, config, expected):
@@ -480,6 +493,10 @@ def check_pre_config(self, config, expected):
def check_core_config(self, config, expected):
core_config = dict(config['core_config'])
+ for key, value in list(expected.items()):
+ if value is self.IGNORE_CONFIG:
+ del core_config[key]
+ del expected[key]
self.assertEqual(core_config, expected)
def check_global_config(self, config):
@@ -517,7 +534,7 @@ def check_config(self, testname, expected_config, expected_preconfig,
env['PYTHONUTF8'] = '0'
expected_preconfig = dict(self.DEFAULT_PRE_CONFIG, **expected_preconfig)
- expected_config = self.get_expected_config(expected_config, env, add_path)
+ expected_config = self.get_expected_config(expected_preconfig, expected_config, env, add_path)
for key in self.COPY_PRE_CONFIG:
if key not in expected_preconfig:
expected_preconfig[key] = expected_config[key]
@@ -692,7 +709,9 @@ def test_preinit_isolated2(self):
self.check_config("preinit_isolated2", config, preconfig)
def test_init_isolated_config(self):
- preconfig = {}
+ preconfig = {
+ 'configure_locale': 0,
+ }
config = {
'isolated': 1,
'use_environment': 0,
@@ -710,6 +729,13 @@ def test_init_python_config(self):
}
self.check_config("init_python_config", config, preconfig)
+ def test_init_dont_configure_locale(self):
+ # _PyPreConfig.configure_locale=0
+ preconfig = {
+ 'configure_locale': 0,
+ }
+ self.check_config("init_dont_configure_locale", {}, preconfig)
+
def test_init_read_set(self):
preconfig = {}
core_config = {
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index e6896966f53..000b2fcec98 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -788,6 +788,33 @@ static int init_python_config(void)
}
+static int init_dont_configure_locale(void)
+{
+ _PyInitError err;
+
+ _PyPreConfig preconfig = _PyPreConfig_INIT;
+ preconfig.configure_locale = 0;
+ preconfig.coerce_c_locale = 1;
+ preconfig.coerce_c_locale_warn = 1;
+
+ err = _Py_PreInitialize(&preconfig);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+
+ _PyCoreConfig config = _PyCoreConfig_INIT;
+ config.program_name = L"./_testembed";
+ err = _Py_InitializeFromConfig(&config);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+
+ dump_config();
+ Py_Finalize();
+ return 0;
+}
+
+
static int init_dev_mode(void)
{
_PyCoreConfig config;
@@ -966,6 +993,7 @@ static struct TestCase TestCases[] = {
{ "init_env", test_init_env },
{ "init_env_dev_mode", test_init_env_dev_mode },
{ "init_env_dev_mode_alloc", test_init_env_dev_mode_alloc },
+ { "init_dont_configure_locale", init_dont_configure_locale },
{ "init_dev_mode", init_dev_mode },
{ "init_isolated_flag", init_isolated_flag },
{ "init_isolated_config", init_isolated_config },
diff --git a/Python/preconfig.c b/Python/preconfig.c
index 7814ee08a63..985af39cb00 100644
--- a/Python/preconfig.c
+++ b/Python/preconfig.c
@@ -286,6 +286,7 @@ _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config)
{
_PyPreConfig_Init(config);
+ config->configure_locale = 0;
config->isolated = 1;
config->use_environment = 0;
#ifdef MS_WINDOWS
@@ -312,6 +313,7 @@ _PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
COPY_ATTR(isolated);
COPY_ATTR(use_environment);
+ COPY_ATTR(configure_locale);
COPY_ATTR(dev_mode);
COPY_ATTR(coerce_c_locale);
COPY_ATTR(coerce_c_locale_warn);
@@ -360,6 +362,7 @@ _PyPreConfig_AsDict(const _PyPreConfig *config)
SET_ITEM_INT(isolated);
SET_ITEM_INT(use_environment);
+ SET_ITEM_INT(configure_locale);
SET_ITEM_INT(coerce_c_locale);
SET_ITEM_INT(coerce_c_locale_warn);
SET_ITEM_INT(utf8_mode);
@@ -603,6 +606,12 @@ preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
static void
preconfig_init_coerce_c_locale(_PyPreConfig *config)
{
+ if (!config->configure_locale) {
+ config->coerce_c_locale = 0;
+ config->coerce_c_locale_warn = 0;
+ return;
+ }
+
const char *env = _Py_GetEnv(config->use_environment, "PYTHONCOERCECLOCALE");
if (env) {
if (strcmp(env, "0") == 0) {
@@ -746,7 +755,9 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
}
/* Set LC_CTYPE to the user preferred locale */
- _Py_SetLocaleFromEnv(LC_CTYPE);
+ if (config->configure_locale) {
+ _Py_SetLocaleFromEnv(LC_CTYPE);
+ }
_PyPreCmdline cmdline = _PyPreCmdline_INIT;
int init_utf8_mode = Py_UTF8Mode;
@@ -879,12 +890,14 @@ _PyPreConfig_Write(const _PyPreConfig *config)
_PyPreConfig_SetGlobalConfig(config);
- if (config->coerce_c_locale) {
- _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
- }
+ if (config->configure_locale) {
+ if (config->coerce_c_locale) {
+ _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
+ }
- /* Set LC_CTYPE to the user preferred locale */
- _Py_SetLocaleFromEnv(LC_CTYPE);
+ /* Set LC_CTYPE to the user preferred locale */
+ _Py_SetLocaleFromEnv(LC_CTYPE);
+ }
/* Write the new pre-configuration into _PyRuntime */
PyMemAllocatorEx old_alloc;
From 12083284c54be25abadd85781d36b63731dc1f0c Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Fri, 17 May 2019 23:05:29 +0200
Subject: [PATCH 096/199] bpo-36763: _Py_RunMain() doesn't call Py_Exit()
anymore (GH-13390)
Py_Main() and _Py_RunMain() now return the exitcode rather than
calling Py_Exit(exitcode) when calling PyErr_Print() if the current
exception type is SystemExit.
* Add _Py_HandleSystemExit().
* Add pymain_exit_err_print().
* Add pymain_exit_print().
---
Include/internal/pycore_pylifecycle.h | 2 +
.../2019-05-17-19-23-24.bpo-36763.TswmDy.rst | 3 +
Modules/main.c | 123 +++++++++++-------
Python/pythonrun.c | 52 +++++---
4 files changed, 117 insertions(+), 63 deletions(-)
create mode 100644 Misc/NEWS.d/next/C API/2019-05-17-19-23-24.bpo-36763.TswmDy.rst
diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h
index 0d83acdf28a..4684ebea44a 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -100,6 +100,8 @@ PyAPI_FUNC(_PyInitError) _Py_PreInitializeFromCoreConfig(
const _PyCoreConfig *coreconfig,
const _PyArgv *args);
+PyAPI_FUNC(int) _Py_HandleSystemExit(int *exitcode_p);
+
#ifdef __cplusplus
}
#endif
diff --git a/Misc/NEWS.d/next/C API/2019-05-17-19-23-24.bpo-36763.TswmDy.rst b/Misc/NEWS.d/next/C API/2019-05-17-19-23-24.bpo-36763.TswmDy.rst
new file mode 100644
index 00000000000..29c016600db
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2019-05-17-19-23-24.bpo-36763.TswmDy.rst
@@ -0,0 +1,3 @@
+``Py_Main()`` now returns the exitcode rather than calling
+``Py_Exit(exitcode)`` when calling ``PyErr_Print()`` if the current
+exception type is ``SystemExit``.
diff --git a/Modules/main.c b/Modules/main.c
index 72546a21cac..6d4b351e5e1 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -94,8 +94,34 @@ stdin_is_interactive(const _PyCoreConfig *config)
}
-static PyObject *
-pymain_get_importer(const wchar_t *filename)
+/* Display the current Python exception and return an exitcode */
+static int
+pymain_err_print(int *exitcode_p)
+{
+ int exitcode;
+ if (_Py_HandleSystemExit(&exitcode)) {
+ *exitcode_p = exitcode;
+ return 1;
+ }
+
+ PyErr_Print();
+ return 0;
+}
+
+
+static int
+pymain_exit_err_print(void)
+{
+ int exitcode = 1;
+ pymain_err_print(&exitcode);
+ return exitcode;
+}
+
+
+/* Write an exitcode into *exitcode and return 1 if we have to exit Python.
+ Return 0 otherwise. */
+static int
+pymain_get_importer(const wchar_t *filename, PyObject **importer_p, int *exitcode)
{
PyObject *sys_path0 = NULL, *importer;
@@ -112,17 +138,18 @@ pymain_get_importer(const wchar_t *filename)
if (importer == Py_None) {
Py_DECREF(sys_path0);
Py_DECREF(importer);
- return NULL;
+ return 0;
}
Py_DECREF(importer);
- return sys_path0;
+ *importer_p = sys_path0;
+ return 0;
error:
Py_XDECREF(sys_path0);
+
PySys_WriteStderr("Failed checking if argv[0] is an import path entry\n");
- PyErr_Print();
- return NULL;
+ return pymain_err_print(exitcode);
}
@@ -217,8 +244,7 @@ pymain_run_command(wchar_t *command, PyCompilerFlags *cf)
error:
PySys_WriteStderr("Unable to decode the command from the command line:\n");
- PyErr_Print();
- return 1;
+ return pymain_exit_err_print();
}
@@ -229,44 +255,37 @@ pymain_run_module(const wchar_t *modname, int set_argv0)
runpy = PyImport_ImportModule("runpy");
if (runpy == NULL) {
fprintf(stderr, "Could not import runpy module\n");
- PyErr_Print();
- return -1;
+ return pymain_exit_err_print();
}
runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main");
if (runmodule == NULL) {
fprintf(stderr, "Could not access runpy._run_module_as_main\n");
- PyErr_Print();
Py_DECREF(runpy);
- return -1;
+ return pymain_exit_err_print();
}
module = PyUnicode_FromWideChar(modname, wcslen(modname));
if (module == NULL) {
fprintf(stderr, "Could not convert module name to unicode\n");
- PyErr_Print();
Py_DECREF(runpy);
Py_DECREF(runmodule);
- return -1;
+ return pymain_exit_err_print();
}
runargs = Py_BuildValue("(Oi)", module, set_argv0);
if (runargs == NULL) {
fprintf(stderr,
"Could not create arguments for runpy._run_module_as_main\n");
- PyErr_Print();
Py_DECREF(runpy);
Py_DECREF(runmodule);
Py_DECREF(module);
- return -1;
+ return pymain_exit_err_print();
}
result = PyObject_Call(runmodule, runargs, NULL);
- if (result == NULL) {
- PyErr_Print();
- }
Py_DECREF(runpy);
Py_DECREF(runmodule);
Py_DECREF(module);
Py_DECREF(runargs);
if (result == NULL) {
- return -1;
+ return pymain_exit_err_print();
}
Py_DECREF(result);
return 0;
@@ -315,9 +334,8 @@ pymain_run_file(_PyCoreConfig *config, PyCompilerFlags *cf)
/* call pending calls like signal handlers (SIGINT) */
if (Py_MakePendingCalls() == -1) {
- PyErr_Print();
fclose(fp);
- return 1;
+ return pymain_exit_err_print();
}
PyObject *unicode, *bytes = NULL;
@@ -343,34 +361,36 @@ pymain_run_file(_PyCoreConfig *config, PyCompilerFlags *cf)
}
-static void
-pymain_run_startup(_PyCoreConfig *config, PyCompilerFlags *cf)
+static int
+pymain_run_startup(_PyCoreConfig *config, PyCompilerFlags *cf, int *exitcode)
{
const char *startup = _Py_GetEnv(config->use_environment, "PYTHONSTARTUP");
if (startup == NULL) {
- return;
+ return 0;
}
FILE *fp = _Py_fopen(startup, "r");
if (fp == NULL) {
int save_errno = errno;
PySys_WriteStderr("Could not open PYTHONSTARTUP\n");
- errno = save_errno;
- PyErr_SetFromErrnoWithFilename(PyExc_OSError,
- startup);
- PyErr_Print();
- return;
+ errno = save_errno;
+ PyErr_SetFromErrnoWithFilename(PyExc_OSError, startup);
+
+ return pymain_err_print(exitcode);
}
(void) PyRun_SimpleFileExFlags(fp, startup, 0, cf);
PyErr_Clear();
fclose(fp);
+ return 0;
}
-static void
-pymain_run_interactive_hook(void)
+/* Write an exitcode into *exitcode and return 1 if we have to exit Python.
+ Return 0 otherwise. */
+static int
+pymain_run_interactive_hook(int *exitcode)
{
PyObject *sys, *hook, *result;
sys = PyImport_ImportModule("sys");
@@ -382,7 +402,7 @@ pymain_run_interactive_hook(void)
Py_DECREF(sys);
if (hook == NULL) {
PyErr_Clear();
- return;
+ return 0;
}
result = _PyObject_CallNoArg(hook);
@@ -392,11 +412,11 @@ pymain_run_interactive_hook(void)
}
Py_DECREF(result);
- return;
+ return 0;
error:
PySys_WriteStderr("Failed calling sys.__interactivehook__\n");
- PyErr_Print();
+ return pymain_err_print(exitcode);
}
@@ -406,14 +426,20 @@ pymain_run_stdin(_PyCoreConfig *config, PyCompilerFlags *cf)
if (stdin_is_interactive(config)) {
config->inspect = 0;
Py_InspectFlag = 0; /* do exit on SystemExit */
- pymain_run_startup(config, cf);
- pymain_run_interactive_hook();
+
+ int exitcode;
+ if (pymain_run_startup(config, cf, &exitcode)) {
+ return exitcode;
+ }
+
+ if (pymain_run_interactive_hook(&exitcode)) {
+ return exitcode;
+ }
}
/* call pending calls like signal handlers (SIGINT) */
if (Py_MakePendingCalls() == -1) {
- PyErr_Print();
- return 1;
+ return pymain_exit_err_print();
}
int run = PyRun_AnyFileExFlags(stdin, "", 0, cf);
@@ -437,7 +463,9 @@ pymain_repl(_PyCoreConfig *config, PyCompilerFlags *cf, int *exitcode)
config->inspect = 0;
Py_InspectFlag = 0;
- pymain_run_interactive_hook();
+ if (pymain_run_interactive_hook(exitcode)) {
+ return;
+ }
int res = PyRun_AnyFileFlags(stdin, "", cf);
*exitcode = (res != 0);
@@ -457,8 +485,11 @@ pymain_run_python(int *exitcode)
__main__.py, main_importer_path is set to filename and will be
prepended to sys.path.
- Otherwise, main_importer_path is set to NULL. */
- main_importer_path = pymain_get_importer(config->run_filename);
+ Otherwise, main_importer_path is left unchanged. */
+ if (pymain_get_importer(config->run_filename, &main_importer_path,
+ exitcode)) {
+ return;
+ }
}
if (main_importer_path != NULL) {
@@ -491,11 +522,10 @@ pymain_run_python(int *exitcode)
*exitcode = pymain_run_command(config->run_command, &cf);
}
else if (config->run_module) {
- *exitcode = (pymain_run_module(config->run_module, 1) != 0);
+ *exitcode = pymain_run_module(config->run_module, 1);
}
else if (main_importer_path != NULL) {
- int sts = pymain_run_module(L"__main__", 0);
- *exitcode = (sts != 0);
+ *exitcode = pymain_run_module(L"__main__", 0);
}
else if (config->run_filename != NULL) {
*exitcode = pymain_run_file(config, &cf);
@@ -508,8 +538,7 @@ pymain_run_python(int *exitcode)
goto done;
error:
- PyErr_Print();
- *exitcode = 1;
+ *exitcode = pymain_exit_err_print();
done:
Py_XDECREF(main_importer_path);
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index bc131fd7e5e..d2b27615903 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -585,23 +585,31 @@ print_error_text(PyObject *f, int offset, PyObject *text_obj)
PyFile_WriteString("^\n", f);
}
-static void
-handle_system_exit(void)
-{
- PyObject *exception, *value, *tb;
- int exitcode = 0;
+int
+_Py_HandleSystemExit(int *exitcode_p)
+{
int inspect = _PyInterpreterState_GET_UNSAFE()->core_config.inspect;
if (inspect) {
/* Don't exit if -i flag was given. This flag is set to 0
* when entering interactive mode for inspecting. */
- return;
+ return 0;
}
+ if (!PyErr_ExceptionMatches(PyExc_SystemExit)) {
+ return 0;
+ }
+
+ PyObject *exception, *value, *tb;
PyErr_Fetch(&exception, &value, &tb);
+
fflush(stdout);
- if (value == NULL || value == Py_None)
+
+ int exitcode = 0;
+ if (value == NULL || value == Py_None) {
goto done;
+ }
+
if (PyExceptionInstance_Check(value)) {
/* The error code should be in the `code' attribute. */
_Py_IDENTIFIER(code);
@@ -615,8 +623,10 @@ handle_system_exit(void)
/* If we failed to dig out the 'code' attribute,
just let the else clause below print the error. */
}
- if (PyLong_Check(value))
+
+ if (PyLong_Check(value)) {
exitcode = (int)PyLong_AsLong(value);
+ }
else {
PyObject *sys_stderr = _PySys_GetObjectId(&PyId_stderr);
/* We clear the exception here to avoid triggering the assertion
@@ -633,6 +643,7 @@ handle_system_exit(void)
PySys_WriteStderr("\n");
exitcode = 1;
}
+
done:
/* Restore and clear the exception info, in order to properly decref
* the exception, value, and traceback. If we just exit instead,
@@ -641,18 +652,28 @@ handle_system_exit(void)
*/
PyErr_Restore(exception, value, tb);
PyErr_Clear();
- Py_Exit(exitcode);
- /* NOTREACHED */
+ *exitcode_p = exitcode;
+ return 1;
}
+
+static void
+handle_system_exit(void)
+{
+ int exitcode;
+ if (_Py_HandleSystemExit(&exitcode)) {
+ Py_Exit(exitcode);
+ }
+}
+
+
void
PyErr_PrintEx(int set_sys_last_vars)
{
PyObject *exception, *v, *tb, *hook;
- if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
- handle_system_exit();
- }
+ handle_system_exit();
+
PyErr_Fetch(&exception, &v, &tb);
if (exception == NULL)
return;
@@ -686,10 +707,9 @@ PyErr_PrintEx(int set_sys_last_vars)
stack[2] = tb;
result = _PyObject_FastCall(hook, stack, 3);
if (result == NULL) {
+ handle_system_exit();
+
PyObject *exception2, *v2, *tb2;
- if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
- handle_system_exit();
- }
PyErr_Fetch(&exception2, &v2, &tb2);
PyErr_NormalizeException(&exception2, &v2, &tb2);
/* It should not be possible for exception2 or v2
From 871ff77c1cd334a141d52b0d003c080a1928731e Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Fri, 17 May 2019 23:54:00 +0200
Subject: [PATCH 097/199] bpo-36763: Add _PyInitError functions (GH-13395)
* Add _PyInitError functions:
* _PyInitError_Ok()
* _PyInitError_Error()
* _PyInitError_NoMemory()
* _PyInitError_Exit()
* _PyInitError_IsError()
* _PyInitError_IsExit()
* _PyInitError_Failed()
* frozenmain.c and _testembed.c now use functions rather than macros.
* Move _Py_INIT_xxx() macros to the internal API.
* Move _PyWstrList_INIT macro to the internal API.
---
Include/cpython/coreconfig.h | 37 ++++----------------
Include/internal/pycore_coreconfig.h | 32 +++++++++++++++++
Modules/faulthandler.c | 1 +
Modules/getpath.c | 1 +
Objects/exceptions.c | 1 +
Objects/object.c | 1 +
PC/getpathp.c | 1 +
Programs/_freeze_importlib.c | 2 +-
Programs/_testembed.c | 52 ++++++++++++++--------------
Python/bootstrap_hash.c | 1 +
Python/coreconfig.c | 28 +++++++++++++++
Python/frozenmain.c | 4 +--
12 files changed, 102 insertions(+), 59 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index 73861a96d77..f05eddad912 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -18,34 +18,13 @@ typedef struct {
int exitcode;
} _PyInitError;
-/* Almost all errors causing Python initialization to fail */
-#ifdef _MSC_VER
- /* Visual Studio 2015 doesn't implement C99 __func__ in C */
-# define _Py_INIT_GET_FUNC() __FUNCTION__
-#else
-# define _Py_INIT_GET_FUNC() __func__
-#endif
-
-#define _Py_INIT_OK() \
- (_PyInitError){._type = _Py_INIT_ERR_TYPE_OK,}
- /* other fields are set to 0 */
-#define _Py_INIT_ERR(ERR_MSG) \
- (_PyInitError){ \
- ._type = _Py_INIT_ERR_TYPE_ERROR, \
- ._func = _Py_INIT_GET_FUNC(), \
- .err_msg = (ERR_MSG)}
- /* other fields are set to 0 */
-#define _Py_INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed")
-#define _Py_INIT_EXIT(EXITCODE) \
- (_PyInitError){ \
- ._type = _Py_INIT_ERR_TYPE_EXIT, \
- .exitcode = (EXITCODE)}
-#define _Py_INIT_IS_ERROR(err) \
- (err._type == _Py_INIT_ERR_TYPE_ERROR)
-#define _Py_INIT_IS_EXIT(err) \
- (err._type == _Py_INIT_ERR_TYPE_EXIT)
-#define _Py_INIT_FAILED(err) \
- (err._type != _Py_INIT_ERR_TYPE_OK)
+PyAPI_FUNC(_PyInitError) _PyInitError_Ok(void);
+PyAPI_FUNC(_PyInitError) _PyInitError_Error(const char *err_msg);
+PyAPI_FUNC(_PyInitError) _PyInitError_NoMemory(void);
+PyAPI_FUNC(_PyInitError) _PyInitError_Exit(int exitcode);
+PyAPI_FUNC(int) _PyInitError_IsError(_PyInitError err);
+PyAPI_FUNC(int) _PyInitError_IsExit(_PyInitError err);
+PyAPI_FUNC(int) _PyInitError_Failed(_PyInitError err);
/* --- _PyWstrList ------------------------------------------------ */
@@ -56,8 +35,6 @@ typedef struct {
wchar_t **items;
} _PyWstrList;
-#define _PyWstrList_INIT (_PyWstrList){.length = 0, .items = NULL}
-
/* --- _PyPreConfig ----------------------------------------------- */
diff --git a/Include/internal/pycore_coreconfig.h b/Include/internal/pycore_coreconfig.h
index e9c6d9fee81..80aec21f2c8 100644
--- a/Include/internal/pycore_coreconfig.h
+++ b/Include/internal/pycore_coreconfig.h
@@ -10,9 +10,41 @@ extern "C" {
#include "pycore_pystate.h" /* _PyRuntimeState */
+/* --- _PyInitError ----------------------------------------------- */
+
+/* Almost all errors causing Python initialization to fail */
+#ifdef _MSC_VER
+ /* Visual Studio 2015 doesn't implement C99 __func__ in C */
+# define _Py_INIT_GET_FUNC() __FUNCTION__
+#else
+# define _Py_INIT_GET_FUNC() __func__
+#endif
+
+#define _Py_INIT_OK() \
+ (_PyInitError){._type = _Py_INIT_ERR_TYPE_OK,}
+ /* other fields are set to 0 */
+#define _Py_INIT_ERR(ERR_MSG) \
+ (_PyInitError){ \
+ ._type = _Py_INIT_ERR_TYPE_ERROR, \
+ ._func = _Py_INIT_GET_FUNC(), \
+ .err_msg = (ERR_MSG)}
+ /* other fields are set to 0 */
+#define _Py_INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed")
+#define _Py_INIT_EXIT(EXITCODE) \
+ (_PyInitError){ \
+ ._type = _Py_INIT_ERR_TYPE_EXIT, \
+ .exitcode = (EXITCODE)}
+#define _Py_INIT_IS_ERROR(err) \
+ (err._type == _Py_INIT_ERR_TYPE_ERROR)
+#define _Py_INIT_IS_EXIT(err) \
+ (err._type == _Py_INIT_ERR_TYPE_EXIT)
+#define _Py_INIT_FAILED(err) \
+ (err._type != _Py_INIT_ERR_TYPE_OK)
/* --- _PyWstrList ------------------------------------------------ */
+#define _PyWstrList_INIT (_PyWstrList){.length = 0, .items = NULL}
+
#ifndef NDEBUG
PyAPI_FUNC(int) _PyWstrList_CheckConsistency(const _PyWstrList *list);
#endif
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index 63a9b91ac46..2083a03198f 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -1,4 +1,5 @@
#include "Python.h"
+#include "pycore_coreconfig.h"
#include "pythread.h"
#include
#include
diff --git a/Modules/getpath.c b/Modules/getpath.c
index 34357e47bc2..3dcfcef7bd7 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -1,6 +1,7 @@
/* Return the initial module search path. */
#include "Python.h"
+#include "pycore_coreconfig.h"
#include "osdefs.h"
#include "pycore_fileutils.h"
#include "pycore_pathconfig.h"
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index b40ecb78d45..4dad0b24cee 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -6,6 +6,7 @@
#define PY_SSIZE_T_CLEAN
#include
+#include "pycore_coreconfig.h"
#include "pycore_object.h"
#include "pycore_pymem.h"
#include "pycore_pystate.h"
diff --git a/Objects/object.c b/Objects/object.c
index cb727943cb3..604f5e0d488 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -2,6 +2,7 @@
/* Generic object operations; and implementation of None */
#include "Python.h"
+#include "pycore_coreconfig.h"
#include "pycore_object.h"
#include "pycore_pystate.h"
#include "pycore_context.h"
diff --git a/PC/getpathp.c b/PC/getpathp.c
index 76d3a081b36..64aa1e0d141 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -80,6 +80,7 @@
#include "Python.h"
+#include "pycore_coreconfig.h"
#include "pycore_pystate.h"
#include "osdefs.h"
#include
diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c
index bc29297a6b9..d89d66abee7 100644
--- a/Programs/_freeze_importlib.c
+++ b/Programs/_freeze_importlib.c
@@ -90,7 +90,7 @@ main(int argc, char *argv[])
_PyInitError err = _Py_InitializeFromConfig(&config);
/* No need to call _PyCoreConfig_Clear() since we didn't allocate any
memory: program_name is a constant string. */
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 000b2fcec98..2352179cc6f 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -389,7 +389,7 @@ static int test_init_from_config(void)
preconfig.utf8_mode = 1;
err = _Py_PreInitialize(&preconfig);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
@@ -512,7 +512,7 @@ static int test_init_from_config(void)
config.pathconfig_warnings = 0;
err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
dump_config();
@@ -543,7 +543,7 @@ static int test_init_parse_argv(int parse_argv)
config.parse_argv = parse_argv;
err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
dump_config();
@@ -653,7 +653,7 @@ static int init_isolated_flag(void)
test_init_env_dev_mode_putenvs();
err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
dump_config();
@@ -672,7 +672,7 @@ static int test_preinit_isolated1(void)
preconfig.isolated = 1;
err = _Py_PreInitialize(&preconfig);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
@@ -682,7 +682,7 @@ static int test_preinit_isolated1(void)
test_init_env_dev_mode_putenvs();
err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
dump_config();
@@ -701,7 +701,7 @@ static int test_preinit_isolated2(void)
preconfig.isolated = 0;
err = _Py_PreInitialize(&preconfig);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
@@ -717,7 +717,7 @@ static int test_preinit_isolated2(void)
test_init_env_dev_mode_putenvs();
err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
dump_config();
@@ -734,7 +734,7 @@ static int init_isolated_config(void)
_PyPreConfig_InitIsolatedConfig(&preconfig);
err = _Py_PreInitialize(&preconfig);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
@@ -744,13 +744,13 @@ static int init_isolated_config(void)
_PyCoreConfig config;
err = _PyCoreConfig_InitIsolatedConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
config.program_name = L"./_testembed";
err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
dump_config();
@@ -767,19 +767,19 @@ static int init_python_config(void)
_PyPreConfig_InitPythonConfig(&preconfig);
err = _Py_PreInitialize(&preconfig);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
_PyCoreConfig config;
err = _PyCoreConfig_InitPythonConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
config.program_name = L"./_testembed";
err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
dump_config();
@@ -798,14 +798,14 @@ static int init_dont_configure_locale(void)
preconfig.coerce_c_locale_warn = 1;
err = _Py_PreInitialize(&preconfig);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
_PyCoreConfig config = _PyCoreConfig_INIT;
config.program_name = L"./_testembed";
err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
@@ -824,7 +824,7 @@ static int init_dev_mode(void)
config.dev_mode = 1;
config.program_name = L"./_testembed";
_PyInitError err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
dump_config();
@@ -840,30 +840,30 @@ static int test_init_read_set(void)
_PyCoreConfig_Init(&config);
err = _PyCoreConfig_DecodeLocale(&config.program_name, "./init_read_set");
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
goto fail;
}
err = _PyCoreConfig_Read(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
goto fail;
}
if (_PyWstrList_Append(&config.module_search_paths,
L"init_read_set_path") < 0) {
- err = _Py_INIT_NO_MEMORY();
+ err = _PyInitError_NoMemory();
goto fail;
}
/* override executable computed by _PyCoreConfig_Read() */
err = _PyCoreConfig_SetString(&config.executable, L"my_executable");
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
goto fail;
}
err = _Py_InitializeFromConfig(&config);
_PyCoreConfig_Clear(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
goto fail;
}
dump_config();
@@ -898,7 +898,7 @@ static int test_init_run_main(void)
configure_init_main(&config);
_PyInitError err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
@@ -914,7 +914,7 @@ static int test_init_main(void)
config._init_main = 0;
_PyInitError err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
@@ -928,7 +928,7 @@ static int test_init_main(void)
}
err = _Py_InitializeMain();
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
@@ -951,7 +951,7 @@ static int test_run_main(void)
config.program_name = L"./python3";
_PyInitError err = _Py_InitializeFromConfig(&config);
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c
index dd752b86094..fe71cc388a0 100644
--- a/Python/bootstrap_hash.c
+++ b/Python/bootstrap_hash.c
@@ -1,4 +1,5 @@
#include "Python.h"
+#include "pycore_coreconfig.h"
#ifdef MS_WINDOWS
# include
/* All sample MSDN wincrypt programs include the header below. It is at least
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index 2e8f4cf6f10..3c17e3536d8 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -203,6 +203,34 @@ _Py_GetGlobalVariablesAsDict(void)
}
+/* --- _PyInitError ----------------------------------------------- */
+
+_PyInitError _PyInitError_Ok(void)
+{ return _Py_INIT_OK(); }
+
+_PyInitError _PyInitError_Error(const char *err_msg)
+{
+ return (_PyInitError){._type = _Py_INIT_ERR_TYPE_ERROR,
+ .err_msg = err_msg};
+}
+
+_PyInitError _PyInitError_NoMemory(void)
+{ return _PyInitError_Error("memory allocation failed"); }
+
+_PyInitError _PyInitError_Exit(int exitcode)
+{ return _Py_INIT_EXIT(exitcode); }
+
+
+int _PyInitError_IsError(_PyInitError err)
+{ return _Py_INIT_IS_ERROR(err); }
+
+int _PyInitError_IsExit(_PyInitError err)
+{ return _Py_INIT_IS_EXIT(err); }
+
+int _PyInitError_Failed(_PyInitError err)
+{ return _Py_INIT_FAILED(err); }
+
+
/* --- _PyWstrList ------------------------------------------------ */
#ifndef NDEBUG
diff --git a/Python/frozenmain.c b/Python/frozenmain.c
index 0175e42596b..7b232bb8023 100644
--- a/Python/frozenmain.c
+++ b/Python/frozenmain.c
@@ -17,7 +17,7 @@ int
Py_FrozenMain(int argc, char **argv)
{
_PyInitError err = _PyRuntime_Initialize();
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
@@ -84,7 +84,7 @@ Py_FrozenMain(int argc, char **argv)
err = _Py_InitializeFromConfig(&config);
/* No need to call _PyCoreConfig_Clear() since we didn't allocate any
memory: program_name is a constant string. */
- if (_Py_INIT_FAILED(err)) {
+ if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
}
From 4fa7504ee3184cff064e23fe6799e717ed0f9357 Mon Sep 17 00:00:00 2001
From: Pedro Lacerda
Date: Fri, 17 May 2019 19:32:44 -0300
Subject: [PATCH 098/199] bpo-27268: Fix incorrect error message on float('')
(GH-2745)
---
Python/pystrtod.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Python/pystrtod.c b/Python/pystrtod.c
index 02a3fb57805..4aa99d546ca 100644
--- a/Python/pystrtod.c
+++ b/Python/pystrtod.c
@@ -353,15 +353,15 @@ PyOS_string_to_double(const char *s,
else if (!endptr && (fail_pos == s || *fail_pos != '\0'))
PyErr_Format(PyExc_ValueError,
"could not convert string to float: "
- "%.200s", s);
+ "'%.200s'", s);
else if (fail_pos == s)
PyErr_Format(PyExc_ValueError,
"could not convert string to float: "
- "%.200s", s);
+ "'%.200s'", s);
else if (errno == ERANGE && fabs(x) >= 1.0 && overflow_exception)
PyErr_Format(overflow_exception,
"value too large to convert to float: "
- "%.200s", s);
+ "'%.200s'", s);
else
result = x;
From b594784272d4907b1c40d3c40d17cb081aa9cf9b Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Sat, 18 May 2019 00:38:16 +0200
Subject: [PATCH 099/199] bpo-36763: _Py_InitializeFromArgs() argc becomes
Py_ssize_t (GH-13396)
* The type of initlization function 'argc' parameters becomes
Py_ssize_t, instead of int.
* Change _PyPreConfig_Copy() return type to void, instead of int.
The function cannot fail anymore.
* Fix compilation warnings on Windows.
---
Include/cpython/pylifecycle.h | 8 +++----
Include/internal/pycore_coreconfig.h | 8 +++----
Python/coreconfig.c | 15 +++++-------
Python/preconfig.c | 34 +++++-----------------------
Python/pylifecycle.c | 13 ++++-------
5 files changed, 25 insertions(+), 53 deletions(-)
diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h
index a3ab6c915ef..8fc809d30d8 100644
--- a/Include/cpython/pylifecycle.h
+++ b/Include/cpython/pylifecycle.h
@@ -18,11 +18,11 @@ PyAPI_FUNC(_PyInitError) _Py_PreInitialize(
const _PyPreConfig *src_config);
PyAPI_FUNC(_PyInitError) _Py_PreInitializeFromArgs(
const _PyPreConfig *src_config,
- int argc,
+ Py_ssize_t argc,
char **argv);
PyAPI_FUNC(_PyInitError) _Py_PreInitializeFromWideArgs(
const _PyPreConfig *src_config,
- int argc,
+ Py_ssize_t argc,
wchar_t **argv);
PyAPI_FUNC(int) _Py_IsCoreInitialized(void);
@@ -34,11 +34,11 @@ PyAPI_FUNC(_PyInitError) _Py_InitializeFromConfig(
const _PyCoreConfig *config);
PyAPI_FUNC(_PyInitError) _Py_InitializeFromArgs(
const _PyCoreConfig *config,
- int argc,
+ Py_ssize_t argc,
char **argv);
PyAPI_FUNC(_PyInitError) _Py_InitializeFromWideArgs(
const _PyCoreConfig *config,
- int argc,
+ Py_ssize_t argc,
wchar_t **argv);
PyAPI_FUNC(_PyInitError) _Py_InitializeMain(void);
diff --git a/Include/internal/pycore_coreconfig.h b/Include/internal/pycore_coreconfig.h
index 80aec21f2c8..ea4418f5061 100644
--- a/Include/internal/pycore_coreconfig.h
+++ b/Include/internal/pycore_coreconfig.h
@@ -61,7 +61,7 @@ PyAPI_FUNC(int) _PyWstrList_Extend(_PyWstrList *list,
/* --- _PyArgv ---------------------------------------------------- */
typedef struct {
- int argc;
+ Py_ssize_t argc;
int use_bytes_argv;
char **bytes_argv;
wchar_t **wchar_argv;
@@ -123,7 +123,7 @@ PyAPI_FUNC(_PyInitError) _PyPreCmdline_Read(_PyPreCmdline *cmdline,
PyAPI_FUNC(void) _PyPreConfig_Init(_PyPreConfig *config);
PyAPI_FUNC(void) _PyPreConfig_InitPythonConfig(_PyPreConfig *config);
PyAPI_FUNC(void) _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config);
-PyAPI_FUNC(int) _PyPreConfig_Copy(_PyPreConfig *config,
+PyAPI_FUNC(void) _PyPreConfig_Copy(_PyPreConfig *config,
const _PyPreConfig *config2);
PyAPI_FUNC(PyObject*) _PyPreConfig_AsDict(const _PyPreConfig *config);
PyAPI_FUNC(void) _PyPreConfig_GetCoreConfig(_PyPreConfig *config,
@@ -158,10 +158,10 @@ PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetPyArgv(
const _PyArgv *args);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetArgv(
_PyCoreConfig *config,
- int argc,
+ Py_ssize_t argc,
char **argv);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetWideArgv(_PyCoreConfig *config,
- int argc,
+ Py_ssize_t argc,
wchar_t **argv);
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index 3c17e3536d8..fd457262a82 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -1746,7 +1746,7 @@ config_usage(int error, const wchar_t* program)
/* Parse the command line arguments */
static _PyInitError
config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions,
- int *opt_index)
+ Py_ssize_t *opt_index)
{
_PyInitError err;
const _PyWstrList *argv = &config->argv;
@@ -2044,7 +2044,7 @@ config_init_warnoptions(_PyCoreConfig *config,
static _PyInitError
-config_update_argv(_PyCoreConfig *config, int opt_index)
+config_update_argv(_PyCoreConfig *config, Py_ssize_t opt_index)
{
const _PyWstrList *cmdline_argv = &config->argv;
_PyWstrList config_argv = _PyWstrList_INIT;
@@ -2105,10 +2105,7 @@ core_read_precmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline)
_PyPreConfig preconfig;
_PyPreConfig_Init(&preconfig);
- if (_PyPreConfig_Copy(&preconfig, &_PyRuntime.preconfig) < 0) {
- err = _Py_INIT_NO_MEMORY();
- return err;
- }
+ _PyPreConfig_Copy(&preconfig, &_PyRuntime.preconfig);
_PyPreConfig_GetCoreConfig(&preconfig, config);
@@ -2145,7 +2142,7 @@ config_read_cmdline(_PyCoreConfig *config)
}
if (config->parse_argv) {
- int opt_index;
+ Py_ssize_t opt_index;
err = config_parse_cmdline(config, &cmdline_warnoptions, &opt_index);
if (_Py_INIT_FAILED(err)) {
goto done;
@@ -2207,7 +2204,7 @@ _PyCoreConfig_SetPyArgv(_PyCoreConfig *config, const _PyArgv *args)
/* Set config.argv: decode argv using Py_DecodeLocale(). Pre-initialize Python
if needed to ensure that encodings are properly configured. */
_PyInitError
-_PyCoreConfig_SetArgv(_PyCoreConfig *config, int argc, char **argv)
+_PyCoreConfig_SetArgv(_PyCoreConfig *config, Py_ssize_t argc, char **argv)
{
_PyArgv args = {
.argc = argc,
@@ -2219,7 +2216,7 @@ _PyCoreConfig_SetArgv(_PyCoreConfig *config, int argc, char **argv)
_PyInitError
-_PyCoreConfig_SetWideArgv(_PyCoreConfig *config, int argc, wchar_t **argv)
+_PyCoreConfig_SetWideArgv(_PyCoreConfig *config, Py_ssize_t argc, wchar_t **argv)
{
_PyArgv args = {
.argc = argc,
diff --git a/Python/preconfig.c b/Python/preconfig.c
index 985af39cb00..b7bcfeb9b2f 100644
--- a/Python/preconfig.c
+++ b/Python/preconfig.c
@@ -297,19 +297,10 @@ _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config)
}
-int
+void
_PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
{
#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
-#define COPY_STR_ATTR(ATTR) \
- do { \
- if (config2->ATTR != NULL) { \
- config->ATTR = _PyMem_RawStrdup(config2->ATTR); \
- if (config->ATTR == NULL) { \
- return -1; \
- } \
- } \
- } while (0)
COPY_ATTR(isolated);
COPY_ATTR(use_environment);
@@ -317,15 +308,13 @@ _PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
COPY_ATTR(dev_mode);
COPY_ATTR(coerce_c_locale);
COPY_ATTR(coerce_c_locale_warn);
+ COPY_ATTR(utf8_mode);
+ COPY_ATTR(allocator);
#ifdef MS_WINDOWS
COPY_ATTR(legacy_windows_fs_encoding);
#endif
- COPY_ATTR(utf8_mode);
- COPY_ATTR(allocator);
#undef COPY_ATTR
-#undef COPY_STR_ATTR
- return 0;
}
@@ -750,9 +739,7 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
/* Save the config to be able to restore it if encodings change */
_PyPreConfig save_config;
_PyPreConfig_Init(&save_config);
- if (_PyPreConfig_Copy(&save_config, config) < 0) {
- return _Py_INIT_NO_MEMORY();
- }
+ _PyPreConfig_Copy(&save_config, config);
/* Set LC_CTYPE to the user preferred locale */
if (config->configure_locale) {
@@ -835,10 +822,7 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
just keep UTF-8 Mode value. */
int new_utf8_mode = config->utf8_mode;
int new_coerce_c_locale = config->coerce_c_locale;
- if (_PyPreConfig_Copy(config, &save_config) < 0) {
- err = _Py_INIT_NO_MEMORY();
- goto done;
- }
+ _PyPreConfig_Copy(config, &save_config);
config->utf8_mode = new_utf8_mode;
config->coerce_c_locale = new_coerce_c_locale;
@@ -900,13 +884,7 @@ _PyPreConfig_Write(const _PyPreConfig *config)
}
/* Write the new pre-configuration into _PyRuntime */
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- int res = _PyPreConfig_Copy(&_PyRuntime.preconfig, config);
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- if (res < 0) {
- return _Py_INIT_NO_MEMORY();
- }
+ _PyPreConfig_Copy(&_PyRuntime.preconfig, config);
return _Py_INIT_OK();
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 231706d2ab6..d29b293b79e 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -705,10 +705,7 @@ _Py_PreInitializeFromPyArgv(const _PyPreConfig *src_config, const _PyArgv *args)
_PyPreConfig_Init(&config);
if (src_config) {
- if (_PyPreConfig_Copy(&config, src_config) < 0) {
- err = _Py_INIT_NO_MEMORY();
- return err;
- }
+ _PyPreConfig_Copy(&config, src_config);
}
err = _PyPreConfig_Read(&config, args);
@@ -727,7 +724,7 @@ _Py_PreInitializeFromPyArgv(const _PyPreConfig *src_config, const _PyArgv *args)
_PyInitError
-_Py_PreInitializeFromArgs(const _PyPreConfig *src_config, int argc, char **argv)
+_Py_PreInitializeFromArgs(const _PyPreConfig *src_config, Py_ssize_t argc, char **argv)
{
_PyArgv args = {.use_bytes_argv = 1, .argc = argc, .bytes_argv = argv};
return _Py_PreInitializeFromPyArgv(src_config, &args);
@@ -735,7 +732,7 @@ _Py_PreInitializeFromArgs(const _PyPreConfig *src_config, int argc, char **argv)
_PyInitError
-_Py_PreInitializeFromWideArgs(const _PyPreConfig *src_config, int argc, wchar_t **argv)
+_Py_PreInitializeFromWideArgs(const _PyPreConfig *src_config, Py_ssize_t argc, wchar_t **argv)
{
_PyArgv args = {.use_bytes_argv = 0, .argc = argc, .wchar_argv = argv};
return _Py_PreInitializeFromPyArgv(src_config, &args);
@@ -1024,7 +1021,7 @@ init_python(const _PyCoreConfig *config, const _PyArgv *args)
_PyInitError
-_Py_InitializeFromArgs(const _PyCoreConfig *config, int argc, char **argv)
+_Py_InitializeFromArgs(const _PyCoreConfig *config, Py_ssize_t argc, char **argv)
{
_PyArgv args = {.use_bytes_argv = 1, .argc = argc, .bytes_argv = argv};
return init_python(config, &args);
@@ -1032,7 +1029,7 @@ _Py_InitializeFromArgs(const _PyCoreConfig *config, int argc, char **argv)
_PyInitError
-_Py_InitializeFromWideArgs(const _PyCoreConfig *config, int argc, wchar_t **argv)
+_Py_InitializeFromWideArgs(const _PyCoreConfig *config, Py_ssize_t argc, wchar_t **argv)
{
_PyArgv args = {.use_bytes_argv = 0, .argc = argc, .wchar_argv = argv};
return init_python(config, &args);
From 51a860ee01a9e96f8013fe6ca836ec95e7eb3010 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A9ry=20Ogam?=
Date: Sat, 18 May 2019 00:44:57 +0200
Subject: [PATCH 100/199] Correct typos in the Barrier specification (GH-9395)
---
Doc/library/threading.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
index 99dd7fff0d2..715940c1c52 100644
--- a/Doc/library/threading.rst
+++ b/Doc/library/threading.rst
@@ -968,7 +968,7 @@ As an example, here is a simple way to synchronize a client and server thread::
Return the barrier to the default, empty state. Any threads waiting on it
will receive the :class:`BrokenBarrierError` exception.
- Note that using this function may can require some external
+ Note that using this function may require some external
synchronization if there are other threads whose state is unknown. If a
barrier is broken it may be better to just leave it and create a new one.
@@ -976,7 +976,7 @@ As an example, here is a simple way to synchronize a client and server thread::
Put the barrier into a broken state. This causes any active or future
calls to :meth:`wait` to fail with the :class:`BrokenBarrierError`. Use
- this for example if one of the needs to abort, to avoid deadlocking the
+ this for example if one of the threads needs to abort, to avoid deadlocking the
application.
It may be preferable to simply create the barrier with a sensible
From e7b1136ec3b40d174d71f2195cceaadf4fe9539c Mon Sep 17 00:00:00 2001
From: Toshio Kuratomi
Date: Fri, 17 May 2019 18:54:02 -0400
Subject: [PATCH 101/199] Document a workaround for a curses bug (GH-13209)
---
Doc/library/curses.rst | 13 ++++++++++---
.../2019-05-08-13-17-44.bpo-35924.lqbNpW.rst | 2 ++
2 files changed, 12 insertions(+), 3 deletions(-)
create mode 100644 Misc/NEWS.d/next/Documentation/2019-05-08-13-17-44.bpo-35924.lqbNpW.rst
diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst
index 2a4d9ce8a35..7d1e7538a29 100644
--- a/Doc/library/curses.rst
+++ b/Doc/library/curses.rst
@@ -708,9 +708,16 @@ the following methods and attributes:
.. note::
- Writing outside the window, subwindow, or pad raises :exc:`curses.error`.
- Attempting to write to the lower right corner of a window, subwindow,
- or pad will cause an exception to be raised after the string is printed.
+ * Writing outside the window, subwindow, or pad raises :exc:`curses.error`.
+ Attempting to write to the lower right corner of a window, subwindow,
+ or pad will cause an exception to be raised after the string is printed.
+
+ * A `bug in ncurses `_, the backend
+ for this Python module, can cause SegFaults when resizing windows. This
+ is fixed in ncurses-6.1-20190511. If you are stuck with an earlier
+ ncurses, you can avoid triggering this if you do not call :func:`addstr`
+ with a *str* that has embedded newlines. Instead, call :func:`addstr`
+ separately for each line.
.. method:: window.attroff(attr)
diff --git a/Misc/NEWS.d/next/Documentation/2019-05-08-13-17-44.bpo-35924.lqbNpW.rst b/Misc/NEWS.d/next/Documentation/2019-05-08-13-17-44.bpo-35924.lqbNpW.rst
new file mode 100644
index 00000000000..a88778f85cc
--- /dev/null
+++ b/Misc/NEWS.d/next/Documentation/2019-05-08-13-17-44.bpo-35924.lqbNpW.rst
@@ -0,0 +1,2 @@
+Add a note to the ``curses.addstr()`` documentation to warn that multiline
+strings can cause segfaults because of an ncurses bug.
From 27ee0f8551a6d576a65e20da90acf9f3cb412c35 Mon Sep 17 00:00:00 2001
From: David Carlier
Date: Fri, 17 May 2019 23:46:22 +0000
Subject: [PATCH 102/199] Fix couple of dead code paths (GH-7418)
---
Objects/bytesobject.c | 2 --
Objects/stringlib/fastsearch.h | 1 -
Python/ast.c | 3 ---
Python/compile.c | 1 -
4 files changed, 7 deletions(-)
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index ebbdb7c3c16..41453b2d14e 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -1617,12 +1617,10 @@ bytes_richcompare(PyBytesObject *a, PyBytesObject *b, int op)
case Py_GE:
/* a string is equal to itself */
Py_RETURN_TRUE;
- break;
case Py_NE:
case Py_LT:
case Py_GT:
Py_RETURN_FALSE;
- break;
default:
PyErr_BadArgument();
return NULL;
diff --git a/Objects/stringlib/fastsearch.h b/Objects/stringlib/fastsearch.h
index a8a51d577f3..46fcf356d0d 100644
--- a/Objects/stringlib/fastsearch.h
+++ b/Objects/stringlib/fastsearch.h
@@ -192,7 +192,6 @@ FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n,
}
return count;
}
- return -1;
}
mlast = m - 1;
diff --git a/Python/ast.c b/Python/ast.c
index 03da4e7f7f9..abc8d89c8a3 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -2971,7 +2971,6 @@ ast_for_expr(struct compiling *c, const node *n)
return Compare(expression, ops, cmps, LINENO(n), n->n_col_offset,
n->n_end_lineno, n->n_end_col_offset, c->c_arena);
}
- break;
case star_expr:
return ast_for_starred(c, n);
@@ -3618,7 +3617,6 @@ alias_for_import_name(struct compiling *c, const node *n, int store)
return NULL;
return a;
}
- break;
case dotted_name:
if (NCH(n) == 1) {
node *name_node = CHILD(n, 0);
@@ -3669,7 +3667,6 @@ alias_for_import_name(struct compiling *c, const node *n, int store)
}
return alias(str, NULL, c->c_arena);
}
- break;
case STAR:
str = PyUnicode_InternFromString("*");
if (!str)
diff --git a/Python/compile.c b/Python/compile.c
index 2a086a509f4..b20548c7772 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -4868,7 +4868,6 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
return compiler_error(c,
"can't use starred expression here");
}
- break;
case Name_kind:
return compiler_nameop(c, e->v.Name.id, e->v.Name.ctx);
/* child nodes of List and Tuple will have expr_context set */
From bab0db6076900cd828588be8595b3cdfade7e7e9 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Sat, 18 May 2019 03:21:27 +0200
Subject: [PATCH 103/199] bpo-36763: Use _PyCoreConfig_InitPythonConfig()
(GH-13398)
_PyPreConfig_InitPythonConfig() and _PyCoreConfig_InitPythonConfig()
no longer inherit their values from global configuration variables.
Changes:
* _PyPreCmdline_Read() now ignores -X dev and PYTHONDEVMODE
if dev_mode is already set.
* Inline _PyPreConfig_INIT macro into _PyPreConfig_Init() function.
* Inline _PyCoreConfig_INIT macro into _PyCoreConfig_Init() function.
* Replace _PyCoreConfig_Init() with _PyCoreConfig_InitPythonConfig()
in most tests of _testembed.c.
* Replace _PyCoreConfig_Init() with _PyCoreConfig_InitIsolatedConfig()
in _freeze_importlib.c.
* Move some initialization functions from the internal
to the private API.
---
Include/cpython/coreconfig.h | 77 ++++---------------
Include/internal/pycore_coreconfig.h | 20 +----
Lib/test/test_embed.py | 105 +++++++++++++++----------
Programs/_freeze_importlib.c | 6 +-
Programs/_testembed.c | 111 +++++++++++++++++++--------
Python/coreconfig.c | 77 ++++++++++++++-----
Python/frozenmain.c | 2 +-
Python/preconfig.c | 23 ++++--
8 files changed, 240 insertions(+), 181 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index f05eddad912..ca71c15b67d 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -115,27 +115,8 @@ typedef struct {
PyMemAllocatorName allocator;
} _PyPreConfig;
-#ifdef MS_WINDOWS
-# define _PyPreConfig_WINDOWS_INIT \
- .legacy_windows_fs_encoding = -1,
-#else
-# define _PyPreConfig_WINDOWS_INIT
-#endif
-
-#define _PyPreConfig_INIT \
- (_PyPreConfig){ \
- _PyPreConfig_WINDOWS_INIT \
- ._config_version = _Py_CONFIG_VERSION, \
- .isolated = -1, \
- .use_environment = -1, \
- .configure_locale = 1, \
- .utf8_mode = -2, \
- .dev_mode = -1, \
- .allocator = PYMEM_ALLOCATOR_NOT_SET}
-
-PyAPI_FUNC(void) _PyPreConfig_Init(_PyPreConfig *config);
PyAPI_FUNC(void) _PyPreConfig_InitPythonConfig(_PyPreConfig *config);
-PyAPI_FUNC(void) _PyPreConfig_InitIsolateConfig(_PyPreConfig *config);
+PyAPI_FUNC(void) _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config);
/* --- _PyCoreConfig ---------------------------------------------- */
@@ -419,47 +400,23 @@ typedef struct {
} _PyCoreConfig;
-#ifdef MS_WINDOWS
-# define _PyCoreConfig_WINDOWS_INIT \
- .legacy_windows_stdio = -1,
-#else
-# define _PyCoreConfig_WINDOWS_INIT
-#endif
-
-#define _PyCoreConfig_INIT \
- (_PyCoreConfig){ \
- _PyCoreConfig_WINDOWS_INIT \
- ._config_version = _Py_CONFIG_VERSION, \
- .isolated = -1, \
- .use_environment = -1, \
- .dev_mode = -1, \
- .install_signal_handlers = 1, \
- .use_hash_seed = -1, \
- .faulthandler = -1, \
- .tracemalloc = -1, \
- .use_module_search_paths = 0, \
- .parse_argv = 0, \
- .site_import = -1, \
- .bytes_warning = -1, \
- .inspect = -1, \
- .interactive = -1, \
- .optimization_level = -1, \
- .parser_debug= -1, \
- .write_bytecode = -1, \
- .verbose = -1, \
- .quiet = -1, \
- .user_site_directory = -1, \
- .configure_c_stdio = 0, \
- .buffered_stdio = -1, \
- ._install_importlib = 1, \
- .check_hash_pycs_mode = NULL, \
- .pathconfig_warnings = -1, \
- ._init_main = 1}
-/* Note: _PyCoreConfig_INIT sets other fields to 0/NULL */
-
-PyAPI_FUNC(void) _PyCoreConfig_Init(_PyCoreConfig *config);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPythonConfig(_PyCoreConfig *config);
-PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitIsolateConfig(_PyCoreConfig *config);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitIsolatedConfig(_PyCoreConfig *config);
+PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetString(
+ wchar_t **config_str,
+ const wchar_t *str);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_DecodeLocale(
+ wchar_t **config_str,
+ const char *str);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *config);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetArgv(
+ _PyCoreConfig *config,
+ Py_ssize_t argc,
+ char **argv);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetWideArgv(_PyCoreConfig *config,
+ Py_ssize_t argc,
+ wchar_t **argv);
#ifdef __cplusplus
}
diff --git a/Include/internal/pycore_coreconfig.h b/Include/internal/pycore_coreconfig.h
index ea4418f5061..edde7b1d8d8 100644
--- a/Include/internal/pycore_coreconfig.h
+++ b/Include/internal/pycore_coreconfig.h
@@ -121,8 +121,6 @@ PyAPI_FUNC(_PyInitError) _PyPreCmdline_Read(_PyPreCmdline *cmdline,
/* --- _PyPreConfig ----------------------------------------------- */
PyAPI_FUNC(void) _PyPreConfig_Init(_PyPreConfig *config);
-PyAPI_FUNC(void) _PyPreConfig_InitPythonConfig(_PyPreConfig *config);
-PyAPI_FUNC(void) _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config);
PyAPI_FUNC(void) _PyPreConfig_Copy(_PyPreConfig *config,
const _PyPreConfig *config2);
PyAPI_FUNC(PyObject*) _PyPreConfig_AsDict(const _PyPreConfig *config);
@@ -135,34 +133,18 @@ PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(const _PyPreConfig *config);
/* --- _PyCoreConfig ---------------------------------------------- */
-PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
-PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPythonConfig(_PyCoreConfig *config);
-PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitIsolatedConfig(_PyCoreConfig *config);
+PyAPI_FUNC(void) _PyCoreConfig_Init(_PyCoreConfig *config);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Copy(
_PyCoreConfig *config,
const _PyCoreConfig *config2);
-PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetString(
- wchar_t **config_str,
- const wchar_t *str);
-PyAPI_FUNC(_PyInitError) _PyCoreConfig_DecodeLocale(
- wchar_t **config_str,
- const char *str);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPathConfig(_PyCoreConfig *config);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetPathConfig(
const _PyCoreConfig *config);
-PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *config);
PyAPI_FUNC(void) _PyCoreConfig_Write(const _PyCoreConfig *config,
_PyRuntimeState *runtime);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetPyArgv(
_PyCoreConfig *config,
const _PyArgv *args);
-PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetArgv(
- _PyCoreConfig *config,
- Py_ssize_t argc,
- char **argv);
-PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetWideArgv(_PyCoreConfig *config,
- Py_ssize_t argc,
- wchar_t **argv);
/* --- Function used for testing ---------------------------------- */
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index c389df85fb6..6b77a2d1fd8 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -285,6 +285,16 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'coerce_c_locale_warn': 0,
'utf8_mode': 0,
}
+ ISOLATED_PRE_CONFIG = dict(DEFAULT_PRE_CONFIG,
+ configure_locale=0,
+ isolated=1,
+ use_environment=0,
+ utf8_mode=0,
+ dev_mode=0,
+ )
+ if MS_WINDOWS:
+ ISOLATED_PRE_CONFIG['legacy_windows_fs_encoding'] = 0
+
COPY_PRE_CONFIG = [
'dev_mode',
'isolated',
@@ -363,6 +373,24 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'legacy_windows_stdio': 0,
})
+ PYTHON_CORE_CONFIG = dict(DEFAULT_CORE_CONFIG,
+ configure_c_stdio=1,
+ parse_argv=1,
+ )
+ ISOLATED_CORE_CONFIG = dict(DEFAULT_CORE_CONFIG,
+ isolated=1,
+ use_environment=0,
+ user_site_directory=0,
+ dev_mode=0,
+ install_signal_handlers=0,
+ use_hash_seed=0,
+ faulthandler=0,
+ tracemalloc=0,
+ pathconfig_warnings=0,
+ )
+ if MS_WINDOWS:
+ ISOLATED_CORE_CONFIG['legacy_windows_stdio'] = 0
+
# global config
DEFAULT_GLOBAL_CONFIG = {
'Py_HasFileSystemDefaultEncoding': 0,
@@ -410,8 +438,15 @@ def main_xoptions(self, xoptions_list):
xoptions[opt] = True
return xoptions
- def get_expected_config(self, expected_preconfig, expected, env, add_path=None):
- expected = dict(self.DEFAULT_CORE_CONFIG, **expected)
+ def get_expected_config(self, expected_preconfig, expected, env, api,
+ add_path=None):
+ if api == "python":
+ default_config = self.PYTHON_CORE_CONFIG
+ elif api == "isolated":
+ default_config = self.ISOLATED_CORE_CONFIG
+ else:
+ default_config = self.DEFAULT_CORE_CONFIG
+ expected = dict(default_config, **expected)
code = textwrap.dedent('''
import json
@@ -521,8 +556,8 @@ def check_global_config(self, config):
self.assertEqual(config['global_config'], expected)
- def check_config(self, testname, expected_config, expected_preconfig,
- add_path=None, stderr=None):
+ def check_config(self, testname, expected_config=None, expected_preconfig=None,
+ add_path=None, stderr=None, api="default"):
env = dict(os.environ)
# Remove PYTHON* environment variables to get deterministic environment
for key in list(env):
@@ -533,8 +568,18 @@ def check_config(self, testname, expected_config, expected_preconfig,
env['PYTHONCOERCECLOCALE'] = '0'
env['PYTHONUTF8'] = '0'
- expected_preconfig = dict(self.DEFAULT_PRE_CONFIG, **expected_preconfig)
- expected_config = self.get_expected_config(expected_preconfig, expected_config, env, add_path)
+ if api == "isolated":
+ default_preconfig = self.ISOLATED_PRE_CONFIG
+ else:
+ default_preconfig = self.DEFAULT_PRE_CONFIG
+ if expected_preconfig is None:
+ expected_preconfig = {}
+ expected_preconfig = dict(default_preconfig, **expected_preconfig)
+ if expected_config is None:
+ expected_config = {}
+ expected_config = self.get_expected_config(expected_preconfig,
+ expected_config, env,
+ api, add_path)
for key in self.COPY_PRE_CONFIG:
if key not in expected_preconfig:
expected_preconfig[key] = expected_config[key]
@@ -677,76 +722,56 @@ def test_init_dev_mode(self):
'dev_mode': 1,
'warnoptions': ['default'],
}
- self.check_config("init_dev_mode", config, preconfig)
+ self.check_config("init_dev_mode", config, preconfig, api="python")
def test_init_isolated_flag(self):
- preconfig = {}
config = {
'isolated': 1,
'use_environment': 0,
'user_site_directory': 0,
}
- self.check_config("init_isolated_flag", config, preconfig)
+ self.check_config("init_isolated_flag", config, api="python")
def test_preinit_isolated1(self):
# _PyPreConfig.isolated=1, _PyCoreConfig.isolated not set
- preconfig = {}
config = {
'isolated': 1,
'use_environment': 0,
'user_site_directory': 0,
}
- self.check_config("preinit_isolated1", config, preconfig)
+ self.check_config("preinit_isolated1", config)
def test_preinit_isolated2(self):
# _PyPreConfig.isolated=0, _PyCoreConfig.isolated=1
- preconfig = {}
config = {
'isolated': 1,
'use_environment': 0,
'user_site_directory': 0,
}
- self.check_config("preinit_isolated2", config, preconfig)
+ self.check_config("preinit_isolated2", config)
def test_init_isolated_config(self):
- preconfig = {
- 'configure_locale': 0,
- }
- config = {
- 'isolated': 1,
- 'use_environment': 0,
- 'user_site_directory': 0,
- 'install_signal_handlers': 0,
- 'pathconfig_warnings': 0,
- }
- self.check_config("init_isolated_config", config, preconfig)
+ self.check_config("init_isolated_config", api="isolated")
def test_init_python_config(self):
- preconfig = {}
- config = {
- 'configure_c_stdio': 1,
- 'parse_argv': 1,
- }
- self.check_config("init_python_config", config, preconfig)
+ self.check_config("init_python_config", api="python")
def test_init_dont_configure_locale(self):
# _PyPreConfig.configure_locale=0
preconfig = {
'configure_locale': 0,
}
- self.check_config("init_dont_configure_locale", {}, preconfig)
+ self.check_config("init_dont_configure_locale", {}, preconfig, api="python")
def test_init_read_set(self):
- preconfig = {}
core_config = {
'program_name': './init_read_set',
'executable': 'my_executable',
}
- self.check_config("init_read_set", core_config, preconfig,
+ self.check_config("init_read_set", core_config, api="python",
add_path="init_read_set_path")
def test_init_run_main(self):
- preconfig = {}
code = ('import _testinternalcapi, json; '
'print(json.dumps(_testinternalcapi.get_configs()))')
core_config = {
@@ -755,10 +780,9 @@ def test_init_run_main(self):
'run_command': code + '\n',
'parse_argv': 1,
}
- self.check_config("init_run_main", core_config, preconfig)
+ self.check_config("init_run_main", core_config, api="python")
def test_init_main(self):
- preconfig = {}
code = ('import _testinternalcapi, json; '
'print(json.dumps(_testinternalcapi.get_configs()))')
core_config = {
@@ -768,25 +792,26 @@ def test_init_main(self):
'parse_argv': 1,
'_init_main': 0,
}
- self.check_config("init_main", core_config, preconfig,
+ self.check_config("init_main", core_config, api="python",
stderr="Run Python code before _Py_InitializeMain")
def test_init_parse_argv(self):
core_config = {
+ 'parse_argv': 1,
'argv': ['-c', 'arg1', '-v', 'arg3'],
'program_name': './argv0',
- 'parse_argv': 1,
'run_command': 'pass\n',
'use_environment': 0,
}
- self.check_config("init_parse_argv", core_config, {})
+ self.check_config("init_parse_argv", core_config, api="python")
def test_init_dont_parse_argv(self):
core_config = {
+ 'parse_argv': 0,
'argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'],
'program_name': './argv0',
}
- self.check_config("init_dont_parse_argv", core_config, {})
+ self.check_config("init_dont_parse_argv", core_config, api="python")
if __name__ == "__main__":
diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c
index d89d66abee7..1a719e2f967 100644
--- a/Programs/_freeze_importlib.c
+++ b/Programs/_freeze_importlib.c
@@ -77,14 +77,12 @@ main(int argc, char *argv[])
text[text_size] = '\0';
_PyCoreConfig config;
- _PyCoreConfig_Init(&config);
- config.use_environment = 0;
- config.user_site_directory = 0;
+ _PyCoreConfig_InitIsolatedConfig(&config);
+
config.site_import = 0;
config.program_name = L"./_freeze_importlib";
/* Don't install importlib, since it could execute outdated bytecode. */
config._install_importlib = 0;
- config.pathconfig_warnings = 0;
config._init_main = 0;
_PyInitError err = _Py_InitializeFromConfig(&config);
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 2352179cc6f..f1bb731dcba 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -5,6 +5,7 @@
#include
#include "pycore_coreconfig.h" /* FIXME: PEP 587 makes these functions public */
+#include
#include "pythread.h"
#include
#include
@@ -404,7 +405,7 @@ static int test_init_from_config(void)
config.use_hash_seed = 1;
config.hash_seed = 123;
- /* dev_mode=1 is tested in init_dev_mode() */
+ /* dev_mode=1 is tested in test_init_dev_mode() */
putenv("PYTHONFAULTHANDLER=");
config.faulthandler = 1;
@@ -521,12 +522,12 @@ static int test_init_from_config(void)
}
-static int test_init_parse_argv(int parse_argv)
+static int check_init_parse_argv(int parse_argv)
{
_PyInitError err;
_PyCoreConfig config;
- _PyCoreConfig_Init(&config);
+ _PyCoreConfig_InitPythonConfig(&config);
static wchar_t* argv[] = {
L"./argv0",
@@ -552,15 +553,15 @@ static int test_init_parse_argv(int parse_argv)
}
-static int init_parse_argv(void)
+static int test_init_parse_argv(void)
{
- return test_init_parse_argv(1);
+ return check_init_parse_argv(1);
}
-static int init_dont_parse_argv(void)
+static int test_init_dont_parse_argv(void)
{
- return test_init_parse_argv(0);
+ return check_init_parse_argv(0);
}
@@ -603,7 +604,7 @@ static int test_init_env(void)
}
-static void test_init_env_dev_mode_putenvs(void)
+static void set_all_env_vars(void)
{
test_init_env_putenvs();
putenv("PYTHONMALLOC=");
@@ -616,7 +617,7 @@ static int test_init_env_dev_mode(void)
{
/* Test initialization from environment variables */
Py_IgnoreEnvironmentFlag = 0;
- test_init_env_dev_mode_putenvs();
+ set_all_env_vars();
_testembed_Py_Initialize();
dump_config();
Py_Finalize();
@@ -628,7 +629,7 @@ static int test_init_env_dev_mode_alloc(void)
{
/* Test initialization from environment variables */
Py_IgnoreEnvironmentFlag = 0;
- test_init_env_dev_mode_putenvs();
+ set_all_env_vars();
putenv("PYTHONMALLOC=malloc");
_testembed_Py_Initialize();
dump_config();
@@ -637,13 +638,13 @@ static int test_init_env_dev_mode_alloc(void)
}
-static int init_isolated_flag(void)
+static int test_init_isolated_flag(void)
{
_PyInitError err;
/* Test _PyCoreConfig.isolated=1 */
_PyCoreConfig config;
- _PyCoreConfig_Init(&config);
+ _PyCoreConfig_InitPythonConfig(&config);
Py_IsolatedFlag = 0;
config.isolated = 1;
@@ -651,7 +652,7 @@ static int init_isolated_flag(void)
/* Use path starting with "./" avoids a search along the PATH */
config.program_name = L"./_testembed";
- test_init_env_dev_mode_putenvs();
+ set_all_env_vars();
err = _Py_InitializeFromConfig(&config);
if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
@@ -680,7 +681,7 @@ static int test_preinit_isolated1(void)
_PyCoreConfig_Init(&config);
config.program_name = L"./_testembed";
- test_init_env_dev_mode_putenvs();
+ set_all_env_vars();
err = _Py_InitializeFromConfig(&config);
if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
@@ -715,7 +716,7 @@ static int test_preinit_isolated2(void)
/* Use path starting with "./" avoids a search along the PATH */
config.program_name = L"./_testembed";
- test_init_env_dev_mode_putenvs();
+ set_all_env_vars();
err = _Py_InitializeFromConfig(&config);
if (_PyInitError_Failed(err)) {
_Py_ExitInitError(err);
@@ -726,10 +727,38 @@ static int test_preinit_isolated2(void)
}
-static int init_isolated_config(void)
+static void set_all_global_config_variables(void)
+{
+ Py_IsolatedFlag = 0;
+ Py_IgnoreEnvironmentFlag = 0;
+ Py_BytesWarningFlag = 2;
+ Py_InspectFlag = 1;
+ Py_InteractiveFlag = 1;
+ Py_OptimizeFlag = 1;
+ Py_DebugFlag = 1;
+ Py_VerboseFlag = 1;
+ Py_QuietFlag = 1;
+ Py_FrozenFlag = 0;
+ Py_UnbufferedStdioFlag = 1;
+ Py_NoSiteFlag = 1;
+ Py_DontWriteBytecodeFlag = 1;
+ Py_NoUserSiteDirectory = 1;
+#ifdef MS_WINDOWS
+ Py_LegacyWindowsStdioFlag = 1;
+#endif
+}
+
+
+static int test_init_isolated_config(void)
{
_PyInitError err;
+ /* environment variables must be ignored */
+ set_all_env_vars();
+
+ /* global configuration variables must be ignored */
+ set_all_global_config_variables();
+
_PyPreConfig preconfig;
_PyPreConfig_InitIsolatedConfig(&preconfig);
@@ -759,10 +788,23 @@ static int init_isolated_config(void)
}
-static int init_python_config(void)
+static int test_init_python_config(void)
{
_PyInitError err;
+ /* global configuration variables must be ignored */
+ set_all_global_config_variables();
+ Py_IsolatedFlag = 1;
+ Py_IgnoreEnvironmentFlag = 1;
+ Py_FrozenFlag = 1;
+ Py_UnbufferedStdioFlag = 1;
+ Py_NoSiteFlag = 1;
+ Py_DontWriteBytecodeFlag = 1;
+ Py_NoUserSiteDirectory = 1;
+#ifdef MS_WINDOWS
+ Py_LegacyWindowsStdioFlag = 1;
+#endif
+
_PyPreConfig preconfig;
_PyPreConfig_InitPythonConfig(&preconfig);
@@ -788,11 +830,12 @@ static int init_python_config(void)
}
-static int init_dont_configure_locale(void)
+static int test_init_dont_configure_locale(void)
{
_PyInitError err;
- _PyPreConfig preconfig = _PyPreConfig_INIT;
+ _PyPreConfig preconfig;
+ _PyPreConfig_InitPythonConfig(&preconfig);
preconfig.configure_locale = 0;
preconfig.coerce_c_locale = 1;
preconfig.coerce_c_locale_warn = 1;
@@ -802,7 +845,8 @@ static int init_dont_configure_locale(void)
_Py_ExitInitError(err);
}
- _PyCoreConfig config = _PyCoreConfig_INIT;
+ _PyCoreConfig config;
+ _PyCoreConfig_InitPythonConfig(&config);
config.program_name = L"./_testembed";
err = _Py_InitializeFromConfig(&config);
if (_PyInitError_Failed(err)) {
@@ -815,10 +859,10 @@ static int init_dont_configure_locale(void)
}
-static int init_dev_mode(void)
+static int test_init_dev_mode(void)
{
_PyCoreConfig config;
- _PyCoreConfig_Init(&config);
+ _PyCoreConfig_InitPythonConfig(&config);
putenv("PYTHONFAULTHANDLER=");
putenv("PYTHONMALLOC=");
config.dev_mode = 1;
@@ -837,7 +881,7 @@ static int test_init_read_set(void)
{
_PyInitError err;
_PyCoreConfig config;
- _PyCoreConfig_Init(&config);
+ _PyCoreConfig_InitPythonConfig(&config);
err = _PyCoreConfig_DecodeLocale(&config.program_name, "./init_read_set");
if (_PyInitError_Failed(err)) {
@@ -894,7 +938,7 @@ static void configure_init_main(_PyCoreConfig *config)
static int test_init_run_main(void)
{
_PyCoreConfig config;
- _PyCoreConfig_Init(&config);
+ _PyCoreConfig_InitPythonConfig(&config);
configure_init_main(&config);
_PyInitError err = _Py_InitializeFromConfig(&config);
@@ -909,7 +953,7 @@ static int test_init_run_main(void)
static int test_init_main(void)
{
_PyCoreConfig config;
- _PyCoreConfig_Init(&config);
+ _PyCoreConfig_InitPythonConfig(&config);
configure_init_main(&config);
config._init_main = 0;
@@ -939,7 +983,7 @@ static int test_init_main(void)
static int test_run_main(void)
{
_PyCoreConfig config;
- _PyCoreConfig_Init(&config);
+ _PyCoreConfig_InitPythonConfig(&config);
wchar_t *argv[] = {L"python3", L"-c",
(L"import sys; "
@@ -947,7 +991,6 @@ static int test_run_main(void)
L"arg2"};
config.argv.length = Py_ARRAY_LENGTH(argv);
config.argv.items = argv;
- config.parse_argv = 1;
config.program_name = L"./python3";
_PyInitError err = _Py_InitializeFromConfig(&config);
@@ -988,16 +1031,16 @@ static struct TestCase TestCases[] = {
{ "init_default_config", test_init_default_config },
{ "init_global_config", test_init_global_config },
{ "init_from_config", test_init_from_config },
- { "init_parse_argv", init_parse_argv },
- { "init_dont_parse_argv", init_dont_parse_argv },
+ { "init_parse_argv", test_init_parse_argv },
+ { "init_dont_parse_argv", test_init_dont_parse_argv },
{ "init_env", test_init_env },
{ "init_env_dev_mode", test_init_env_dev_mode },
{ "init_env_dev_mode_alloc", test_init_env_dev_mode_alloc },
- { "init_dont_configure_locale", init_dont_configure_locale },
- { "init_dev_mode", init_dev_mode },
- { "init_isolated_flag", init_isolated_flag },
- { "init_isolated_config", init_isolated_config },
- { "init_python_config", init_python_config },
+ { "init_dont_configure_locale", test_init_dont_configure_locale },
+ { "init_dev_mode", test_init_dev_mode },
+ { "init_isolated_flag", test_init_isolated_flag },
+ { "init_isolated_config", test_init_isolated_config },
+ { "init_python_config", test_init_python_config },
{ "preinit_isolated1", test_preinit_isolated1 },
{ "preinit_isolated2", test_preinit_isolated2 },
{ "init_read_set", test_init_read_set },
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index fd457262a82..3678d124067 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -551,14 +551,69 @@ _PyCoreConfig_Clear(_PyCoreConfig *config)
void
_PyCoreConfig_Init(_PyCoreConfig *config)
{
- *config = _PyCoreConfig_INIT;
+ memset(config, 0, sizeof(*config));
+
+ config->_config_version = _Py_CONFIG_VERSION;
+ config->isolated = -1;
+ config->use_environment = -1;
+ config->dev_mode = -1;
+ config->install_signal_handlers = 1;
+ config->use_hash_seed = -1;
+ config->faulthandler = -1;
+ config->tracemalloc = -1;
+ config->use_module_search_paths = 0;
+ config->parse_argv = 0;
+ config->site_import = -1;
+ config->bytes_warning = -1;
+ config->inspect = -1;
+ config->interactive = -1;
+ config->optimization_level = -1;
+ config->parser_debug= -1;
+ config->write_bytecode = -1;
+ config->verbose = -1;
+ config->quiet = -1;
+ config->user_site_directory = -1;
+ config->configure_c_stdio = 0;
+ config->buffered_stdio = -1;
+ config->_install_importlib = 1;
+ config->check_hash_pycs_mode = NULL;
+ config->pathconfig_warnings = -1;
+ config->_init_main = 1;
+#ifdef MS_WINDOWS
+ config->legacy_windows_stdio = -1;
+#endif
+}
+
+
+static void
+_PyCoreConfig_InitDefaults(_PyCoreConfig *config)
+{
+ _PyCoreConfig_Init(config);
+
+ config->isolated = 0;
+ config->use_environment = 1;
+ config->site_import = 1;
+ config->bytes_warning = 0;
+ config->inspect = 0;
+ config->interactive = 0;
+ config->optimization_level = 0;
+ config->parser_debug= 0;
+ config->write_bytecode = 1;
+ config->verbose = 0;
+ config->quiet = 0;
+ config->user_site_directory = 1;
+ config->buffered_stdio = 1;
+ config->pathconfig_warnings = 1;
+#ifdef MS_WINDOWS
+ config->legacy_windows_stdio = 0;
+#endif
}
_PyInitError
_PyCoreConfig_InitPythonConfig(_PyCoreConfig *config)
{
- _PyCoreConfig_Init(config);
+ _PyCoreConfig_InitDefaults(config);
config->configure_c_stdio = 1;
config->parse_argv = 1;
@@ -570,30 +625,16 @@ _PyCoreConfig_InitPythonConfig(_PyCoreConfig *config)
_PyInitError
_PyCoreConfig_InitIsolatedConfig(_PyCoreConfig *config)
{
- _PyCoreConfig_Init(config);
+ _PyCoreConfig_InitDefaults(config);
- /* set to 1 */
config->isolated = 1;
- config->site_import = 1;
- config->write_bytecode = 1;
- config->buffered_stdio = 1;
-
- /* set to 0 */
config->use_environment = 0;
+ config->user_site_directory = 0;
config->dev_mode = 0;
config->install_signal_handlers = 0;
config->use_hash_seed = 0;
config->faulthandler = 0;
config->tracemalloc = 0;
- config->bytes_warning = 0;
- config->inspect = 0;
- config->interactive = 0;
- config->optimization_level = 0;
- config->parser_debug = 0;
- config->verbose = 0;
- config->quiet = 0;
- config->user_site_directory = 0;
- config->configure_c_stdio = 0;
config->pathconfig_warnings = 0;
#ifdef MS_WINDOWS
config->legacy_windows_stdio = 0;
diff --git a/Python/frozenmain.c b/Python/frozenmain.c
index 7b232bb8023..a51fb580012 100644
--- a/Python/frozenmain.c
+++ b/Python/frozenmain.c
@@ -40,7 +40,7 @@ Py_FrozenMain(int argc, char **argv)
}
_PyCoreConfig config;
- _PyCoreConfig_Init(&config);
+ _PyCoreConfig_InitPythonConfig(&config);
config.pathconfig_warnings = 0; /* Suppress errors from getpath.c */
if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
diff --git a/Python/preconfig.c b/Python/preconfig.c
index b7bcfeb9b2f..0f4bd8ece53 100644
--- a/Python/preconfig.c
+++ b/Python/preconfig.c
@@ -241,8 +241,9 @@ _PyPreCmdline_Read(_PyPreCmdline *cmdline,
}
/* dev_mode */
- if ((cmdline && _Py_get_xoption(&cmdline->xoptions, L"dev"))
- || _Py_GetEnv(cmdline->use_environment, "PYTHONDEVMODE"))
+ if ((cmdline->dev_mode < 0)
+ && (_Py_get_xoption(&cmdline->xoptions, L"dev")
+ || _Py_GetEnv(cmdline->use_environment, "PYTHONDEVMODE")))
{
cmdline->dev_mode = 1;
}
@@ -260,10 +261,22 @@ _PyPreCmdline_Read(_PyPreCmdline *cmdline,
/* --- _PyPreConfig ----------------------------------------------- */
+
void
_PyPreConfig_Init(_PyPreConfig *config)
{
- *config = _PyPreConfig_INIT;
+ memset(config, 0, sizeof(*config));
+
+ config->_config_version = _Py_CONFIG_VERSION;
+ config->isolated = -1;
+ config->use_environment = -1;
+ config->configure_locale = 1;
+ config->utf8_mode = -2;
+ config->dev_mode = -1;
+ config->allocator = PYMEM_ALLOCATOR_NOT_SET;
+#ifdef MS_WINDOWS
+ config->legacy_windows_fs_encoding = -1;
+#endif
}
@@ -289,11 +302,11 @@ _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config)
config->configure_locale = 0;
config->isolated = 1;
config->use_environment = 0;
+ config->utf8_mode = 0;
+ config->dev_mode = 0;
#ifdef MS_WINDOWS
config->legacy_windows_fs_encoding = 0;
#endif
- config->utf8_mode = 0;
- config->dev_mode = 0;
}
From 410759fba80aded5247b693c60745aa16906f3bb Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Sat, 18 May 2019 04:17:01 +0200
Subject: [PATCH 104/199] bpo-36763: Remove _PyCoreConfig.dll_path (GH-13402)
---
Include/cpython/coreconfig.h | 3 ---
Include/internal/pycore_pathconfig.h | 4 ++++
Lib/test/test_embed.py | 3 ---
PC/getpathp.c | 18 ++++++++----------
Python/coreconfig.c | 12 ------------
Python/pathconfig.c | 16 +++-------------
6 files changed, 15 insertions(+), 41 deletions(-)
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index ca71c15b67d..a71f16171b7 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -353,9 +353,6 @@ typedef struct {
wchar_t *base_prefix; /* sys.base_prefix */
wchar_t *exec_prefix; /* sys.exec_prefix */
wchar_t *base_exec_prefix; /* sys.base_exec_prefix */
-#ifdef MS_WINDOWS
- wchar_t *dll_path; /* Windows DLL path */
-#endif
/* --- Parameter only used by Py_Main() ---------- */
diff --git a/Include/internal/pycore_pathconfig.h b/Include/internal/pycore_pathconfig.h
index 9eb8e88df76..bee391187cc 100644
--- a/Include/internal/pycore_pathconfig.h
+++ b/Include/internal/pycore_pathconfig.h
@@ -53,6 +53,10 @@ PyAPI_FUNC(int) _Py_FindEnvConfigValue(
wchar_t *value,
size_t value_size);
+#ifdef MS_WINDOWS
+extern wchar_t* _Py_GetDLLPath(void);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 6b77a2d1fd8..5a5419dcfcf 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -369,7 +369,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'legacy_windows_fs_encoding': 0,
})
DEFAULT_CORE_CONFIG.update({
- 'dll_path': GET_DEFAULT_CONFIG,
'legacy_windows_stdio': 0,
})
@@ -466,8 +465,6 @@ def get_expected_config(self, expected_preconfig, expected, env, api,
'filesystem_errors': sys.getfilesystemencodeerrors(),
'module_search_paths': core_config['module_search_paths'],
}
- if sys.platform == 'win32':
- data['dll_path'] = core_config['dll_path']
data = json.dumps(data)
data = data.encode('utf-8')
diff --git a/PC/getpathp.c b/PC/getpathp.c
index 64aa1e0d141..62c42ecefe9 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -508,8 +508,8 @@ getpythonregpath(HKEY keyBase, int skipcore)
#endif /* Py_ENABLE_SHARED */
-static _PyInitError
-get_dll_path(PyCalculatePath *calculate, _PyPathConfig *config)
+wchar_t*
+_Py_GetDLLPath(void)
{
wchar_t dll_path[MAXPATHLEN+1];
memset(dll_path, 0, sizeof(dll_path));
@@ -525,11 +525,7 @@ get_dll_path(PyCalculatePath *calculate, _PyPathConfig *config)
dll_path[0] = 0;
#endif
- config->dll_path = _PyMem_RawWcsdup(dll_path);
- if (config->dll_path == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
- return _Py_INIT_OK();
+ return _PyMem_RawWcsdup(dll_path);
}
@@ -956,9 +952,11 @@ calculate_path_impl(const _PyCoreConfig *core_config,
{
_PyInitError err;
- err = get_dll_path(calculate, config);
- if (_Py_INIT_FAILED(err)) {
- return err;
+ assert(config->dll_path == NULL);
+
+ config->dll_path = _Py_GetDLLPath();
+ if (config->dll_path == NULL) {
+ return _Py_INIT_NO_MEMORY();
}
err = get_program_full_path(core_config, calculate, config);
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index 3678d124067..470bda87028 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -531,9 +531,6 @@ _PyCoreConfig_Clear(_PyCoreConfig *config)
CLEAR(config->prefix);
CLEAR(config->base_prefix);
CLEAR(config->exec_prefix);
-#ifdef MS_WINDOWS
- CLEAR(config->dll_path);
-#endif
CLEAR(config->base_exec_prefix);
CLEAR(config->filesystem_encoding);
@@ -761,9 +758,6 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
COPY_WSTR_ATTR(prefix);
COPY_WSTR_ATTR(base_prefix);
COPY_WSTR_ATTR(exec_prefix);
-#ifdef MS_WINDOWS
- COPY_WSTR_ATTR(dll_path);
-#endif
COPY_WSTR_ATTR(base_exec_prefix);
COPY_ATTR(site_import);
@@ -864,9 +858,6 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config)
SET_ITEM_WSTR(base_prefix);
SET_ITEM_WSTR(exec_prefix);
SET_ITEM_WSTR(base_exec_prefix);
-#ifdef MS_WINDOWS
- SET_ITEM_WSTR(dll_path);
-#endif
SET_ITEM_INT(site_import);
SET_ITEM_INT(bytes_warning);
SET_ITEM_INT(inspect);
@@ -2355,9 +2346,6 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
assert(config->base_prefix != NULL);
assert(config->exec_prefix != NULL);
assert(config->base_exec_prefix != NULL);
-#ifdef MS_WINDOWS
- assert(config->dll_path != NULL);
-#endif
}
assert(config->filesystem_encoding != NULL);
assert(config->filesystem_errors != NULL);
diff --git a/Python/pathconfig.c b/Python/pathconfig.c
index c8c69ebad6a..3d9d3b1b205 100644
--- a/Python/pathconfig.c
+++ b/Python/pathconfig.c
@@ -214,7 +214,8 @@ _PyCoreConfig_SetPathConfig(const _PyCoreConfig *core_config)
goto no_memory;
}
#ifdef MS_WINDOWS
- if (copy_wstr(&path_config.dll_path, core_config->dll_path) < 0) {
+ path_config.dll_path = _Py_GetDLLPath();
+ if (path_config.dll_path == NULL) {
goto no_memory;
}
#endif
@@ -322,14 +323,6 @@ _PyCoreConfig_CalculatePathConfig(_PyCoreConfig *config)
}
}
-#ifdef MS_WINDOWS
- if (config->dll_path == NULL) {
- if (copy_wstr(&config->dll_path, path_config.dll_path) < 0) {
- goto no_memory;
- }
- }
-#endif
-
if (path_config.isolated != -1) {
config->isolated = path_config.isolated;
}
@@ -356,9 +349,6 @@ _PyCoreConfig_InitPathConfig(_PyCoreConfig *config)
if (!config->use_module_search_paths
|| (config->executable == NULL)
|| (config->prefix == NULL)
-#ifdef MS_WINDOWS
- || (config->dll_path == NULL)
-#endif
|| (config->exec_prefix == NULL))
{
_PyInitError err = _PyCoreConfig_CalculatePathConfig(config);
@@ -435,7 +425,7 @@ Py_SetPath(const wchar_t *path)
new_config.exec_prefix = _PyMem_RawWcsdup(L"");
alloc_error |= (new_config.exec_prefix == NULL);
#ifdef MS_WINDOWS
- new_config.dll_path = _PyMem_RawWcsdup(L"");
+ new_config.dll_path = _Py_GetDLLPath();
alloc_error |= (new_config.dll_path == NULL);
#endif
new_config.module_search_path = _PyMem_RawWcsdup(path);
From 73934b9da07daefb203e7d26089e7486a1ce4fdf Mon Sep 17 00:00:00 2001
From: Mark Dickinson
Date: Sat, 18 May 2019 12:29:50 +0100
Subject: [PATCH 105/199] bpo-36887: add math.isqrt (GH-13244)
* Add math.isqrt function computing the integer square root.
* Code cleanup: remove redundant comments, rename some variables.
* Tighten up code a bit more; use Py_XDECREF to simplify error handling.
* Update Modules/mathmodule.c
Co-Authored-By: Serhiy Storchaka
* Update Modules/mathmodule.c
Use real argument clinic type instead of an alias
Co-Authored-By: Serhiy Storchaka
* Add proof sketch
* Updates from review.
* Correct and expand documentation.
* Fix bad reference handling on error; make some variables block-local; other tidying.
* Style and consistency fixes.
* Add missing error check; don't try to DECREF a NULL a
* Simplify some error returns.
* Another two test cases:
- clarify that floats are rejected even if they happen to be
squares of small integers
- TypeError beats ValueError for a negative float
* Documentation and markup improvements; thanks Serhiy for the suggestions!
* Cleaner Misc/NEWS entry wording.
* Clean up (with one fix) to the algorithm explanation and proof.
---
Doc/library/math.rst | 17 ++
Doc/whatsnew/3.8.rst | 3 +
Lib/test/test_math.py | 51 ++++
.../2019-05-11-14-50-59.bpo-36887.XD3f22.rst | 1 +
Modules/clinic/mathmodule.c.h | 11 +-
Modules/mathmodule.c | 261 ++++++++++++++++++
6 files changed, 343 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-11-14-50-59.bpo-36887.XD3f22.rst
diff --git a/Doc/library/math.rst b/Doc/library/math.rst
index 49f932d0384..bf660ae9def 100644
--- a/Doc/library/math.rst
+++ b/Doc/library/math.rst
@@ -166,6 +166,20 @@ Number-theoretic and representation functions
Return ``True`` if *x* is a NaN (not a number), and ``False`` otherwise.
+.. function:: isqrt(n)
+
+ Return the integer square root of the nonnegative integer *n*. This is the
+ floor of the exact square root of *n*, or equivalently the greatest integer
+ *a* such that *a*\ ² |nbsp| ≤ |nbsp| *n*.
+
+ For some applications, it may be more convenient to have the least integer
+ *a* such that *n* |nbsp| ≤ |nbsp| *a*\ ², or in other words the ceiling of
+ the exact square root of *n*. For positive *n*, this can be computed using
+ ``a = 1 + isqrt(n - 1)``.
+
+ .. versionadded:: 3.8
+
+
.. function:: ldexp(x, i)
Return ``x * (2**i)``. This is essentially the inverse of function
@@ -538,3 +552,6 @@ Constants
Module :mod:`cmath`
Complex number versions of many of these functions.
+
+.. |nbsp| unicode:: 0xA0
+ :trim:
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index d47993bf112..07da4047a38 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -344,6 +344,9 @@ Added new function, :func:`math.prod`, as analogous function to :func:`sum`
that returns the product of a 'start' value (default: 1) times an iterable of
numbers. (Contributed by Pablo Galindo in :issue:`35606`)
+Added new function :func:`math.isqrt` for computing integer square roots.
+(Contributed by Mark Dickinson in :issue:`36887`.)
+
os
--
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py
index cb05dee0e0f..a11a3447856 100644
--- a/Lib/test/test_math.py
+++ b/Lib/test/test_math.py
@@ -912,6 +912,57 @@ class T(tuple):
self.assertEqual(math.dist(p, q), 5*scale)
self.assertEqual(math.dist(q, p), 5*scale)
+ def testIsqrt(self):
+ # Test a variety of inputs, large and small.
+ test_values = (
+ list(range(1000))
+ + list(range(10**6 - 1000, 10**6 + 1000))
+ + [3**9999, 10**5001]
+ )
+
+ for value in test_values:
+ with self.subTest(value=value):
+ s = math.isqrt(value)
+ self.assertIs(type(s), int)
+ self.assertLessEqual(s*s, value)
+ self.assertLess(value, (s+1)*(s+1))
+
+ # Negative values
+ with self.assertRaises(ValueError):
+ math.isqrt(-1)
+
+ # Integer-like things
+ s = math.isqrt(True)
+ self.assertIs(type(s), int)
+ self.assertEqual(s, 1)
+
+ s = math.isqrt(False)
+ self.assertIs(type(s), int)
+ self.assertEqual(s, 0)
+
+ class IntegerLike(object):
+ def __init__(self, value):
+ self.value = value
+
+ def __index__(self):
+ return self.value
+
+ s = math.isqrt(IntegerLike(1729))
+ self.assertIs(type(s), int)
+ self.assertEqual(s, 41)
+
+ with self.assertRaises(ValueError):
+ math.isqrt(IntegerLike(-3))
+
+ # Non-integer-like things
+ bad_values = [
+ 3.5, "a string", decimal.Decimal("3.5"), 3.5j,
+ 100.0, -4.0,
+ ]
+ for value in bad_values:
+ with self.subTest(value=value):
+ with self.assertRaises(TypeError):
+ math.isqrt(value)
def testLdexp(self):
self.assertRaises(TypeError, math.ldexp)
diff --git a/Misc/NEWS.d/next/Library/2019-05-11-14-50-59.bpo-36887.XD3f22.rst b/Misc/NEWS.d/next/Library/2019-05-11-14-50-59.bpo-36887.XD3f22.rst
new file mode 100644
index 00000000000..fe2929cea85
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-11-14-50-59.bpo-36887.XD3f22.rst
@@ -0,0 +1 @@
+Add new function :func:`math.isqrt` to compute integer square roots.
diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h
index 1806a01588c..e677bd896cd 100644
--- a/Modules/clinic/mathmodule.c.h
+++ b/Modules/clinic/mathmodule.c.h
@@ -65,6 +65,15 @@ PyDoc_STRVAR(math_fsum__doc__,
#define MATH_FSUM_METHODDEF \
{"fsum", (PyCFunction)math_fsum, METH_O, math_fsum__doc__},
+PyDoc_STRVAR(math_isqrt__doc__,
+"isqrt($module, n, /)\n"
+"--\n"
+"\n"
+"Return the integer part of the square root of the input.");
+
+#define MATH_ISQRT_METHODDEF \
+ {"isqrt", (PyCFunction)math_isqrt, METH_O, math_isqrt__doc__},
+
PyDoc_STRVAR(math_factorial__doc__,
"factorial($module, x, /)\n"
"--\n"
@@ -628,4 +637,4 @@ skip_optional_kwonly:
exit:
return return_value;
}
-/*[clinic end generated code: output=96e71135dce41c48 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=aeed62f403b90199 input=a9049054013a1b77]*/
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 8f6a303cc4d..821309221f8 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -1476,6 +1476,266 @@ count_set_bits(unsigned long n)
return count;
}
+/* Integer square root
+
+Given a nonnegative integer `n`, we want to compute the largest integer
+`a` for which `a * a <= n`, or equivalently the integer part of the exact
+square root of `n`.
+
+We use an adaptive-precision pure-integer version of Newton's iteration. Given
+a positive integer `n`, the algorithm produces at each iteration an integer
+approximation `a` to the square root of `n >> s` for some even integer `s`,
+with `s` decreasing as the iterations progress. On the final iteration, `s` is
+zero and we have an approximation to the square root of `n` itself.
+
+At every step, the approximation `a` is strictly within 1.0 of the true square
+root, so we have
+
+ (a - 1)**2 < (n >> s) < (a + 1)**2
+
+After the final iteration, a check-and-correct step is needed to determine
+whether `a` or `a - 1` gives the desired integer square root of `n`.
+
+The algorithm is remarkable in its simplicity. There's no need for a
+per-iteration check-and-correct step, and termination is straightforward: the
+number of iterations is known in advance (it's exactly `floor(log2(log2(n)))`
+for `n > 1`). The only tricky part of the correctness proof is in establishing
+that the bound `(a - 1)**2 < (n >> s) < (a + 1)**2` is maintained from one
+iteration to the next. A sketch of the proof of this is given below.
+
+In addition to the proof sketch, a formal, computer-verified proof
+of correctness (using Lean) of an equivalent recursive algorithm can be found
+here:
+
+ https://github.com/mdickinson/snippets/blob/master/proofs/isqrt/src/isqrt.lean
+
+
+Here's Python code equivalent to the C implementation below:
+
+ def isqrt(n):
+ """
+ Return the integer part of the square root of the input.
+ """
+ n = operator.index(n)
+
+ if n < 0:
+ raise ValueError("isqrt() argument must be nonnegative")
+ if n == 0:
+ return 0
+
+ c = (n.bit_length() - 1) // 2
+ a = 1
+ d = 0
+ for s in reversed(range(c.bit_length())):
+ e = d
+ d = c >> s
+ a = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a
+ assert (a-1)**2 < n >> 2*(c - d) < (a+1)**2
+
+ return a - (a*a > n)
+
+
+Sketch of proof of correctness
+------------------------------
+
+The delicate part of the correctness proof is showing that the loop invariant
+is preserved from one iteration to the next. That is, just before the line
+
+ a = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a
+
+is executed in the above code, we know that
+
+ (1) (a - 1)**2 < (n >> 2*(c - e)) < (a + 1)**2.
+
+(since `e` is always the value of `d` from the previous iteration). We must
+prove that after that line is executed, we have
+
+ (a - 1)**2 < (n >> 2*(c - d)) < (a + 1)**2
+
+To faciliate the proof, we make some changes of notation. Write `m` for
+`n >> 2*(c-d)`, and write `b` for the new value of `a`, so
+
+ b = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a
+
+or equivalently:
+
+ (2) b = (a << d - e - 1) + (m >> d - e + 1) // a
+
+Then we can rewrite (1) as:
+
+ (3) (a - 1)**2 < (m >> 2*(d - e)) < (a + 1)**2
+
+and we must show that (b - 1)**2 < m < (b + 1)**2.
+
+From this point on, we switch to mathematical notation, so `/` means exact
+division rather than integer division and `^` is used for exponentiation. We
+use the `√` symbol for the exact square root. In (3), we can remove the
+implicit floor operation to give:
+
+ (4) (a - 1)^2 < m / 4^(d - e) < (a + 1)^2
+
+Taking square roots throughout (4), scaling by `2^(d-e)`, and rearranging gives
+
+ (5) 0 <= | 2^(d-e)a - √m | < 2^(d-e)
+
+Squaring and dividing through by `2^(d-e+1) a` gives
+
+ (6) 0 <= 2^(d-e-1) a + m / (2^(d-e+1) a) - √m < 2^(d-e-1) / a
+
+We'll show below that `2^(d-e-1) <= a`. Given that, we can replace the
+right-hand side of (6) with `1`, and now replacing the central
+term `m / (2^(d-e+1) a)` with its floor in (6) gives
+
+ (7) -1 < 2^(d-e-1) a + m // 2^(d-e+1) a - √m < 1
+
+Or equivalently, from (2):
+
+ (7) -1 < b - √m < 1
+
+and rearranging gives that `(b-1)^2 < m < (b+1)^2`, which is what we needed
+to prove.
+
+We're not quite done: we still have to prove the inequality `2^(d - e - 1) <=
+a` that was used to get line (7) above. From the definition of `c`, we have
+`4^c <= n`, which implies
+
+ (8) 4^d <= m
+
+also, since `e == d >> 1`, `d` is at most `2e + 1`, from which it follows
+that `2d - 2e - 1 <= d` and hence that
+
+ (9) 4^(2d - 2e - 1) <= m
+
+Dividing both sides by `4^(d - e)` gives
+
+ (10) 4^(d - e - 1) <= m / 4^(d - e)
+
+But we know from (4) that `m / 4^(d-e) < (a + 1)^2`, hence
+
+ (11) 4^(d - e - 1) < (a + 1)^2
+
+Now taking square roots of both sides and observing that both `2^(d-e-1)` and
+`a` are integers gives `2^(d - e - 1) <= a`, which is what we needed. This
+completes the proof sketch.
+
+*/
+
+/*[clinic input]
+math.isqrt
+
+ n: object
+ /
+
+Return the integer part of the square root of the input.
+[clinic start generated code]*/
+
+static PyObject *
+math_isqrt(PyObject *module, PyObject *n)
+/*[clinic end generated code: output=35a6f7f980beab26 input=5b6e7ae4fa6c43d6]*/
+{
+ int a_too_large, s;
+ size_t c, d;
+ PyObject *a = NULL, *b;
+
+ n = PyNumber_Index(n);
+ if (n == NULL) {
+ return NULL;
+ }
+
+ if (_PyLong_Sign(n) < 0) {
+ PyErr_SetString(
+ PyExc_ValueError,
+ "isqrt() argument must be nonnegative");
+ goto error;
+ }
+ if (_PyLong_Sign(n) == 0) {
+ Py_DECREF(n);
+ return PyLong_FromLong(0);
+ }
+
+ c = _PyLong_NumBits(n);
+ if (c == (size_t)(-1)) {
+ goto error;
+ }
+ c = (c - 1U) / 2U;
+
+ /* s = c.bit_length() */
+ s = 0;
+ while ((c >> s) > 0) {
+ ++s;
+ }
+
+ a = PyLong_FromLong(1);
+ if (a == NULL) {
+ goto error;
+ }
+ d = 0;
+ while (--s >= 0) {
+ PyObject *q, *shift;
+ size_t e = d;
+
+ d = c >> s;
+
+ /* q = (n >> 2*c - e - d + 1) // a */
+ shift = PyLong_FromSize_t(2U*c - d - e + 1U);
+ if (shift == NULL) {
+ goto error;
+ }
+ q = PyNumber_Rshift(n, shift);
+ Py_DECREF(shift);
+ if (q == NULL) {
+ goto error;
+ }
+ Py_SETREF(q, PyNumber_FloorDivide(q, a));
+ if (q == NULL) {
+ goto error;
+ }
+
+ /* a = (a << d - 1 - e) + q */
+ shift = PyLong_FromSize_t(d - 1U - e);
+ if (shift == NULL) {
+ Py_DECREF(q);
+ goto error;
+ }
+ Py_SETREF(a, PyNumber_Lshift(a, shift));
+ Py_DECREF(shift);
+ if (a == NULL) {
+ Py_DECREF(q);
+ goto error;
+ }
+ Py_SETREF(a, PyNumber_Add(a, q));
+ Py_DECREF(q);
+ if (a == NULL) {
+ goto error;
+ }
+ }
+
+ /* The correct result is either a or a - 1. Figure out which, and
+ decrement a if necessary. */
+
+ /* a_too_large = n < a * a */
+ b = PyNumber_Multiply(a, a);
+ if (b == NULL) {
+ goto error;
+ }
+ a_too_large = PyObject_RichCompareBool(n, b, Py_LT);
+ Py_DECREF(b);
+ if (a_too_large == -1) {
+ goto error;
+ }
+
+ if (a_too_large) {
+ Py_SETREF(a, PyNumber_Subtract(a, _PyLong_One));
+ }
+ Py_DECREF(n);
+ return a;
+
+ error:
+ Py_XDECREF(a);
+ Py_DECREF(n);
+ return NULL;
+}
+
/* Divide-and-conquer factorial algorithm
*
* Based on the formula and pseudo-code provided at:
@@ -2737,6 +2997,7 @@ static PyMethodDef math_methods[] = {
MATH_ISFINITE_METHODDEF
MATH_ISINF_METHODDEF
MATH_ISNAN_METHODDEF
+ MATH_ISQRT_METHODDEF
MATH_LDEXP_METHODDEF
{"lgamma", math_lgamma, METH_O, math_lgamma_doc},
MATH_LOG_METHODDEF
From e917f2ed9af044fe808fc9b4ddc6c5eb99003500 Mon Sep 17 00:00:00 2001
From: Raymond Hettinger
Date: Sat, 18 May 2019 10:18:29 -0700
Subject: [PATCH 106/199] bpo-36546: Add more tests and expand docs (#13406)
---
Doc/library/statistics.rst | 31 ++++++++++++++++++++----------
Lib/test/test_statistics.py | 38 ++++++++++++++++++++++++++-----------
2 files changed, 48 insertions(+), 21 deletions(-)
diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst
index fb7df4e7188..bc841fda72f 100644
--- a/Doc/library/statistics.rst
+++ b/Doc/library/statistics.rst
@@ -511,22 +511,33 @@ However, for reading convenience, most of the examples show sorted sequences.
is not least 1.
The *dist* can be any iterable containing sample data or it can be an
- instance of a class that defines an :meth:`~inv_cdf` method.
+ instance of a class that defines an :meth:`~inv_cdf` method. For meaningful
+ results, the number of data points in *dist* should be larger than *n*.
Raises :exc:`StatisticsError` if there are not at least two data points.
For sample data, the cut points are linearly interpolated from the
two nearest data points. For example, if a cut point falls one-third
of the distance between two sample values, ``100`` and ``112``, the
- cut-point will evaluate to ``104``. Other selection methods may be
- offered in the future (for example choose ``100`` as the nearest
- value or compute ``106`` as the midpoint). This might matter if
- there are too few samples for a given number of cut points.
+ cut-point will evaluate to ``104``.
- If *method* is set to *inclusive*, *dist* is treated as population data.
- The minimum value is treated as the 0th percentile and the maximum
- value is treated as the 100th percentile. If *dist* is an instance of
- a class that defines an :meth:`~inv_cdf` method, setting *method*
- has no effect.
+ The *method* for computing quantiles can be varied depending on
+ whether the data in *dist* includes or excludes the lowest and
+ highest possible values from the population.
+
+ The default *method* is "exclusive" and is used for data sampled from
+ a population that can have more extreme values than found in the
+ samples. The portion of the population falling below the *i-th* of
+ *m* data points is computed as ``i / (m + 1)``.
+
+ Setting the *method* to "inclusive" is used for describing population
+ data or for samples that include the extreme points. The minimum
+ value in *dist* is treated as the 0th percentile and the maximum
+ value is treated as the 100th percentile. The portion of the
+ population falling below the *i-th* of *m* data points is computed as
+ ``(i - 1) / (m - 1)``.
+
+ If *dist* is an instance of a class that defines an
+ :meth:`~inv_cdf` method, setting *method* has no effect.
.. doctest::
diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py
index 1922de5df4b..946c7428c61 100644
--- a/Lib/test/test_statistics.py
+++ b/Lib/test/test_statistics.py
@@ -2161,17 +2161,18 @@ def test_specific_cases(self):
# Quantiles should be idempotent
if len(expected) >= 2:
self.assertEqual(quantiles(expected, n=n), expected)
- # Cross-check against other methods
- if len(data) >= n:
- # After end caps are added, method='inclusive' should
- # give the same result as method='exclusive' whenever
- # there are more data points than desired cut points.
- padded_data = [min(data) - 1000] + data + [max(data) + 1000]
- self.assertEqual(
- quantiles(data, n=n),
- quantiles(padded_data, n=n, method='inclusive'),
- (n, data),
- )
+ # Cross-check against method='inclusive' which should give
+ # the same result after adding in minimum and maximum values
+ # extrapolated from the two lowest and two highest points.
+ sdata = sorted(data)
+ lo = 2 * sdata[0] - sdata[1]
+ hi = 2 * sdata[-1] - sdata[-2]
+ padded_data = data + [lo, hi]
+ self.assertEqual(
+ quantiles(data, n=n),
+ quantiles(padded_data, n=n, method='inclusive'),
+ (n, data),
+ )
# Invariant under tranlation and scaling
def f(x):
return 3.5 * x - 1234.675
@@ -2188,6 +2189,11 @@ def f(x):
actual = quantiles(statistics.NormalDist(), n=n)
self.assertTrue(all(math.isclose(e, a, abs_tol=0.0001)
for e, a in zip(expected, actual)))
+ # Q2 agrees with median()
+ for k in range(2, 60):
+ data = random.choices(range(100), k=k)
+ q1, q2, q3 = quantiles(data)
+ self.assertEqual(q2, statistics.median(data))
def test_specific_cases_inclusive(self):
# Match results computed by hand and cross-checked
@@ -2233,6 +2239,11 @@ def f(x):
actual = quantiles(statistics.NormalDist(), n=n, method="inclusive")
self.assertTrue(all(math.isclose(e, a, abs_tol=0.0001)
for e, a in zip(expected, actual)))
+ # Natural deciles
+ self.assertEqual(quantiles([0, 100], n=10, method='inclusive'),
+ [10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0])
+ self.assertEqual(quantiles(range(0, 101), n=10, method='inclusive'),
+ [10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0])
# Whenever n is smaller than the number of data points, running
# method='inclusive' should give the same result as method='exclusive'
# after the two included extreme points are removed.
@@ -2242,6 +2253,11 @@ def f(x):
data.remove(max(data))
expected = quantiles(data, n=32)
self.assertEqual(expected, actual)
+ # Q2 agrees with median()
+ for k in range(2, 60):
+ data = random.choices(range(100), k=k)
+ q1, q2, q3 = quantiles(data, method='inclusive')
+ self.assertEqual(q2, statistics.median(data))
def test_equal_inputs(self):
quantiles = statistics.quantiles
From abea73bf4a320ff658c9a98fef3d948a142e61a9 Mon Sep 17 00:00:00 2001
From: Anthony Sottile
Date: Sat, 18 May 2019 11:27:17 -0700
Subject: [PATCH 107/199] bpo-2180: Treat line continuation at EOF as a
`SyntaxError` (GH-13401)
This makes the parser consistent with the tokenize module (already the case
in `pypy`).
sample
------
```python
x = 5\
```
before
------
```console
$ python3 t.py
$ python3 -mtokenize t.py
t.py:2:0: error: EOF in multi-line statement
```
after
-----
```console
$ ./python t.py
File "t.py", line 3
x = 5\
^
SyntaxError: unexpected EOF while parsing
$ ./python -m tokenize t.py
t.py:2:0: error: EOF in multi-line statement
```
https://bugs.python.org/issue2180
---
Lib/test/test_eof.py | 26 ++++++++++++++++++-
.../2019-05-17-18-34-30.bpo-2180.aBqHeW.rst | 1 +
Parser/tokenizer.c | 11 +++++++-
3 files changed, 36 insertions(+), 2 deletions(-)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-05-17-18-34-30.bpo-2180.aBqHeW.rst
diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py
index 7baa7ae57c6..a091ceaa25b 100644
--- a/Lib/test/test_eof.py
+++ b/Lib/test/test_eof.py
@@ -1,7 +1,9 @@
"""test script for a few new invalid token catches"""
-import unittest
+import sys
from test import support
+from test.support import script_helper
+import unittest
class EOFTestCase(unittest.TestCase):
def test_EOFC(self):
@@ -24,5 +26,27 @@ def test_EOFS(self):
else:
raise support.TestFailed
+ def test_line_continuation_EOF(self):
+ """A contination at the end of input must be an error; bpo2180."""
+ expect = 'unexpected EOF while parsing (, line 1)'
+ with self.assertRaises(SyntaxError) as excinfo:
+ exec('x = 5\\')
+ self.assertEqual(str(excinfo.exception), expect)
+ with self.assertRaises(SyntaxError) as excinfo:
+ exec('\\')
+ self.assertEqual(str(excinfo.exception), expect)
+
+ @unittest.skipIf(not sys.executable, "sys.executable required")
+ def test_line_continuation_EOF_from_file_bpo2180(self):
+ """Ensure tok_nextc() does not add too many ending newlines."""
+ with support.temp_dir() as temp_dir:
+ file_name = script_helper.make_script(temp_dir, 'foo', '\\')
+ rc, out, err = script_helper.assert_python_failure(file_name)
+ self.assertIn(b'unexpected EOF while parsing', err)
+
+ file_name = script_helper.make_script(temp_dir, 'foo', 'y = 6\\')
+ rc, out, err = script_helper.assert_python_failure(file_name)
+ self.assertIn(b'unexpected EOF while parsing', err)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-17-18-34-30.bpo-2180.aBqHeW.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-17-18-34-30.bpo-2180.aBqHeW.rst
new file mode 100644
index 00000000000..a2207c17aea
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-17-18-34-30.bpo-2180.aBqHeW.rst
@@ -0,0 +1 @@
+Treat line continuation at EOF as a ``SyntaxError`` by Anthony Sottile.
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index 5dc2ae65c42..e52d498d554 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -983,7 +983,8 @@ tok_nextc(struct tok_state *tok)
return EOF;
/* Last line does not end in \n,
fake one */
- strcpy(tok->inp, "\n");
+ if (tok->inp[-1] != '\n')
+ strcpy(tok->inp, "\n");
}
tok->inp = strchr(tok->inp, '\0');
done = tok->inp[-1] == '\n';
@@ -1674,6 +1675,14 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
tok->cur = tok->inp;
return ERRORTOKEN;
}
+ c = tok_nextc(tok);
+ if (c == EOF) {
+ tok->done = E_EOF;
+ tok->cur = tok->inp;
+ return ERRORTOKEN;
+ } else {
+ tok_backup(tok, c);
+ }
tok->cont_line = 1;
goto again; /* Read next line */
}
From 56027ccd6b9dab4a090e4fef8574933fb9a36ff2 Mon Sep 17 00:00:00 2001
From: Abhishek Kumar Singh
Date: Sun, 19 May 2019 02:06:19 +0530
Subject: [PATCH 108/199] bpo-19376: Added doc mentioning `datetime.strptime()`
without a year fails for Feb 29. (GH-10243)
---
Doc/library/datetime.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst
index abdc9773548..3c45e56b5f4 100644
--- a/Doc/library/datetime.rst
+++ b/Doc/library/datetime.rst
@@ -2048,6 +2048,9 @@ For :class:`date` objects, the format codes for hours, minutes, seconds, and
microseconds should not be used, as :class:`date` objects have no such
values. If they're used anyway, ``0`` is substituted for them.
+For the :meth:`datetime.strptime` class method, the default value is ``1900-01-01T00:00:00.000``:
+any components not specified in the format string will be pulled from the default value. [#]_
+
The full set of format codes supported varies across platforms, because Python
calls the platform C library's :func:`strftime` function, and platform
variations are common. To see the full set of format codes supported on your
@@ -2282,3 +2285,4 @@ Notes:
.. rubric:: Footnotes
.. [#] If, that is, we ignore the effects of Relativity
+.. [#] Passing ``datetime.strptime('Feb 29', '%b %d')`` will fail since ``1900`` is not a leap year.
From eab99650799699f766c2660f4cfa8ff3f9e8457f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Batuhan=20Ta=C5=9Fkaya?=
<47358913+isidentical@users.noreply.github.com>
Date: Sun, 19 May 2019 00:53:53 +0300
Subject: [PATCH 109/199] bpo-36567: Use manpages_url to create links for man
pages (GH-13339)
---
Doc/conf.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Doc/conf.py b/Doc/conf.py
index afe66270c10..e85ea5b2d2f 100644
--- a/Doc/conf.py
+++ b/Doc/conf.py
@@ -23,6 +23,9 @@
except ImportError:
_tkinter = None
'''
+
+manpages_url = 'https://manpages.debian.org/{path}'
+
# General substitutions.
project = 'Python'
copyright = '2001-%s, Python Software Foundation' % time.strftime('%Y')
From fa19a25c238d0769e6a5aa63ce05133d66043556 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Batuhan=20Ta=C5=9Fkaya?=
<47358913+isidentical@users.noreply.github.com>
Date: Sun, 19 May 2019 01:10:20 +0300
Subject: [PATCH 110/199] Add support for PEP572 in ast_unparse.c (GH-13337)
---
Lib/test/test_future.py | 2 ++
.../2019-05-15-14-01-09.bpo-36826.GLrO3W.rst | 1 +
Python/ast_unparse.c | 13 +++++++++++++
3 files changed, 16 insertions(+)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-05-15-14-01-09.bpo-36826.GLrO3W.rst
diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py
index 38de3dfdafc..cd320a266a8 100644
--- a/Lib/test/test_future.py
+++ b/Lib/test/test_future.py
@@ -275,6 +275,8 @@ def test_annotations(self):
eq('f((x for x in a), 2)')
eq('(((a)))', 'a')
eq('(((a, b)))', '(a, b)')
+ eq("(x:=10)")
+ eq("f'{(x:=10):=10}'")
if __name__ == "__main__":
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-15-14-01-09.bpo-36826.GLrO3W.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-15-14-01-09.bpo-36826.GLrO3W.rst
new file mode 100644
index 00000000000..5a1b51999f2
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-15-14-01-09.bpo-36826.GLrO3W.rst
@@ -0,0 +1 @@
+Add NamedExpression kind support to ast_unparse.c
diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c
index 25a5c698a1d..5f366a188b3 100644
--- a/Python/ast_unparse.c
+++ b/Python/ast_unparse.c
@@ -809,6 +809,17 @@ append_ast_await(_PyUnicodeWriter *writer, expr_ty e, int level)
return 0;
}
+static int
+append_named_expr(_PyUnicodeWriter *writer, expr_ty e, int level)
+{
+ APPEND_STR_IF(level > PR_TUPLE, "(");
+ APPEND_EXPR(e->v.NamedExpr.target, PR_ATOM);
+ APPEND_STR(":=");
+ APPEND_EXPR(e->v.NamedExpr.value, PR_ATOM);
+ APPEND_STR_IF(level > PR_TUPLE, ")");
+ return 0;
+}
+
static int
append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level)
{
@@ -867,6 +878,8 @@ append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level)
return append_ast_list(writer, e);
case Tuple_kind:
return append_ast_tuple(writer, e, level);
+ case NamedExpr_kind:
+ return append_named_expr(writer, e, level);
default:
PyErr_SetString(PyExc_SystemError,
"unknown expression kind");
From da6129e821099c1372d511a11d18af83d6d5d128 Mon Sep 17 00:00:00 2001
From: Pablo Galindo
Date: Sat, 18 May 2019 23:40:22 +0100
Subject: [PATCH 111/199] bpo-36961: Handle positional-only arguments in
uparse.c (GH-13412)
---
Lib/test/test_future.py | 12 ++++++++++++
Python/ast_unparse.c | 22 ++++++++++++++++------
2 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py
index cd320a266a8..dd148b62956 100644
--- a/Lib/test/test_future.py
+++ b/Lib/test/test_future.py
@@ -183,6 +183,18 @@ def test_annotations(self):
eq('lambda a, b, c=True: a')
eq("lambda a, b, c=True, *, d=1 << v2, e='str': a")
eq("lambda a, b, c=True, *vararg, d, e='str', **kwargs: a + b")
+ eq("lambda a, /, b, c=True, *vararg, d, e='str', **kwargs: a + b")
+ eq('lambda x, /: x')
+ eq('lambda x=1, /: x')
+ eq('lambda x, /, y: x + y')
+ eq('lambda x=1, /, y=2: x + y')
+ eq('lambda x, /, y=1: x + y')
+ eq('lambda x, /, y=1, *, z=3: x + y + z')
+ eq('lambda x=1, /, y=2, *, z=3: x + y + z')
+ eq('lambda x=1, /, y=2, *, z: x + y + z')
+ eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2: x + y + z + w + l + l2')
+ eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2, **kwargs: x + y + z + w + l + l2')
+ eq('lambda x, /, y=1, *, z: x + y + z')
eq('lambda x: lambda y: x + y')
eq('1 if True else 2')
eq('str or None if int or True else str or bytes or None')
diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c
index 5f366a188b3..f1b991a7c38 100644
--- a/Python/ast_unparse.c
+++ b/Python/ast_unparse.c
@@ -193,22 +193,30 @@ static int
append_ast_args(_PyUnicodeWriter *writer, arguments_ty args)
{
bool first;
- Py_ssize_t i, di, arg_count, default_count;
+ Py_ssize_t i, di, arg_count, posonlyarg_count, default_count;
first = true;
- /* positional arguments with defaults */
+ /* positional-only and positional arguments with defaults */
+ posonlyarg_count = asdl_seq_LEN(args->posonlyargs);
arg_count = asdl_seq_LEN(args->args);
default_count = asdl_seq_LEN(args->defaults);
- for (i = 0; i < arg_count; i++) {
+ for (i = 0; i < posonlyarg_count + arg_count; i++) {
APPEND_STR_IF_NOT_FIRST(", ");
- APPEND(arg, (arg_ty)asdl_seq_GET(args->args, i));
+ if (i < posonlyarg_count){
+ APPEND(arg, (arg_ty)asdl_seq_GET(args->posonlyargs, i));
+ } else {
+ APPEND(arg, (arg_ty)asdl_seq_GET(args->args, i-posonlyarg_count));
+ }
- di = i - arg_count + default_count;
+ di = i - posonlyarg_count - arg_count + default_count;
if (di >= 0) {
APPEND_STR("=");
APPEND_EXPR((expr_ty)asdl_seq_GET(args->defaults, di), PR_TEST);
}
+ if (posonlyarg_count && i + 1 == posonlyarg_count) {
+ APPEND_STR(", /");
+ }
}
/* vararg, or bare '*' if no varargs but keyword-only arguments present */
@@ -251,7 +259,9 @@ static int
append_ast_lambda(_PyUnicodeWriter *writer, expr_ty e, int level)
{
APPEND_STR_IF(level > PR_TEST, "(");
- APPEND_STR(asdl_seq_LEN(e->v.Lambda.args->args) ? "lambda " : "lambda");
+ Py_ssize_t n_positional = (asdl_seq_LEN(e->v.Lambda.args->args) +
+ asdl_seq_LEN(e->v.Lambda.args->posonlyargs));
+ APPEND_STR(n_positional ? "lambda " : "lambda");
APPEND(args, e->v.Lambda.args);
APPEND_STR(": ");
APPEND_EXPR(e->v.Lambda.body, PR_TEST);
From 9892f454d11b7ea9ba394a115b3e6f48ef6f78fe Mon Sep 17 00:00:00 2001
From: Jelle Zijlstra
Date: Sat, 18 May 2019 17:17:56 -0700
Subject: [PATCH 112/199] bpo-33519: clarify that .copy() is not part of the
MutableSequence ABC (GH-6965)
---
Doc/library/stdtypes.rst | 6 ++++--
.../Documentation/2018-05-17-21-02-00.bpo-33519.Q7s2FB.rst | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)
create mode 100644 Misc/NEWS.d/next/Documentation/2018-05-17-21-02-00.bpo-33519.Q7s2FB.rst
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index 53337291dd3..293a1ab6a0d 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -1114,7 +1114,7 @@ Notes:
item is removed and returned.
(3)
- ``remove`` raises :exc:`ValueError` when *x* is not found in *s*.
+ :meth:`remove` raises :exc:`ValueError` when *x* is not found in *s*.
(4)
The :meth:`reverse` method modifies the sequence in place for economy of
@@ -1124,7 +1124,9 @@ Notes:
(5)
:meth:`clear` and :meth:`!copy` are included for consistency with the
interfaces of mutable containers that don't support slicing operations
- (such as :class:`dict` and :class:`set`)
+ (such as :class:`dict` and :class:`set`). :meth:`!copy` is not part of the
+ :class:`collections.abc.MutableSequence` ABC, but most concrete
+ mutable sequence classes provide it.
.. versionadded:: 3.3
:meth:`clear` and :meth:`!copy` methods.
diff --git a/Misc/NEWS.d/next/Documentation/2018-05-17-21-02-00.bpo-33519.Q7s2FB.rst b/Misc/NEWS.d/next/Documentation/2018-05-17-21-02-00.bpo-33519.Q7s2FB.rst
new file mode 100644
index 00000000000..0ee6c0d5f8e
--- /dev/null
+++ b/Misc/NEWS.d/next/Documentation/2018-05-17-21-02-00.bpo-33519.Q7s2FB.rst
@@ -0,0 +1 @@
+Clarify that `copy()` is not part of the `MutableSequence` ABC.
From f665b96e92a6a6943e312e2c606f348db95939ab Mon Sep 17 00:00:00 2001
From: Ashwin Ramaswami
Date: Sat, 18 May 2019 18:17:48 -0700
Subject: [PATCH 113/199] Fix typo in test comment (GH-11442)
---
Lib/unittest/test/test_case.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
index 687fe5b65f1..c2401c39b91 100644
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -620,7 +620,7 @@ def AllSnakesCreatedEqual(a, b, msg=None):
self.addTypeEqualityFunc(SadSnake, AllSnakesCreatedEqual)
self.assertEqual(s1, s2)
# No this doesn't clean up and remove the SadSnake equality func
- # from this TestCase instance but since its a local nothing else
+ # from this TestCase instance but since it's local nothing else
# will ever notice that.
def testAssertIs(self):
From 1d5bdef550d4395211fbe5f3c1444d7ea5bb54a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bo=C5=A1tjan=20Mejak?=
Date: Sun, 19 May 2019 11:01:36 +0200
Subject: [PATCH 114/199] Orthographical fix (GH-13418)
Add a missing comma.
---
Doc/library/asyncio-task.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
index e7cf39b2bcc..bb064bd93de 100644
--- a/Doc/library/asyncio-task.rst
+++ b/Doc/library/asyncio-task.rst
@@ -40,7 +40,7 @@ be executed::
>>> main()
-To actually run a coroutine asyncio provides three main mechanisms:
+To actually run a coroutine, asyncio provides three main mechanisms:
* The :func:`asyncio.run` function to run the top-level
entry point "main()" function (see the above example.)
From a5119e7d75c9729fc36c059d05f3d7132e7f6bb4 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka
Date: Sun, 19 May 2019 14:14:38 +0300
Subject: [PATCH 115/199] bpo-36957: Add _PyLong_Rshift() and _PyLong_Lshift().
(GH-13416)
---
Include/longobject.h | 3 ++
Modules/mathmodule.c | 30 +++---------
Objects/floatobject.c | 4 +-
Objects/longobject.c | 103 ++++++++++++++++++++++++++++++------------
4 files changed, 87 insertions(+), 53 deletions(-)
diff --git a/Include/longobject.h b/Include/longobject.h
index b696f544b9c..a24bbea3a90 100644
--- a/Include/longobject.h
+++ b/Include/longobject.h
@@ -230,6 +230,9 @@ PyAPI_FUNC(PyObject *) _PyLong_GCD(PyObject *, PyObject *);
#ifndef Py_LIMITED_API
PyAPI_DATA(PyObject *) _PyLong_Zero;
PyAPI_DATA(PyObject *) _PyLong_One;
+
+PyAPI_FUNC(PyObject *) _PyLong_Rshift(PyObject *, size_t);
+PyAPI_FUNC(PyObject *) _PyLong_Lshift(PyObject *, size_t);
#endif
#ifdef __cplusplus
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 821309221f8..7a0044a9fcf 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -1671,18 +1671,13 @@ math_isqrt(PyObject *module, PyObject *n)
}
d = 0;
while (--s >= 0) {
- PyObject *q, *shift;
+ PyObject *q;
size_t e = d;
d = c >> s;
/* q = (n >> 2*c - e - d + 1) // a */
- shift = PyLong_FromSize_t(2U*c - d - e + 1U);
- if (shift == NULL) {
- goto error;
- }
- q = PyNumber_Rshift(n, shift);
- Py_DECREF(shift);
+ q = _PyLong_Rshift(n, 2U*c - d - e + 1U);
if (q == NULL) {
goto error;
}
@@ -1692,13 +1687,7 @@ math_isqrt(PyObject *module, PyObject *n)
}
/* a = (a << d - 1 - e) + q */
- shift = PyLong_FromSize_t(d - 1U - e);
- if (shift == NULL) {
- Py_DECREF(q);
- goto error;
- }
- Py_SETREF(a, PyNumber_Lshift(a, shift));
- Py_DECREF(shift);
+ Py_SETREF(a, _PyLong_Lshift(a, d - 1U - e));
if (a == NULL) {
Py_DECREF(q);
goto error;
@@ -1939,9 +1928,9 @@ static PyObject *
math_factorial(PyObject *module, PyObject *arg)
/*[clinic end generated code: output=6686f26fae00e9ca input=6d1c8105c0d91fb4]*/
{
- long x;
+ long x, two_valuation;
int overflow;
- PyObject *result, *odd_part, *two_valuation, *pyint_form;
+ PyObject *result, *odd_part, *pyint_form;
if (PyFloat_Check(arg)) {
PyObject *lx;
@@ -1990,13 +1979,8 @@ math_factorial(PyObject *module, PyObject *arg)
odd_part = factorial_odd_part(x);
if (odd_part == NULL)
return NULL;
- two_valuation = PyLong_FromLong(x - count_set_bits(x));
- if (two_valuation == NULL) {
- Py_DECREF(odd_part);
- return NULL;
- }
- result = PyNumber_Lshift(odd_part, two_valuation);
- Py_DECREF(two_valuation);
+ two_valuation = x - count_set_bits(x);
+ result = _PyLong_Lshift(odd_part, two_valuation);
Py_DECREF(odd_part);
return result;
}
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index adb9b80c271..4ff43bb338f 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -463,13 +463,13 @@ float_richcompare(PyObject *v, PyObject *w, int op)
*/
PyObject *temp;
- temp = PyNumber_Lshift(ww, _PyLong_One);
+ temp = _PyLong_Lshift(ww, 1);
if (temp == NULL)
goto Error;
Py_DECREF(ww);
ww = temp;
- temp = PyNumber_Lshift(vv, _PyLong_One);
+ temp = _PyLong_Lshift(vv, 1);
if (temp == NULL)
goto Error;
Py_DECREF(vv);
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 9fb1fb02c27..1934328820c 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -4416,9 +4416,9 @@ long_bool(PyLongObject *v)
/* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */
static int
-divmod_shift(PyLongObject *shiftby, Py_ssize_t *wordshift, digit *remshift)
+divmod_shift(PyObject *shiftby, Py_ssize_t *wordshift, digit *remshift)
{
- assert(PyLong_Check((PyObject *)shiftby));
+ assert(PyLong_Check(shiftby));
assert(Py_SIZE(shiftby) >= 0);
Py_ssize_t lshiftby = PyLong_AsSsize_t((PyObject *)shiftby);
if (lshiftby >= 0) {
@@ -4430,7 +4430,7 @@ divmod_shift(PyLongObject *shiftby, Py_ssize_t *wordshift, digit *remshift)
be that PyLong_AsSsize_t raised an OverflowError. */
assert(PyErr_ExceptionMatches(PyExc_OverflowError));
PyErr_Clear();
- PyLongObject *wordshift_obj = divrem1(shiftby, PyLong_SHIFT, remshift);
+ PyLongObject *wordshift_obj = divrem1((PyLongObject *)shiftby, PyLong_SHIFT, remshift);
if (wordshift_obj == NULL) {
return -1;
}
@@ -4448,19 +4448,11 @@ divmod_shift(PyLongObject *shiftby, Py_ssize_t *wordshift, digit *remshift)
}
static PyObject *
-long_rshift(PyLongObject *a, PyLongObject *b)
+long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift)
{
PyLongObject *z = NULL;
- Py_ssize_t newsize, wordshift, hishift, i, j;
- digit loshift, lomask, himask;
-
- CHECK_BINOP(a, b);
-
- if (Py_SIZE(b) < 0) {
- PyErr_SetString(PyExc_ValueError,
- "negative shift count");
- return NULL;
- }
+ Py_ssize_t newsize, hishift, i, j;
+ digit lomask, himask;
if (Py_SIZE(a) < 0) {
/* Right shifting negative numbers is harder */
@@ -4468,7 +4460,7 @@ long_rshift(PyLongObject *a, PyLongObject *b)
a1 = (PyLongObject *) long_invert(a);
if (a1 == NULL)
return NULL;
- a2 = (PyLongObject *) long_rshift(a1, b);
+ a2 = (PyLongObject *) long_rshift1(a1, wordshift, remshift);
Py_DECREF(a1);
if (a2 == NULL)
return NULL;
@@ -4476,19 +4468,17 @@ long_rshift(PyLongObject *a, PyLongObject *b)
Py_DECREF(a2);
}
else {
- if (divmod_shift(b, &wordshift, &loshift) < 0)
- return NULL;
newsize = Py_SIZE(a) - wordshift;
if (newsize <= 0)
return PyLong_FromLong(0);
- hishift = PyLong_SHIFT - loshift;
+ hishift = PyLong_SHIFT - remshift;
lomask = ((digit)1 << hishift) - 1;
himask = PyLong_MASK ^ lomask;
z = _PyLong_New(newsize);
if (z == NULL)
return NULL;
for (i = 0, j = wordshift; i < newsize; i++, j++) {
- z->ob_digit[i] = (a->ob_digit[j] >> loshift) & lomask;
+ z->ob_digit[i] = (a->ob_digit[j] >> remshift) & lomask;
if (i+1 < newsize)
z->ob_digit[i] |= (a->ob_digit[j+1] << hishift) & himask;
}
@@ -4498,15 +4488,10 @@ long_rshift(PyLongObject *a, PyLongObject *b)
}
static PyObject *
-long_lshift(PyObject *v, PyObject *w)
+long_rshift(PyObject *a, PyObject *b)
{
- /* This version due to Tim Peters */
- PyLongObject *a = (PyLongObject*)v;
- PyLongObject *b = (PyLongObject*)w;
- PyLongObject *z = NULL;
- Py_ssize_t oldsize, newsize, wordshift, i, j;
+ Py_ssize_t wordshift;
digit remshift;
- twodigits accum;
CHECK_BINOP(a, b);
@@ -4517,9 +4502,35 @@ long_lshift(PyObject *v, PyObject *w)
if (Py_SIZE(a) == 0) {
return PyLong_FromLong(0);
}
-
if (divmod_shift(b, &wordshift, &remshift) < 0)
return NULL;
+ return long_rshift1((PyLongObject *)a, wordshift, remshift);
+}
+
+/* Return a >> shiftby. */
+PyObject *
+_PyLong_Rshift(PyObject *a, size_t shiftby)
+{
+ Py_ssize_t wordshift;
+ digit remshift;
+
+ assert(PyLong_Check(a));
+ if (Py_SIZE(a) == 0) {
+ return PyLong_FromLong(0);
+ }
+ wordshift = shiftby / PyLong_SHIFT;
+ remshift = shiftby % PyLong_SHIFT;
+ return long_rshift1((PyLongObject *)a, wordshift, remshift);
+}
+
+static PyObject *
+long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift)
+{
+ /* This version due to Tim Peters */
+ PyLongObject *z = NULL;
+ Py_ssize_t oldsize, newsize, i, j;
+ twodigits accum;
+
oldsize = Py_ABS(Py_SIZE(a));
newsize = oldsize + wordshift;
if (remshift)
@@ -4547,6 +4558,42 @@ long_lshift(PyObject *v, PyObject *w)
return (PyObject *) maybe_small_long(z);
}
+static PyObject *
+long_lshift(PyObject *a, PyObject *b)
+{
+ Py_ssize_t wordshift;
+ digit remshift;
+
+ CHECK_BINOP(a, b);
+
+ if (Py_SIZE(b) < 0) {
+ PyErr_SetString(PyExc_ValueError, "negative shift count");
+ return NULL;
+ }
+ if (Py_SIZE(a) == 0) {
+ return PyLong_FromLong(0);
+ }
+ if (divmod_shift(b, &wordshift, &remshift) < 0)
+ return NULL;
+ return long_lshift1((PyLongObject *)a, wordshift, remshift);
+}
+
+/* Return a << shiftby. */
+PyObject *
+_PyLong_Lshift(PyObject *a, size_t shiftby)
+{
+ Py_ssize_t wordshift;
+ digit remshift;
+
+ assert(PyLong_Check(a));
+ if (Py_SIZE(a) == 0) {
+ return PyLong_FromLong(0);
+ }
+ wordshift = shiftby / PyLong_SHIFT;
+ remshift = shiftby % PyLong_SHIFT;
+ return long_lshift1((PyLongObject *)a, wordshift, remshift);
+}
+
/* Compute two's complement of digit vector a[0:m], writing result to
z[0:m]. The digit vector a need not be normalized, but should not
be entirely zero. a and z may point to the same digit vector. */
@@ -5552,7 +5599,7 @@ static PyNumberMethods long_as_number = {
(inquiry)long_bool, /*tp_bool*/
(unaryfunc)long_invert, /*nb_invert*/
long_lshift, /*nb_lshift*/
- (binaryfunc)long_rshift, /*nb_rshift*/
+ long_rshift, /*nb_rshift*/
long_and, /*nb_and*/
long_xor, /*nb_xor*/
long_or, /*nb_or*/
From c661b30f89ffe7a7995538d3b1649469b184bee4 Mon Sep 17 00:00:00 2001
From: Xtreak
Date: Sun, 19 May 2019 19:10:06 +0530
Subject: [PATCH 116/199] bpo-36948: Fix NameError in
urllib.request.URLopener.retrieve (GH-13389)
---
Lib/test/test_urllib.py | 20 ++++++++++++++++++-
Lib/urllib/request.py | 10 +++++-----
.../2019-05-17-21-42-58.bpo-36948.vnUDvk.rst | 2 ++
3 files changed, 26 insertions(+), 6 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-05-17-21-42-58.bpo-36948.vnUDvk.rst
diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py
index 7214492eca9..74b19fbdcd8 100644
--- a/Lib/test/test_urllib.py
+++ b/Lib/test/test_urllib.py
@@ -1445,7 +1445,7 @@ def test_thishost(self):
self.assertIsInstance(urllib.request.thishost(), tuple)
-class URLopener_Tests(unittest.TestCase):
+class URLopener_Tests(FakeHTTPMixin, unittest.TestCase):
"""Testcase to test the open method of URLopener class."""
def test_quoted_open(self):
@@ -1463,6 +1463,24 @@ def open_spam(self, url):
"spam://c:|windows%/:=&?~#+!$,;'@()*[]|/path/"),
"//c:|windows%/:=&?~#+!$,;'@()*[]|/path/")
+ @support.ignore_warnings(category=DeprecationWarning)
+ def test_urlopener_retrieve_file(self):
+ with support.temp_dir() as tmpdir:
+ fd, tmpfile = tempfile.mkstemp(dir=tmpdir)
+ os.close(fd)
+ fileurl = "file:" + urllib.request.pathname2url(tmpfile)
+ filename, _ = urllib.request.URLopener().retrieve(fileurl)
+ self.assertEqual(filename, tmpfile)
+
+ @support.ignore_warnings(category=DeprecationWarning)
+ def test_urlopener_retrieve_remote(self):
+ url = "http://www.python.org/file.txt"
+ self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!")
+ self.addCleanup(self.unfakehttp)
+ filename, _ = urllib.request.URLopener().retrieve(url)
+ self.assertEqual(os.path.splitext(filename)[1], ".txt")
+
+
# Just commented them out.
# Can't really tell why keep failing in windows and sparc.
# Everywhere else they work ok, but on those machines, sometimes
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
index df2ff06f0fc..230ac390abb 100644
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -1783,7 +1783,7 @@ def retrieve(self, url, filename=None, reporthook=None, data=None):
fp = self.open_local_file(url1)
hdrs = fp.info()
fp.close()
- return url2pathname(splithost(url1)[1]), hdrs
+ return url2pathname(_splithost(url1)[1]), hdrs
except OSError as msg:
pass
fp = self.open(url, data)
@@ -1792,10 +1792,10 @@ def retrieve(self, url, filename=None, reporthook=None, data=None):
if filename:
tfp = open(filename, 'wb')
else:
- garbage, path = splittype(url)
- garbage, path = splithost(path or "")
- path, garbage = splitquery(path or "")
- path, garbage = splitattr(path or "")
+ garbage, path = _splittype(url)
+ garbage, path = _splithost(path or "")
+ path, garbage = _splitquery(path or "")
+ path, garbage = _splitattr(path or "")
suffix = os.path.splitext(path)[1]
(fd, filename) = tempfile.mkstemp(suffix)
self.__tempfiles.append(filename)
diff --git a/Misc/NEWS.d/next/Library/2019-05-17-21-42-58.bpo-36948.vnUDvk.rst b/Misc/NEWS.d/next/Library/2019-05-17-21-42-58.bpo-36948.vnUDvk.rst
new file mode 100644
index 00000000000..c8cfa54067f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-17-21-42-58.bpo-36948.vnUDvk.rst
@@ -0,0 +1,2 @@
+Fix :exc:`NameError` in :meth:`urllib.request.URLopener.retrieve`. Patch by
+Karthikeyan Singaravelan.
From f4e1babf44792bdeb0c01da96821ba0800a51fd8 Mon Sep 17 00:00:00 2001
From: Bar Harel
Date: Sun, 19 May 2019 16:57:13 +0300
Subject: [PATCH 117/199] bpo-27141: Fix collections.UserList and UserDict
shallow copy. (GH-4094)
---
Lib/collections/__init__.py | 14 +++++++++++
Lib/test/test_collections.py | 24 +++++++++++++++++++
.../2017-10-24-00-42-14.bpo-27141.zbAgSs.rst | 3 +++
3 files changed, 41 insertions(+)
create mode 100644 Misc/NEWS.d/next/Library/2017-10-24-00-42-14.bpo-27141.zbAgSs.rst
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index 706907ad4a2..960d82a5dcf 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -1038,6 +1038,13 @@ def __contains__(self, key):
# Now, add the methods in dicts but not in MutableMapping
def __repr__(self): return repr(self.data)
+ def __copy__(self):
+ inst = self.__class__.__new__(self.__class__)
+ inst.__dict__.update(self.__dict__)
+ # Create a copy and avoid triggering descriptors
+ inst.__dict__["data"] = self.__dict__["data"].copy()
+ return inst
+
def copy(self):
if self.__class__ is UserDict:
return UserDict(self.data.copy())
@@ -1050,6 +1057,7 @@ def copy(self):
self.data = data
c.update(self)
return c
+
@classmethod
def fromkeys(cls, iterable, value=None):
d = cls()
@@ -1118,6 +1126,12 @@ def __mul__(self, n):
def __imul__(self, n):
self.data *= n
return self
+ def __copy__(self):
+ inst = self.__class__.__new__(self.__class__)
+ inst.__dict__.update(self.__dict__)
+ # Create a copy and avoid triggering descriptors
+ inst.__dict__["data"] = self.__dict__["data"][:]
+ return inst
def append(self, item): self.data.append(item)
def insert(self, i, item): self.data.insert(i, item)
def pop(self, i=-1): return self.data.pop(i)
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index 1f619bcdac9..e2d04d5b476 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -37,6 +37,20 @@ def _superset_test(self, a, b):
b=b.__name__,
),
)
+
+ def _copy_test(self, obj):
+ # Test internal copy
+ obj_copy = obj.copy()
+ self.assertIsNot(obj.data, obj_copy.data)
+ self.assertEqual(obj.data, obj_copy.data)
+
+ # Test copy.copy
+ obj.test = [1234] # Make sure instance vars are also copied.
+ obj_copy = copy.copy(obj)
+ self.assertIsNot(obj.data, obj_copy.data)
+ self.assertEqual(obj.data, obj_copy.data)
+ self.assertIs(obj.test, obj_copy.test)
+
def test_str_protocol(self):
self._superset_test(UserString, str)
@@ -46,6 +60,16 @@ def test_list_protocol(self):
def test_dict_protocol(self):
self._superset_test(UserDict, dict)
+ def test_list_copy(self):
+ obj = UserList()
+ obj.append(123)
+ self._copy_test(obj)
+
+ def test_dict_copy(self):
+ obj = UserDict()
+ obj[123] = "abc"
+ self._copy_test(obj)
+
################################################################################
### ChainMap (helper class for configparser and the string module)
diff --git a/Misc/NEWS.d/next/Library/2017-10-24-00-42-14.bpo-27141.zbAgSs.rst b/Misc/NEWS.d/next/Library/2017-10-24-00-42-14.bpo-27141.zbAgSs.rst
new file mode 100644
index 00000000000..76c2abbf82d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-10-24-00-42-14.bpo-27141.zbAgSs.rst
@@ -0,0 +1,3 @@
+Added a ``__copy__()`` to ``collections.UserList`` and
+``collections.UserDict`` in order to correctly implement shallow copying of
+the objects. Patch by Bar Harel.
From 7c59362a15dfce538512ff1fce4e07d33a925cfb Mon Sep 17 00:00:00 2001
From: Berker Peksag
Date: Sun, 19 May 2019 18:56:15 +0300
Subject: [PATCH 118/199] bpo-29183: Fix double exceptions in
wsgiref.handlers.BaseHandler (GH-12914)
---
Lib/test/test_wsgiref.py | 25 +++++++++++++++++++
Lib/wsgiref/handlers.py | 11 +++++++-
.../2019-04-22-22-55-29.bpo-29183.MILvsk.rst | 3 +++
3 files changed, 38 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-04-22-22-55-29.bpo-29183.MILvsk.rst
diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py
index 46f88a94434..42432bfbd26 100644
--- a/Lib/test/test_wsgiref.py
+++ b/Lib/test/test_wsgiref.py
@@ -806,6 +806,31 @@ def write(self, b):
self.assertFalse(stderr.getvalue())
+ def testDontResetInternalStateOnException(self):
+ class CustomException(ValueError):
+ pass
+
+ # We are raising CustomException here to trigger an exception
+ # during the execution of SimpleHandler.finish_response(), so
+ # we can easily test that the internal state of the handler is
+ # preserved in case of an exception.
+ class AbortingWriter:
+ def write(self, b):
+ raise CustomException
+
+ stderr = StringIO()
+ environ = {"SERVER_PROTOCOL": "HTTP/1.0"}
+ h = SimpleHandler(BytesIO(), AbortingWriter(), stderr, environ)
+ h.run(hello_app)
+
+ self.assertIn("CustomException", stderr.getvalue())
+
+ # Test that the internal state of the handler is preserved.
+ self.assertIsNotNone(h.result)
+ self.assertIsNotNone(h.headers)
+ self.assertIsNotNone(h.status)
+ self.assertIsNotNone(h.environ)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/wsgiref/handlers.py b/Lib/wsgiref/handlers.py
index 834073d5009..31360e58785 100644
--- a/Lib/wsgiref/handlers.py
+++ b/Lib/wsgiref/handlers.py
@@ -183,7 +183,16 @@ def finish_response(self):
for data in self.result:
self.write(data)
self.finish_content()
- finally:
+ except:
+ # Call close() on the iterable returned by the WSGI application
+ # in case of an exception.
+ if hasattr(self.result, 'close'):
+ self.result.close()
+ raise
+ else:
+ # We only call close() when no exception is raised, because it
+ # will set status, result, headers, and environ fields to None.
+ # See bpo-29183 for more details.
self.close()
diff --git a/Misc/NEWS.d/next/Library/2019-04-22-22-55-29.bpo-29183.MILvsk.rst b/Misc/NEWS.d/next/Library/2019-04-22-22-55-29.bpo-29183.MILvsk.rst
new file mode 100644
index 00000000000..1d19f191eed
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-04-22-22-55-29.bpo-29183.MILvsk.rst
@@ -0,0 +1,3 @@
+Fix double exceptions in :class:`wsgiref.handlers.BaseHandler` by calling
+its :meth:`~wsgiref.handlers.BaseHandler.close` method only when no
+exception is raised.
From 5c08ce9bf712acbb3f05a3a57baf51fcb534cdf0 Mon Sep 17 00:00:00 2001
From: Mark Dickinson
Date: Sun, 19 May 2019 17:51:56 +0100
Subject: [PATCH 119/199] bpo-36957: Speed up math.isqrt (#13405)
* Add math.isqrt function computing the integer square root.
* Code cleanup: remove redundant comments, rename some variables.
* Tighten up code a bit more; use Py_XDECREF to simplify error handling.
* Update Modules/mathmodule.c
Co-Authored-By: Serhiy Storchaka
* Update Modules/mathmodule.c
Use real argument clinic type instead of an alias
Co-Authored-By: Serhiy Storchaka
* Add proof sketch
* Updates from review.
* Correct and expand documentation.
* Fix bad reference handling on error; make some variables block-local; other tidying.
* Style and consistency fixes.
* Add missing error check; don't try to DECREF a NULL a
* Simplify some error returns.
* Another two test cases:
- clarify that floats are rejected even if they happen to be
squares of small integers
- TypeError beats ValueError for a negative float
* Add fast path for small inputs. Needs tests.
* Speed up isqrt for n >= 2**64 as well; add extra tests.
* Reduce number of test-cases to avoid dominating the run-time of test_math.
* Don't perform unnecessary extra iterations when computing c_bit_length.
* Abstract common uint64_t code out into a separate function.
* Cleanup.
* Add a missing Py_DECREF in an error branch. More cleanup.
* Update Modules/mathmodule.c
Add missing `static` declaration to helper function.
Co-Authored-By: Serhiy Storchaka
* Add missing backtick.
---
Lib/test/test_math.py | 1 +
Modules/mathmodule.c | 64 +++++++++++++++++++++++++++++++++++++------
2 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py
index a11a3447856..853a0e62f82 100644
--- a/Lib/test/test_math.py
+++ b/Lib/test/test_math.py
@@ -917,6 +917,7 @@ def testIsqrt(self):
test_values = (
list(range(1000))
+ list(range(10**6 - 1000, 10**6 + 1000))
+ + [2**e + i for e in range(60, 200) for i in range(-40, 40)]
+ [3**9999, 10**5001]
)
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 7a0044a9fcf..a153e984ca5 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -1620,6 +1620,22 @@ completes the proof sketch.
*/
+
+/* Approximate square root of a large 64-bit integer.
+
+ Given `n` satisfying `2**62 <= n < 2**64`, return `a`
+ satisfying `(a - 1)**2 < n < (a + 1)**2`. */
+
+static uint64_t
+_approximate_isqrt(uint64_t n)
+{
+ uint32_t u = 1U + (n >> 62);
+ u = (u << 1) + (n >> 59) / u;
+ u = (u << 3) + (n >> 53) / u;
+ u = (u << 7) + (n >> 41) / u;
+ return (u << 15) + (n >> 17) / u;
+}
+
/*[clinic input]
math.isqrt
@@ -1633,8 +1649,9 @@ static PyObject *
math_isqrt(PyObject *module, PyObject *n)
/*[clinic end generated code: output=35a6f7f980beab26 input=5b6e7ae4fa6c43d6]*/
{
- int a_too_large, s;
+ int a_too_large, c_bit_length;
size_t c, d;
+ uint64_t m, u;
PyObject *a = NULL, *b;
n = PyNumber_Index(n);
@@ -1653,24 +1670,55 @@ math_isqrt(PyObject *module, PyObject *n)
return PyLong_FromLong(0);
}
+ /* c = (n.bit_length() - 1) // 2 */
c = _PyLong_NumBits(n);
if (c == (size_t)(-1)) {
goto error;
}
c = (c - 1U) / 2U;
- /* s = c.bit_length() */
- s = 0;
- while ((c >> s) > 0) {
- ++s;
+ /* Fast path: if c <= 31 then n < 2**64 and we can compute directly with a
+ fast, almost branch-free algorithm. In the final correction, we use `u*u
+ - 1 >= m` instead of the simpler `u*u > m` in order to get the correct
+ result in the corner case where `u=2**32`. */
+ if (c <= 31U) {
+ m = (uint64_t)PyLong_AsUnsignedLongLong(n);
+ Py_DECREF(n);
+ if (m == (uint64_t)(-1) && PyErr_Occurred()) {
+ return NULL;
+ }
+ u = _approximate_isqrt(m << (62U - 2U*c)) >> (31U - c);
+ u -= u * u - 1U >= m;
+ return PyLong_FromUnsignedLongLong((unsigned long long)u);
}
- a = PyLong_FromLong(1);
+ /* Slow path: n >= 2**64. We perform the first five iterations in C integer
+ arithmetic, then switch to using Python long integers. */
+
+ /* From n >= 2**64 it follows that c.bit_length() >= 6. */
+ c_bit_length = 6;
+ while ((c >> c_bit_length) > 0U) {
+ ++c_bit_length;
+ }
+
+ /* Initialise d and a. */
+ d = c >> (c_bit_length - 5);
+ b = _PyLong_Rshift(n, 2U*c - 62U);
+ if (b == NULL) {
+ goto error;
+ }
+ m = (uint64_t)PyLong_AsUnsignedLongLong(b);
+ Py_DECREF(b);
+ if (m == (uint64_t)(-1) && PyErr_Occurred()) {
+ goto error;
+ }
+ u = _approximate_isqrt(m) >> (31U - d);
+ a = PyLong_FromUnsignedLongLong((unsigned long long)u);
if (a == NULL) {
goto error;
}
- d = 0;
- while (--s >= 0) {
+
+ for (int s = c_bit_length - 6; s >= 0; --s) {
PyObject *q;
size_t e = d;
From 287b84de939db47aa8c6f30734ceb8aba9d1db29 Mon Sep 17 00:00:00 2001
From: Xtreak
Date: Mon, 20 May 2019 03:22:20 +0530
Subject: [PATCH 120/199] bpo-34580: Update sqlite3 examples to call close()
explicitly (GH-9079)
The sqlit3.Connection object doesn't call its close() method when it's used
as a context manager.
---
Doc/includes/sqlite3/adapter_datetime.py | 2 ++
Doc/includes/sqlite3/adapter_point_1.py | 2 ++
Doc/includes/sqlite3/adapter_point_2.py | 2 ++
Doc/includes/sqlite3/connect_db_1.py | 3 ---
Doc/includes/sqlite3/connect_db_2.py | 3 ---
Doc/includes/sqlite3/countcursors.py | 2 ++
Doc/includes/sqlite3/ctx_manager.py | 4 ++++
Doc/includes/sqlite3/execsql_fetchonerow.py | 2 ++
Doc/includes/sqlite3/execsql_printall_1.py | 2 ++
Doc/includes/sqlite3/execute_1.py | 2 ++
Doc/includes/sqlite3/execute_3.py | 12 ------------
Doc/includes/sqlite3/executemany_1.py | 2 ++
Doc/includes/sqlite3/executemany_2.py | 2 ++
Doc/includes/sqlite3/executescript.py | 1 +
Doc/includes/sqlite3/insert_more_people.py | 2 ++
Doc/includes/sqlite3/load_extension.py | 2 ++
Doc/includes/sqlite3/md5func.py | 2 ++
Doc/includes/sqlite3/mysumaggr.py | 2 ++
Doc/includes/sqlite3/parse_colnames.py | 2 ++
Doc/includes/sqlite3/pysqlite_datetime.py | 2 ++
Doc/includes/sqlite3/row_factory.py | 2 ++
Doc/includes/sqlite3/rowclass.py | 2 ++
Doc/includes/sqlite3/shortcut_methods.py | 4 ++++
Doc/includes/sqlite3/simple_tableprinter.py | 2 ++
Doc/includes/sqlite3/text_factory.py | 2 ++
Doc/library/sqlite3.rst | 6 +++++-
26 files changed, 52 insertions(+), 19 deletions(-)
delete mode 100644 Doc/includes/sqlite3/connect_db_1.py
delete mode 100644 Doc/includes/sqlite3/connect_db_2.py
delete mode 100644 Doc/includes/sqlite3/execute_3.py
diff --git a/Doc/includes/sqlite3/adapter_datetime.py b/Doc/includes/sqlite3/adapter_datetime.py
index be33395100c..d5221d80c35 100644
--- a/Doc/includes/sqlite3/adapter_datetime.py
+++ b/Doc/includes/sqlite3/adapter_datetime.py
@@ -13,3 +13,5 @@ def adapt_datetime(ts):
now = datetime.datetime.now()
cur.execute("select ?", (now,))
print(cur.fetchone()[0])
+
+con.close()
diff --git a/Doc/includes/sqlite3/adapter_point_1.py b/Doc/includes/sqlite3/adapter_point_1.py
index 6b1af841564..77daf8f16d2 100644
--- a/Doc/includes/sqlite3/adapter_point_1.py
+++ b/Doc/includes/sqlite3/adapter_point_1.py
@@ -14,3 +14,5 @@ def __conform__(self, protocol):
p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])
+
+con.close()
diff --git a/Doc/includes/sqlite3/adapter_point_2.py b/Doc/includes/sqlite3/adapter_point_2.py
index d670700f049..cb86331692b 100644
--- a/Doc/includes/sqlite3/adapter_point_2.py
+++ b/Doc/includes/sqlite3/adapter_point_2.py
@@ -15,3 +15,5 @@ def adapt_point(point):
p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])
+
+con.close()
diff --git a/Doc/includes/sqlite3/connect_db_1.py b/Doc/includes/sqlite3/connect_db_1.py
deleted file mode 100644
index 1b975232865..00000000000
--- a/Doc/includes/sqlite3/connect_db_1.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import sqlite3
-
-con = sqlite3.connect("mydb")
diff --git a/Doc/includes/sqlite3/connect_db_2.py b/Doc/includes/sqlite3/connect_db_2.py
deleted file mode 100644
index f9728b36135..00000000000
--- a/Doc/includes/sqlite3/connect_db_2.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import sqlite3
-
-con = sqlite3.connect(":memory:")
diff --git a/Doc/includes/sqlite3/countcursors.py b/Doc/includes/sqlite3/countcursors.py
index ef3e70a2a9c..112f47703a2 100644
--- a/Doc/includes/sqlite3/countcursors.py
+++ b/Doc/includes/sqlite3/countcursors.py
@@ -13,3 +13,5 @@ def cursor(self, *args, **kwargs):
cur1 = con.cursor()
cur2 = con.cursor()
print(con.numcursors)
+
+con.close()
diff --git a/Doc/includes/sqlite3/ctx_manager.py b/Doc/includes/sqlite3/ctx_manager.py
index 7af4ad1ecfb..6db77d45046 100644
--- a/Doc/includes/sqlite3/ctx_manager.py
+++ b/Doc/includes/sqlite3/ctx_manager.py
@@ -14,3 +14,7 @@
con.execute("insert into person(firstname) values (?)", ("Joe",))
except sqlite3.IntegrityError:
print("couldn't add Joe twice")
+
+# Connection object used as context manager only commits or rollbacks transactions,
+# so the connection object should be closed manually
+con.close()
diff --git a/Doc/includes/sqlite3/execsql_fetchonerow.py b/Doc/includes/sqlite3/execsql_fetchonerow.py
index 078873bfc97..115bcb50c7c 100644
--- a/Doc/includes/sqlite3/execsql_fetchonerow.py
+++ b/Doc/includes/sqlite3/execsql_fetchonerow.py
@@ -15,3 +15,5 @@
cur.execute(SELECT)
for row in cur:
print('%s is %d years old.' % (row[0], row[1]))
+
+con.close()
diff --git a/Doc/includes/sqlite3/execsql_printall_1.py b/Doc/includes/sqlite3/execsql_printall_1.py
index a4ce5c52814..19306e6e3ca 100644
--- a/Doc/includes/sqlite3/execsql_printall_1.py
+++ b/Doc/includes/sqlite3/execsql_printall_1.py
@@ -11,3 +11,5 @@
# Retrieve all rows as a sequence and print that sequence:
print(cur.fetchall())
+
+con.close()
diff --git a/Doc/includes/sqlite3/execute_1.py b/Doc/includes/sqlite3/execute_1.py
index f864a8984e4..3466b1265a5 100644
--- a/Doc/includes/sqlite3/execute_1.py
+++ b/Doc/includes/sqlite3/execute_1.py
@@ -14,3 +14,5 @@
cur.execute("select * from people where name_last=:who and age=:age", {"who": who, "age": age})
print(cur.fetchone())
+
+con.close()
diff --git a/Doc/includes/sqlite3/execute_3.py b/Doc/includes/sqlite3/execute_3.py
deleted file mode 100644
index 0353683fc70..00000000000
--- a/Doc/includes/sqlite3/execute_3.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import sqlite3
-
-con = sqlite3.connect("mydb")
-
-cur = con.cursor()
-
-who = "Yeltsin"
-age = 72
-
-cur.execute("select name_last, age from people where name_last=:who and age=:age",
- locals())
-print(cur.fetchone())
diff --git a/Doc/includes/sqlite3/executemany_1.py b/Doc/includes/sqlite3/executemany_1.py
index efae10637c7..edf6f8b7ebe 100644
--- a/Doc/includes/sqlite3/executemany_1.py
+++ b/Doc/includes/sqlite3/executemany_1.py
@@ -22,3 +22,5 @@ def __next__(self):
cur.execute("select c from characters")
print(cur.fetchall())
+
+con.close()
diff --git a/Doc/includes/sqlite3/executemany_2.py b/Doc/includes/sqlite3/executemany_2.py
index 527358ebc28..02a594c861e 100644
--- a/Doc/includes/sqlite3/executemany_2.py
+++ b/Doc/includes/sqlite3/executemany_2.py
@@ -13,3 +13,5 @@ def char_generator():
cur.execute("select c from characters")
print(cur.fetchall())
+
+con.close()
diff --git a/Doc/includes/sqlite3/executescript.py b/Doc/includes/sqlite3/executescript.py
index 7e5358178d4..aea8943fbee 100644
--- a/Doc/includes/sqlite3/executescript.py
+++ b/Doc/includes/sqlite3/executescript.py
@@ -22,3 +22,4 @@
1987
);
""")
+con.close()
diff --git a/Doc/includes/sqlite3/insert_more_people.py b/Doc/includes/sqlite3/insert_more_people.py
index edbc79e7e5b..10cf937243f 100644
--- a/Doc/includes/sqlite3/insert_more_people.py
+++ b/Doc/includes/sqlite3/insert_more_people.py
@@ -14,3 +14,5 @@
# The changes will not be saved unless the transaction is committed explicitly:
con.commit()
+
+con.close()
diff --git a/Doc/includes/sqlite3/load_extension.py b/Doc/includes/sqlite3/load_extension.py
index b997c70668a..624cfe262f3 100644
--- a/Doc/includes/sqlite3/load_extension.py
+++ b/Doc/includes/sqlite3/load_extension.py
@@ -24,3 +24,5 @@
""")
for row in con.execute("select rowid, name, ingredients from recipe where name match 'pie'"):
print(row)
+
+con.close()
diff --git a/Doc/includes/sqlite3/md5func.py b/Doc/includes/sqlite3/md5func.py
index 0056b2d6ce8..16dc348bf00 100644
--- a/Doc/includes/sqlite3/md5func.py
+++ b/Doc/includes/sqlite3/md5func.py
@@ -9,3 +9,5 @@ def md5sum(t):
cur = con.cursor()
cur.execute("select md5(?)", (b"foo",))
print(cur.fetchone()[0])
+
+con.close()
diff --git a/Doc/includes/sqlite3/mysumaggr.py b/Doc/includes/sqlite3/mysumaggr.py
index d2dfd2c0b98..11f96395b6c 100644
--- a/Doc/includes/sqlite3/mysumaggr.py
+++ b/Doc/includes/sqlite3/mysumaggr.py
@@ -18,3 +18,5 @@ def finalize(self):
cur.execute("insert into test(i) values (2)")
cur.execute("select mysum(i) from test")
print(cur.fetchone()[0])
+
+con.close()
diff --git a/Doc/includes/sqlite3/parse_colnames.py b/Doc/includes/sqlite3/parse_colnames.py
index cc68c76459e..5f01dbfe1cb 100644
--- a/Doc/includes/sqlite3/parse_colnames.py
+++ b/Doc/includes/sqlite3/parse_colnames.py
@@ -6,3 +6,5 @@
cur.execute('select ? as "x [timestamp]"', (datetime.datetime.now(),))
dt = cur.fetchone()[0]
print(dt, type(dt))
+
+con.close()
diff --git a/Doc/includes/sqlite3/pysqlite_datetime.py b/Doc/includes/sqlite3/pysqlite_datetime.py
index 68d49358a57..5d843f906b3 100644
--- a/Doc/includes/sqlite3/pysqlite_datetime.py
+++ b/Doc/includes/sqlite3/pysqlite_datetime.py
@@ -18,3 +18,5 @@
row = cur.fetchone()
print("current_date", row[0], type(row[0]))
print("current_timestamp", row[1], type(row[1]))
+
+con.close()
diff --git a/Doc/includes/sqlite3/row_factory.py b/Doc/includes/sqlite3/row_factory.py
index e436ffc6c80..9de6e7b1b90 100644
--- a/Doc/includes/sqlite3/row_factory.py
+++ b/Doc/includes/sqlite3/row_factory.py
@@ -11,3 +11,5 @@ def dict_factory(cursor, row):
cur = con.cursor()
cur.execute("select 1 as a")
print(cur.fetchone()["a"])
+
+con.close()
diff --git a/Doc/includes/sqlite3/rowclass.py b/Doc/includes/sqlite3/rowclass.py
index 92b5ad60cb5..fc60287069a 100644
--- a/Doc/includes/sqlite3/rowclass.py
+++ b/Doc/includes/sqlite3/rowclass.py
@@ -10,3 +10,5 @@
assert row["name"] == row["nAmE"]
assert row[1] == row["age"]
assert row[1] == row["AgE"]
+
+con.close()
diff --git a/Doc/includes/sqlite3/shortcut_methods.py b/Doc/includes/sqlite3/shortcut_methods.py
index 71600d4f60c..98a39411495 100644
--- a/Doc/includes/sqlite3/shortcut_methods.py
+++ b/Doc/includes/sqlite3/shortcut_methods.py
@@ -18,3 +18,7 @@
print(row)
print("I just deleted", con.execute("delete from person").rowcount, "rows")
+
+# close is not a shortcut method and it's not called automatically,
+# so the connection object should be closed manually
+con.close()
diff --git a/Doc/includes/sqlite3/simple_tableprinter.py b/Doc/includes/sqlite3/simple_tableprinter.py
index 231d8726cd4..148a1707f94 100644
--- a/Doc/includes/sqlite3/simple_tableprinter.py
+++ b/Doc/includes/sqlite3/simple_tableprinter.py
@@ -24,3 +24,5 @@
print(fieldValue.ljust(FIELD_MAX_WIDTH), end=' ')
print() # Finish the row with a newline.
+
+con.close()
diff --git a/Doc/includes/sqlite3/text_factory.py b/Doc/includes/sqlite3/text_factory.py
index 5f96cdb58da..a857a155cdd 100644
--- a/Doc/includes/sqlite3/text_factory.py
+++ b/Doc/includes/sqlite3/text_factory.py
@@ -25,3 +25,5 @@
cur.execute("select ?", ("bar",))
row = cur.fetchone()
assert row[0] == "barfoo"
+
+con.close()
diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst
index 37087ac5af4..20fca54aab1 100644
--- a/Doc/library/sqlite3.rst
+++ b/Doc/library/sqlite3.rst
@@ -537,6 +537,7 @@ Connection Objects
with open('dump.sql', 'w') as f:
for line in con.iterdump():
f.write('%s\n' % line)
+ con.close()
.. method:: backup(target, *, pages=0, progress=None, name="main", sleep=0.250)
@@ -573,8 +574,11 @@ Connection Objects
print(f'Copied {total-remaining} of {total} pages...')
con = sqlite3.connect('existing_db.db')
- with sqlite3.connect('backup.db') as bck:
+ bck = sqlite3.connect('backup.db')
+ with bck:
con.backup(bck, pages=1, progress=progress)
+ bck.close()
+ con.close()
Example 2, copy an existing database into a transient copy::
From d673810b9d9df6fbd29f5b7db3973d5adae10fd3 Mon Sep 17 00:00:00 2001
From: Lysandros Nikolaou
Date: Mon, 20 May 2019 00:11:21 +0200
Subject: [PATCH 121/199] bpo-35252: Remove FIXME from test_functools
(GH-10551)
---
Lib/functools.py | 8 +++++---
Lib/test/test_functools.py | 11 +++++------
.../Library/2019-04-02-19-23-12.bpo-35252.VooTVv.rst | 1 +
3 files changed, 11 insertions(+), 9 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2019-04-02-19-23-12.bpo-35252.VooTVv.rst
diff --git a/Lib/functools.py b/Lib/functools.py
index 28d9f6f75fd..c863341eec5 100644
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -861,9 +861,11 @@ def register(cls, func=None):
# only import typing if annotation parsing is necessary
from typing import get_type_hints
argname, cls = next(iter(get_type_hints(func).items()))
- assert isinstance(cls, type), (
- f"Invalid annotation for {argname!r}. {cls!r} is not a class."
- )
+ if not isinstance(cls, type):
+ raise TypeError(
+ f"Invalid annotation for {argname!r}. "
+ f"{cls!r} is not a class."
+ )
registry[cls] = func
if cache_token is None and hasattr(cls, '__abstractmethods__'):
cache_token = get_cache_token()
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index 85c65d18326..b89d77967a0 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -2355,9 +2355,6 @@ def _(arg):
))
self.assertTrue(str(exc.exception).endswith(msg_suffix))
- # FIXME: The following will only work after PEP 560 is implemented.
- return
-
with self.assertRaises(TypeError) as exc:
@i.register
def _(arg: typing.Iterable[str]):
@@ -2366,10 +2363,12 @@ def _(arg: typing.Iterable[str]):
# types from `typing`. Instead, annotate with regular types
# or ABCs.
return "I annotated with a generic collection"
- self.assertTrue(str(exc.exception).startswith(msg_prefix +
- "._"
+ self.assertTrue(str(exc.exception).startswith(
+ "Invalid annotation for 'arg'."
+ ))
+ self.assertTrue(str(exc.exception).endswith(
+ 'typing.Iterable[str] is not a class.'
))
- self.assertTrue(str(exc.exception).endswith(msg_suffix))
def test_invalid_positional_argument(self):
@functools.singledispatch
diff --git a/Misc/NEWS.d/next/Library/2019-04-02-19-23-12.bpo-35252.VooTVv.rst b/Misc/NEWS.d/next/Library/2019-04-02-19-23-12.bpo-35252.VooTVv.rst
new file mode 100644
index 00000000000..c8f3e7d5f5f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-04-02-19-23-12.bpo-35252.VooTVv.rst
@@ -0,0 +1 @@
+Throw a TypeError instead of an AssertionError when using an invalid type annotation with singledispatch.
From ed48866c55b8e4ee14faa8b5ad97819e8e74c98b Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Mon, 20 May 2019 00:14:57 +0200
Subject: [PATCH 122/199] bpo-35134: Split traceback.h header (GH-13430)
Add new Include/cpython/traceback.h and Include/internal/traceback.h
header files.
---
Include/cpython/traceback.h | 22 +++++++
Include/frameobject.h | 1 -
Include/genobject.h | 2 +
Include/internal/pycore_traceback.h | 92 +++++++++++++++++++++++++++
Include/traceback.h | 99 ++---------------------------
Modules/_tracemalloc.c | 1 +
Modules/faulthandler.c | 1 +
Python/pylifecycle.c | 1 +
8 files changed, 123 insertions(+), 96 deletions(-)
create mode 100644 Include/cpython/traceback.h
create mode 100644 Include/internal/pycore_traceback.h
diff --git a/Include/cpython/traceback.h b/Include/cpython/traceback.h
new file mode 100644
index 00000000000..746097daaf9
--- /dev/null
+++ b/Include/cpython/traceback.h
@@ -0,0 +1,22 @@
+#ifndef Py_CPYTHON_TRACEBACK_H
+# error "this header file must not be included directly"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _traceback {
+ PyObject_HEAD
+ struct _traceback *tb_next;
+ struct _frame *tb_frame;
+ int tb_lasti;
+ int tb_lineno;
+} PyTracebackObject;
+
+PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, PyObject *, int, int);
+PyAPI_FUNC(void) _PyTraceback_Add(const char *, const char *, int);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Include/frameobject.h b/Include/frameobject.h
index a95baf8867a..3bad86a66f7 100644
--- a/Include/frameobject.h
+++ b/Include/frameobject.h
@@ -1,4 +1,3 @@
-
/* Frame object interface */
#ifndef Py_LIMITED_API
diff --git a/Include/genobject.h b/Include/genobject.h
index 16b983339cc..6755963f332 100644
--- a/Include/genobject.h
+++ b/Include/genobject.h
@@ -8,6 +8,8 @@
extern "C" {
#endif
+#include "pystate.h" /* _PyErr_StackItem */
+
struct _frame; /* Avoid including frameobject.h */
/* _PyGenObject_HEAD defines the initial segment of generator
diff --git a/Include/internal/pycore_traceback.h b/Include/internal/pycore_traceback.h
new file mode 100644
index 00000000000..a96199bda5f
--- /dev/null
+++ b/Include/internal/pycore_traceback.h
@@ -0,0 +1,92 @@
+#ifndef Py_INTERNAL_TRACEBACK_H
+#define Py_INTERNAL_TRACEBACK_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
+#include "pystate.h" /* PyInterpreterState */
+
+/* Write the Python traceback into the file 'fd'. For example:
+
+ Traceback (most recent call first):
+ File "xxx", line xxx in
+ File "xxx", line xxx in
+ ...
+ File "xxx", line xxx in
+
+ This function is written for debug purpose only, to dump the traceback in
+ the worst case: after a segmentation fault, at fatal error, etc. That's why,
+ it is very limited. Strings are truncated to 100 characters and encoded to
+ ASCII with backslashreplace. It doesn't write the source code, only the
+ function name, filename and line number of each frame. Write only the first
+ 100 frames: if the traceback is truncated, write the line " ...".
+
+ This function is signal safe. */
+
+PyAPI_FUNC(void) _Py_DumpTraceback(
+ int fd,
+ PyThreadState *tstate);
+
+/* Write the traceback of all threads into the file 'fd'. current_thread can be
+ NULL.
+
+ Return NULL on success, or an error message on error.
+
+ This function is written for debug purpose only. It calls
+ _Py_DumpTraceback() for each thread, and so has the same limitations. It
+ only write the traceback of the first 100 threads: write "..." if there are
+ more threads.
+
+ If current_tstate is NULL, the function tries to get the Python thread state
+ of the current thread. It is not an error if the function is unable to get
+ the current Python thread state.
+
+ If interp is NULL, the function tries to get the interpreter state from
+ the current Python thread state, or from
+ _PyGILState_GetInterpreterStateUnsafe() in last resort.
+
+ It is better to pass NULL to interp and current_tstate, the function tries
+ different options to retrieve these informations.
+
+ This function is signal safe. */
+
+PyAPI_FUNC(const char*) _Py_DumpTracebackThreads(
+ int fd,
+ PyInterpreterState *interp,
+ PyThreadState *current_tstate);
+
+/* Write a Unicode object into the file descriptor fd. Encode the string to
+ ASCII using the backslashreplace error handler.
+
+ Do nothing if text is not a Unicode object. The function accepts Unicode
+ string which is not ready (PyUnicode_WCHAR_KIND).
+
+ This function is signal safe. */
+PyAPI_FUNC(void) _Py_DumpASCII(int fd, PyObject *text);
+
+/* Format an integer as decimal into the file descriptor fd.
+
+ This function is signal safe. */
+PyAPI_FUNC(void) _Py_DumpDecimal(
+ int fd,
+ unsigned long value);
+
+/* Format an integer as hexadecimal into the file descriptor fd with at least
+ width digits.
+
+ The maximum width is sizeof(unsigned long)*2 digits.
+
+ This function is signal safe. */
+PyAPI_FUNC(void) _Py_DumpHexadecimal(
+ int fd,
+ unsigned long value,
+ Py_ssize_t width);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_TRACEBACK_H */
diff --git a/Include/traceback.h b/Include/traceback.h
index b5874100f47..b451927fafa 100644
--- a/Include/traceback.h
+++ b/Include/traceback.h
@@ -1,117 +1,26 @@
-
#ifndef Py_TRACEBACK_H
#define Py_TRACEBACK_H
#ifdef __cplusplus
extern "C" {
#endif
-#include "pystate.h"
-
struct _frame;
/* Traceback interface */
-#ifndef Py_LIMITED_API
-typedef struct _traceback {
- PyObject_HEAD
- struct _traceback *tb_next;
- struct _frame *tb_frame;
- int tb_lasti;
- int tb_lineno;
-} PyTracebackObject;
-#endif
PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *);
PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *);
-#ifndef Py_LIMITED_API
-PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, PyObject *, int, int);
-PyAPI_FUNC(void) _PyTraceback_Add(const char *, const char *, int);
-#endif
/* Reveal traceback type so we can typecheck traceback objects */
PyAPI_DATA(PyTypeObject) PyTraceBack_Type;
#define PyTraceBack_Check(v) (Py_TYPE(v) == &PyTraceBack_Type)
-#ifndef Py_LIMITED_API
-/* Write the Python traceback into the file 'fd'. For example:
-
- Traceback (most recent call first):
- File "xxx", line xxx in
- File "xxx", line xxx in
- ...
- File "xxx", line xxx in
-
- This function is written for debug purpose only, to dump the traceback in
- the worst case: after a segmentation fault, at fatal error, etc. That's why,
- it is very limited. Strings are truncated to 100 characters and encoded to
- ASCII with backslashreplace. It doesn't write the source code, only the
- function name, filename and line number of each frame. Write only the first
- 100 frames: if the traceback is truncated, write the line " ...".
-
- This function is signal safe. */
-
-PyAPI_FUNC(void) _Py_DumpTraceback(
- int fd,
- PyThreadState *tstate);
-
-/* Write the traceback of all threads into the file 'fd'. current_thread can be
- NULL.
-
- Return NULL on success, or an error message on error.
-
- This function is written for debug purpose only. It calls
- _Py_DumpTraceback() for each thread, and so has the same limitations. It
- only write the traceback of the first 100 threads: write "..." if there are
- more threads.
-
- If current_tstate is NULL, the function tries to get the Python thread state
- of the current thread. It is not an error if the function is unable to get
- the current Python thread state.
-
- If interp is NULL, the function tries to get the interpreter state from
- the current Python thread state, or from
- _PyGILState_GetInterpreterStateUnsafe() in last resort.
-
- It is better to pass NULL to interp and current_tstate, the function tries
- different options to retrieve these informations.
-
- This function is signal safe. */
-
-PyAPI_FUNC(const char*) _Py_DumpTracebackThreads(
- int fd,
- PyInterpreterState *interp,
- PyThreadState *current_tstate);
-#endif /* !Py_LIMITED_API */
#ifndef Py_LIMITED_API
-
-/* Write a Unicode object into the file descriptor fd. Encode the string to
- ASCII using the backslashreplace error handler.
-
- Do nothing if text is not a Unicode object. The function accepts Unicode
- string which is not ready (PyUnicode_WCHAR_KIND).
-
- This function is signal safe. */
-PyAPI_FUNC(void) _Py_DumpASCII(int fd, PyObject *text);
-
-/* Format an integer as decimal into the file descriptor fd.
-
- This function is signal safe. */
-PyAPI_FUNC(void) _Py_DumpDecimal(
- int fd,
- unsigned long value);
-
-/* Format an integer as hexadecimal into the file descriptor fd with at least
- width digits.
-
- The maximum width is sizeof(unsigned long)*2 digits.
-
- This function is signal safe. */
-PyAPI_FUNC(void) _Py_DumpHexadecimal(
- int fd,
- unsigned long value,
- Py_ssize_t width);
-
-#endif /* !Py_LIMITED_API */
+# define Py_CPYTHON_TRACEBACK_H
+# include "cpython/traceback.h"
+# undef Py_CPYTHON_TRACEBACK_H
+#endif
#ifdef __cplusplus
}
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index c5d5671032e..ee32ac29b7e 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -1,4 +1,5 @@
#include "Python.h"
+#include "pycore_traceback.h"
#include "hashtable.h"
#include "frameobject.h"
#include "pythread.h"
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index 2083a03198f..aa466c46ccf 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -1,5 +1,6 @@
#include "Python.h"
#include "pycore_coreconfig.h"
+#include "pycore_traceback.h"
#include "pythread.h"
#include
#include
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index d29b293b79e..0781dc8046b 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -13,6 +13,7 @@
#include "pycore_pylifecycle.h"
#include "pycore_pymem.h"
#include "pycore_pystate.h"
+#include "pycore_traceback.h"
#include "grammar.h"
#include "node.h"
#include "token.h"
From fd1e0e93b15af018184476ea0b3af0eabef37d89 Mon Sep 17 00:00:00 2001
From: Victor Stinner
Date: Mon, 20 May 2019 02:22:32 +0200
Subject: [PATCH 123/199] bpo-35134: Register new traceback.h header files
(GH-13431)
Add new cpython/traceback.h and pycore_traceback.h header files to
Makefile.pre.in and PCbuild/ project.
---
Makefile.pre.in | 2 ++
PCbuild/pythoncore.vcxproj | 2 ++
PCbuild/pythoncore.vcxproj.filters | 6 ++++++
3 files changed, 10 insertions(+)
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 4924dedc357..9f70cd515eb 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1059,6 +1059,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/cpython/pylifecycle.h \
$(srcdir)/Include/cpython/pymem.h \
$(srcdir)/Include/cpython/pystate.h \
+ $(srcdir)/Include/cpython/traceback.h \
$(srcdir)/Include/cpython/tupleobject.h \
$(srcdir)/Include/cpython/unicodeobject.h \
\
@@ -1078,6 +1079,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_pylifecycle.h \
$(srcdir)/Include/internal/pycore_pymem.h \
$(srcdir)/Include/internal/pycore_pystate.h \
+ $(srcdir)/Include/internal/pycore_traceback.h \
$(srcdir)/Include/internal/pycore_tupleobject.h \
$(srcdir)/Include/internal/pycore_warnings.h \
$(DTRACE_HEADERS)
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index a71fce6bb60..df57adcfd60 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -135,6 +135,7 @@
+
@@ -169,6 +170,7 @@
+
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 91346465679..5515d9bedeb 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -108,6 +108,9 @@
Include
+
+ Include
+ Include
@@ -210,6 +213,9 @@
Include
+
+ Include
+ Include
From 53d378c81286644138415cb56da52a7351e1a477 Mon Sep 17 00:00:00 2001
From: Zackery Spytz
Date: Sun, 19 May 2019 18:26:35 -0600
Subject: [PATCH 124/199] closes bpo-36951: Correct some types in the
type_members struct in typeobject.c. (GH-13403)
---
Objects/typeobject.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index bfbd320b1f5..c086f182aa9 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -369,11 +369,11 @@ assign_version_tag(PyTypeObject *type)
static PyMemberDef type_members[] = {
{"__basicsize__", T_PYSSIZET, offsetof(PyTypeObject,tp_basicsize),READONLY},
{"__itemsize__", T_PYSSIZET, offsetof(PyTypeObject, tp_itemsize), READONLY},
- {"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY},
- {"__weakrefoffset__", T_LONG,
+ {"__flags__", T_ULONG, offsetof(PyTypeObject, tp_flags), READONLY},
+ {"__weakrefoffset__", T_PYSSIZET,
offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
{"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
- {"__dictoffset__", T_LONG,
+ {"__dictoffset__", T_PYSSIZET,
offsetof(PyTypeObject, tp_dictoffset), READONLY},
{"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY},
{0}
From 6d965b39b7a486dd9e96a60b19ee92382d668299 Mon Sep 17 00:00:00 2001
From: Terry Jan Reedy
Date: Sun, 19 May 2019 22:52:22 -0400
Subject: [PATCH 125/199] bpo-36958: In IDLE, print exit message (GH-13435)
Print any argument other than None or int passed to SystemExit
or sys.exit().
---
Doc/library/idle.rst | 3 +++
Lib/idlelib/NEWS.txt | 6 ++++++
Lib/idlelib/help.html | 4 +++-
Lib/idlelib/run.py | 11 ++++++-----
.../IDLE/2019-05-19-22-02-22.bpo-36958.DZUC6G.rst | 2 ++
5 files changed, 20 insertions(+), 6 deletions(-)
create mode 100644 Misc/NEWS.d/next/IDLE/2019-05-19-22-02-22.bpo-36958.DZUC6G.rst
diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst
index f511d64b550..c51cf19e97b 100644
--- a/Doc/library/idle.rst
+++ b/Doc/library/idle.rst
@@ -700,6 +700,9 @@ If ``sys`` is reset by user code, such as with ``importlib.reload(sys)``,
IDLE's changes are lost and input from the keyboard and output to the screen
will not work correctly.
+When user code raises SystemExit either directly or by calling sys.exit, IDLE
+returns to a Shell prompt instead of exiting.
+
User output in Shell
^^^^^^^^^^^^^^^^^^^^
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
index be855bc4671..3f19ce73739 100644
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -3,6 +3,12 @@ Released on 2019-10-20?
======================================
+bpo-36958: Print any argument other than None or int passed to
+SystemExit or sys.exit().
+
+bpo-36807: When saving a file, call file.flush() and os.fsync()
+so bits are flushed to e.g. a USB drive.
+
bpo-36429: Fix starting IDLE with pyshell.
Add idlelib.pyshell alias at top; remove pyshell alias at bottom.
Remove obsolete __name__=='__main__' command.
diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html
index 56f9ca503da..bc287d637ab 100644
--- a/Lib/idlelib/help.html
+++ b/Lib/idlelib/help.html
@@ -659,6 +659,8 @@ will then be attached to that window for input and output.
If sys is reset by user code, such as with importlib.reload(sys),
IDLE’s changes are lost and input from the keyboard and output to the screen
will not work correctly.
+
When user code raises SystemExit either directly or by calling sys.exit, IDLE
+returns to a Shell prompt instead of exiting.