From webhook-mailer at python.org Sun Oct 1 04:37:53 2017 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Sun, 01 Oct 2017 08:37:53 -0000 Subject: [Python-checkins] bpo-31336: Speed up type creation. (#3279) Message-ID: https://github.com/python/cpython/commit/2102c789035ccacbac4362589402ac68baa2cd29 commit: 2102c789035ccacbac4362589402ac68baa2cd29 branch: master author: scoder committer: Serhiy Storchaka date: 2017-10-01T11:37:47+03:00 summary: bpo-31336: Speed up type creation. (#3279) Speed up class creation by 10-20% by reducing the overhead in the necessary special method lookups. files: A Misc/NEWS.d/next/Core and Builtins/2017-09-13-12-04-23.bpo-31336.gi2ahY.rst M Objects/typeobject.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-09-13-12-04-23.bpo-31336.gi2ahY.rst b/Misc/NEWS.d/next/Core and Builtins/2017-09-13-12-04-23.bpo-31336.gi2ahY.rst new file mode 100644 index 00000000000..e62b065af17 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-09-13-12-04-23.bpo-31336.gi2ahY.rst @@ -0,0 +1,2 @@ +Speed up class creation by 10-20% by reducing the overhead in the +necessary special method lookups. Patch by Stefan Behnel. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5e0d81f6859..e72460bfbb3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2367,35 +2367,39 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) &bases, &PyDict_Type, &orig_dict)) return NULL; - /* Determine the proper metatype to deal with this: */ - winner = _PyType_CalculateMetaclass(metatype, bases); - if (winner == NULL) { - return NULL; - } - - if (winner != metatype) { - if (winner->tp_new != type_new) /* Pass it to the winner */ - return winner->tp_new(winner, args, kwds); - metatype = winner; - } - /* Adjust for empty tuple bases */ nbases = PyTuple_GET_SIZE(bases); if (nbases == 0) { - bases = PyTuple_Pack(1, &PyBaseObject_Type); + base = &PyBaseObject_Type; + bases = PyTuple_Pack(1, base); if (bases == NULL) - goto error; + return NULL; nbases = 1; } - else - Py_INCREF(bases); + else { + /* Search the bases for the proper metatype to deal with this: */ + winner = _PyType_CalculateMetaclass(metatype, bases); + if (winner == NULL) { + return NULL; + } - /* Calculate best base, and check that all bases are type objects */ - base = best_base(bases); - if (base == NULL) { - goto error; + if (winner != metatype) { + if (winner->tp_new != type_new) /* Pass it to the winner */ + return winner->tp_new(winner, args, kwds); + metatype = winner; + } + + /* Calculate best base, and check that all bases are type objects */ + base = best_base(bases); + if (base == NULL) { + return NULL; + } + + Py_INCREF(bases); } + /* Use "goto error" from this point on as we now own the reference to "bases". */ + dict = PyDict_Copy(orig_dict); if (dict == NULL) goto error; @@ -2945,25 +2949,23 @@ PyType_GetSlot(PyTypeObject *type, int slot) return *(void**)(((char*)type) + slotoffsets[slot]); } -/* Internal API to look for a name through the MRO. - This returns a borrowed reference, and doesn't set an exception! */ -PyObject * -_PyType_Lookup(PyTypeObject *type, PyObject *name) +/* Internal API to look for a name through the MRO, bypassing the method cache. + This returns a borrowed reference, and might set an exception. + 'error' is set to: -1: error with exception; 1: error without exception; 0: ok */ +static PyObject * +find_name_in_mro(PyTypeObject *type, PyObject *name, int *error) { Py_ssize_t i, n; PyObject *mro, *res, *base, *dict; - unsigned int h; + Py_hash_t hash; - if (MCACHE_CACHEABLE_NAME(name) && - PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) { - /* fast path */ - h = MCACHE_HASH_METHOD(type, name); - if (method_cache[h].version == type->tp_version_tag && - method_cache[h].name == name) { -#if MCACHE_STATS - method_cache_hits++; -#endif - return method_cache[h].value; + if (!PyUnicode_CheckExact(name) || + (hash = ((PyASCIIObject *) name)->hash) == -1) + { + hash = PyObject_Hash(name); + if (hash == -1) { + *error = -1; + return NULL; } } @@ -2971,28 +2973,22 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) mro = type->tp_mro; if (mro == NULL) { - if ((type->tp_flags & Py_TPFLAGS_READYING) == 0 && - PyType_Ready(type) < 0) { - /* It's not ideal to clear the error condition, - but this function is documented as not setting - an exception, and I don't want to change that. - When PyType_Ready() can't proceed, it won't - set the "ready" flag, so future attempts to ready - the same type will call it again -- hopefully - in a context that propagates the exception out. - */ - PyErr_Clear(); - return NULL; + if ((type->tp_flags & Py_TPFLAGS_READYING) == 0) { + if (PyType_Ready(type) < 0) { + *error = -1; + return NULL; + } + mro = type->tp_mro; } - mro = type->tp_mro; if (mro == NULL) { + *error = 1; return NULL; } } res = NULL; - /* keep a strong reference to mro because type->tp_mro can be replaced - during PyDict_GetItem(dict, name) */ + /* Keep a strong reference to mro because type->tp_mro can be replaced + during dict lookup, e.g. when comparing to non-string keys. */ Py_INCREF(mro); assert(PyTuple_Check(mro)); n = PyTuple_GET_SIZE(mro); @@ -3001,11 +2997,61 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) assert(PyType_Check(base)); dict = ((PyTypeObject *)base)->tp_dict; assert(dict && PyDict_Check(dict)); - res = PyDict_GetItem(dict, name); + res = _PyDict_GetItem_KnownHash(dict, name, hash); if (res != NULL) break; + if (PyErr_Occurred()) { + *error = -1; + goto done; + } } + *error = 0; +done: Py_DECREF(mro); + return res; +} + +/* Internal API to look for a name through the MRO. + This returns a borrowed reference, and doesn't set an exception! */ +PyObject * +_PyType_Lookup(PyTypeObject *type, PyObject *name) +{ + PyObject *res; + int error; + unsigned int h; + + if (MCACHE_CACHEABLE_NAME(name) && + PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) { + /* fast path */ + h = MCACHE_HASH_METHOD(type, name); + if (method_cache[h].version == type->tp_version_tag && + method_cache[h].name == name) { +#if MCACHE_STATS + method_cache_hits++; +#endif + return method_cache[h].value; + } + } + + /* We may end up clearing live exceptions below, so make sure it's ours. */ + assert(!PyErr_Occurred()); + + res = find_name_in_mro(type, name, &error); + /* Only put NULL results into cache if there was no error. */ + if (error) { + /* It's not ideal to clear the error condition, + but this function is documented as not setting + an exception, and I don't want to change that. + E.g., when PyType_Ready() can't proceed, it won't + set the "ready" flag, so future attempts to ready + the same type will call it again -- hopefully + in a context that propagates the exception out. + */ + if (error == -1) { + PyErr_Clear(); + } + return NULL; + } if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(type)) { h = MCACHE_HASH_METHOD(type, name); @@ -6965,6 +7011,7 @@ update_one_slot(PyTypeObject *type, slotdef *p) void *generic = NULL, *specific = NULL; int use_generic = 0; int offset = p->offset; + int error; void **ptr = slotptr(type, offset); if (ptr == NULL) { @@ -6973,9 +7020,18 @@ update_one_slot(PyTypeObject *type, slotdef *p) } while (p->offset == offset); return p; } + /* We may end up clearing live exceptions below, so make sure it's ours. */ + assert(!PyErr_Occurred()); do { - descr = _PyType_Lookup(type, p->name_strobj); + /* Use faster uncached lookup as we won't get any cache hits during type setup. */ + descr = find_name_in_mro(type, p->name_strobj, &error); if (descr == NULL) { + if (error == -1) { + /* It is unlikely by not impossible that there has been an exception + during lookup. Since this function originally expected no errors, + we ignore them here in order to keep up the interface. */ + PyErr_Clear(); + } if (ptr == (void**)&type->tp_iternext) { specific = (void *)_PyObject_NextNotImplemented; } From solipsis at pitrou.net Sun Oct 1 05:06:11 2017 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 01 Oct 2017 09:06:11 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=3 Message-ID: <20171001090609.91619.1E23ED78A7D049E4@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_collections leaked [7, -7, 1] memory blocks, sum=1 test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_spawn leaked [0, 0, -2] memory blocks, sum=-2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogrq2FrR', '--timeout', '7200'] From webhook-mailer at python.org Sun Oct 1 19:01:30 2017 From: webhook-mailer at python.org (Terry Jan Reedy) Date: Sun, 01 Oct 2017 23:01:30 -0000 Subject: [Python-checkins] IDLE: make filetypes a tuple constant. (#3847) Message-ID: https://github.com/python/cpython/commit/5961e7c156f90c7f9444ae95b9d3e55114ca2169 commit: 5961e7c156f90c7f9444ae95b9d3e55114ca2169 branch: master author: Terry Jan Reedy committer: GitHub date: 2017-10-01T19:01:27-04:00 summary: IDLE: make filetypes a tuple constant. (#3847) Save a bit of code, plus non-tuples get converted anyway to tuples by tkinter for the tk call. files: M Lib/idlelib/iomenu.py diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index 3414c7b3aff..f9b6907b40c 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -487,11 +487,11 @@ def print_window(self, event): opendialog = None savedialog = None - filetypes = [ + filetypes = ( ("Python files", "*.py *.pyw", "TEXT"), ("Text files", "*.txt", "TEXT"), ("All files", "*"), - ] + ) defaultextension = '.py' if sys.platform == 'darwin' else '' From webhook-mailer at python.org Sun Oct 1 19:37:22 2017 From: webhook-mailer at python.org (Terry Jan Reedy) Date: Sun, 01 Oct 2017 23:37:22 -0000 Subject: [Python-checkins] [3.6] IDLE: make filetypes a tuple constant. (GH-3847) (#3848) Message-ID: https://github.com/python/cpython/commit/c0418160457970c4654ad8d910cd0ad21a02f3f7 commit: c0418160457970c4654ad8d910cd0ad21a02f3f7 branch: 3.6 author: Terry Jan Reedy committer: GitHub date: 2017-10-01T19:37:19-04:00 summary: [3.6] IDLE: make filetypes a tuple constant. (GH-3847) (#3848) Save a bit of code, plus non-tuples get converted anyway to tuples by tkinter for the tk call. (cherry picked from commit 5961e7c156f90c7f9444ae95b9d3e55114ca2169) files: M Lib/idlelib/iomenu.py diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index 3414c7b3aff..f9b6907b40c 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -487,11 +487,11 @@ def print_window(self, event): opendialog = None savedialog = None - filetypes = [ + filetypes = ( ("Python files", "*.py *.pyw", "TEXT"), ("Text files", "*.txt", "TEXT"), ("All files", "*"), - ] + ) defaultextension = '.py' if sys.platform == 'darwin' else '' From webhook-mailer at python.org Mon Oct 2 02:38:00 2017 From: webhook-mailer at python.org (Benjamin Peterson) Date: Mon, 02 Oct 2017 06:38:00 -0000 Subject: [Python-checkins] remove comment about long-gone SGI modules (#3850) Message-ID: https://github.com/python/cpython/commit/edc05c5d88c1ce853b3d04b34679ed7d69c2142a commit: edc05c5d88c1ce853b3d04b34679ed7d69c2142a branch: master author: Benjamin Peterson committer: GitHub date: 2017-10-01T23:37:57-07:00 summary: remove comment about long-gone SGI modules (#3850) files: M setup.py diff --git a/setup.py b/setup.py index 0b536c8ca32..11c4ec67f43 100644 --- a/setup.py +++ b/setup.py @@ -615,8 +615,6 @@ def detect_modules(self): math_libs = self.detect_math_libs() - # XXX Omitted modules: gl, pure, dl, SGI-specific modules - # # The following modules are all pretty straightforward, and compile # on pretty much any POSIXish platform. From webhook-mailer at python.org Mon Oct 2 03:33:47 2017 From: webhook-mailer at python.org (INADA Naoki) Date: Mon, 02 Oct 2017 07:33:47 -0000 Subject: [Python-checkins] bpo-31659: Use simple slicing to format PEM cert (GH-3849) Message-ID: https://github.com/python/cpython/commit/b75a228af8c0553aef44e4e03763af90fbc8737f commit: b75a228af8c0553aef44e4e03763af90fbc8737f branch: master author: INADA Naoki committer: GitHub date: 2017-10-02T16:33:42+09:00 summary: bpo-31659: Use simple slicing to format PEM cert (GH-3849) DER_cert_to_PEM_cert() used textwrap.fill() to format PEM. But it's library to wrap lines on word boundary, while PEM is base64 encoded string. Additionally, importing textwrap is little slow. files: M Lib/ssl.py diff --git a/Lib/ssl.py b/Lib/ssl.py index 24f24b17bf1..75caae0c440 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -91,7 +91,6 @@ """ import ipaddress -import textwrap import re import sys import os @@ -1201,9 +1200,10 @@ def DER_cert_to_PEM_cert(der_cert_bytes): PEM version of it as a string.""" f = str(base64.standard_b64encode(der_cert_bytes), 'ASCII', 'strict') - return (PEM_HEADER + '\n' + - textwrap.fill(f, 64) + '\n' + - PEM_FOOTER + '\n') + ss = [PEM_HEADER] + ss += [f[i:i+64] for i in range(0, len(f), 64)] + ss.append(PEM_FOOTER + '\n') + return '\n'.join(ss) def PEM_cert_to_DER_cert(pem_cert_string): """Takes a certificate in ASCII PEM format and returns the From solipsis at pitrou.net Mon Oct 2 05:06:33 2017 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 02 Oct 2017 09:06:33 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=11 Message-ID: <20171002090632.131021.FFFA3617301E09E8@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_collections leaked [0, 0, 7] memory blocks, sum=7 test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_forkserver leaked [1, -2, 1] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/refloggVoJq7', '--timeout', '7200'] From webhook-mailer at python.org Mon Oct 2 05:39:58 2017 From: webhook-mailer at python.org (Victor Stinner) Date: Mon, 02 Oct 2017 09:39:58 -0000 Subject: [Python-checkins] bpo-31158: Fix nondeterministic read in test_pty (#3808) Message-ID: https://github.com/python/cpython/commit/e6f62f69f07892b993910ff03c9db3ffa5cb9ca5 commit: e6f62f69f07892b993910ff03c9db3ffa5cb9ca5 branch: master author: Cornelius Diekmann committer: Victor Stinner date: 2017-10-02T02:39:55-07:00 summary: bpo-31158: Fix nondeterministic read in test_pty (#3808) * bpo-31158: Fix nondeterministic read in test_pty * Reuse existing readline implementation from io. Thx to @pitrou * Updated comment Ideally, this commit is fixuped into the previous commit. Since there is already a comment on github, I won't rebase. files: M Lib/test/test_pty.py diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index f283e1930b7..3b448569a2f 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -10,6 +10,7 @@ import select import signal import socket +import io # readline import unittest TEST_STRING_1 = b"I wish to buy a fish license.\n" @@ -23,6 +24,16 @@ def debug(msg): pass +# Note that os.read() is nondeterministic so we need to be very careful +# to make the test suite deterministic. A normal call to os.read() may +# give us less than expected. +# +# Beware, on my Linux system, if I put 'foo\n' into a terminal fd, I get +# back 'foo\r\n' at the other end. The behavior depends on the termios +# setting. The newline translation may be OS-specific. To make the +# test suite deterministic and OS-independent, the functions _readline +# and normalize_output can be used. + def normalize_output(data): # Some operating systems do conversions on newline. We could possibly fix # that by doing the appropriate termios.tcsetattr()s. I couldn't figure out @@ -43,6 +54,12 @@ def normalize_output(data): return data +def _readline(fd): + """Read one line. May block forever if no newline is read.""" + reader = io.FileIO(fd, mode='rb', closefd=False) + return reader.readline() + + # Marginal testing of pty suite. Cannot do extensive 'do or fail' testing # because pty code is not too portable. @@ -94,14 +111,14 @@ def test_basic(self): debug("Writing to slave_fd") os.write(slave_fd, TEST_STRING_1) - s1 = os.read(master_fd, 1024) + s1 = _readline(master_fd) self.assertEqual(b'I wish to buy a fish license.\n', normalize_output(s1)) debug("Writing chunked output") os.write(slave_fd, TEST_STRING_2[:5]) os.write(slave_fd, TEST_STRING_2[5:]) - s2 = os.read(master_fd, 1024) + s2 = _readline(master_fd) self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2)) os.close(slave_fd) From webhook-mailer at python.org Mon Oct 2 05:57:59 2017 From: webhook-mailer at python.org (Victor Stinner) Date: Mon, 02 Oct 2017 09:57:59 -0000 Subject: [Python-checkins] [3.6] bpo-31158: Fix nondeterministic read in test_pty (GH-3808) (GH-3852) Message-ID: https://github.com/python/cpython/commit/66fb5ef3bb9e36187a0e5052dfd99899447df671 commit: 66fb5ef3bb9e36187a0e5052dfd99899447df671 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Victor Stinner date: 2017-10-02T02:57:56-07:00 summary: [3.6] bpo-31158: Fix nondeterministic read in test_pty (GH-3808) (GH-3852) (cherry picked from commit e6f62f69f07892b993910ff03c9db3ffa5cb9ca5) files: M Lib/test/test_pty.py diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index 15f88e4fcd7..45ebea51a05 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -10,6 +10,7 @@ import select import signal import socket +import io # readline import unittest TEST_STRING_1 = b"I wish to buy a fish license.\n" @@ -23,6 +24,16 @@ def debug(msg): pass +# Note that os.read() is nondeterministic so we need to be very careful +# to make the test suite deterministic. A normal call to os.read() may +# give us less than expected. +# +# Beware, on my Linux system, if I put 'foo\n' into a terminal fd, I get +# back 'foo\r\n' at the other end. The behavior depends on the termios +# setting. The newline translation may be OS-specific. To make the +# test suite deterministic and OS-independent, the functions _readline +# and normalize_output can be used. + def normalize_output(data): # Some operating systems do conversions on newline. We could possibly # fix that by doing the appropriate termios.tcsetattr()s. I couldn't @@ -44,6 +55,12 @@ def normalize_output(data): return data +def _readline(fd): + """Read one line. May block forever if no newline is read.""" + reader = io.FileIO(fd, mode='rb', closefd=False) + return reader.readline() + + # Marginal testing of pty suite. Cannot do extensive 'do or fail' testing # because pty code is not too portable. @@ -98,14 +115,14 @@ def test_basic(self): debug("Writing to slave_fd") os.write(slave_fd, TEST_STRING_1) - s1 = os.read(master_fd, 1024) + s1 = _readline(master_fd) self.assertEqual(b'I wish to buy a fish license.\n', normalize_output(s1)) debug("Writing chunked output") os.write(slave_fd, TEST_STRING_2[:5]) os.write(slave_fd, TEST_STRING_2[5:]) - s2 = os.read(master_fd, 1024) + s2 = _readline(master_fd) self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2)) os.close(slave_fd) From webhook-mailer at python.org Mon Oct 2 05:58:11 2017 From: webhook-mailer at python.org (Victor Stinner) Date: Mon, 02 Oct 2017 09:58:11 -0000 Subject: [Python-checkins] bpo-31158: Fix nondeterministic read in test_pty (#3808) (#3853) Message-ID: https://github.com/python/cpython/commit/20cbc1d29facead32c2da06c81a09af0e057015c commit: 20cbc1d29facead32c2da06c81a09af0e057015c branch: 2.7 author: Victor Stinner committer: GitHub date: 2017-10-02T02:58:09-07:00 summary: bpo-31158: Fix nondeterministic read in test_pty (#3808) (#3853) (cherry picked from commit e6f62f69f07892b993910ff03c9db3ffa5cb9ca5) files: M Lib/test/test_pty.py diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index bec38c45456..f623aa09620 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -11,6 +11,7 @@ import select import signal import socket +import io # readline import unittest TEST_STRING_1 = "I wish to buy a fish license.\n" @@ -24,6 +25,16 @@ def debug(msg): pass +# Note that os.read() is nondeterministic so we need to be very careful +# to make the test suite deterministic. A normal call to os.read() may +# give us less than expected. +# +# Beware, on my Linux system, if I put 'foo\n' into a terminal fd, I get +# back 'foo\r\n' at the other end. The behavior depends on the termios +# setting. The newline translation may be OS-specific. To make the +# test suite deterministic and OS-independent, the functions _readline +# and normalize_output can be used. + def normalize_output(data): # Some operating systems do conversions on newline. We could possibly # fix that by doing the appropriate termios.tcsetattr()s. I couldn't @@ -45,6 +56,12 @@ def normalize_output(data): return data +def _readline(fd): + """Read one line. May block forever if no newline is read.""" + reader = io.FileIO(fd, mode='rb', closefd=False) + return reader.readline() + + # Marginal testing of pty suite. Cannot do extensive 'do or fail' testing # because pty code is not too portable. @@ -97,14 +114,14 @@ def test_basic(self): debug("Writing to slave_fd") os.write(slave_fd, TEST_STRING_1) - s1 = os.read(master_fd, 1024) + s1 = _readline(master_fd) self.assertEqual('I wish to buy a fish license.\n', normalize_output(s1)) debug("Writing chunked output") os.write(slave_fd, TEST_STRING_2[:5]) os.write(slave_fd, TEST_STRING_2[5:]) - s2 = os.read(master_fd, 1024) + s2 = _readline(master_fd) self.assertEqual('For my pet fish, Eric.\n', normalize_output(s2)) os.close(slave_fd) From webhook-mailer at python.org Mon Oct 2 10:42:18 2017 From: webhook-mailer at python.org (Antoine Pitrou) Date: Mon, 02 Oct 2017 14:42:18 -0000 Subject: [Python-checkins] bpo-31516: current_thread() should not return a dummy thread at shutdown (#3673) Message-ID: https://github.com/python/cpython/commit/1023dbbcb7f05e76053486ae7ef7f73b4cdc5398 commit: 1023dbbcb7f05e76053486ae7ef7f73b4cdc5398 branch: master author: Antoine Pitrou committer: GitHub date: 2017-10-02T16:42:15+02:00 summary: bpo-31516: current_thread() should not return a dummy thread at shutdown (#3673) bpo-31516: current_thread() should not return a dummy thread at shutdown files: A Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst M Lib/test/test_threading.py M Lib/threading.py diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index f7c3680bda3..6e1ae06f792 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -547,6 +547,35 @@ def f(): self.assertEqual(err, b"") self.assertEqual(data, "Thread-1\nTrue\nTrue\n") + def test_main_thread_during_shutdown(self): + # bpo-31516: current_thread() should still point to the main thread + # at shutdown + code = """if 1: + import gc, threading + + main_thread = threading.current_thread() + assert main_thread is threading.main_thread() # sanity check + + class RefCycle: + def __init__(self): + self.cycle = self + + def __del__(self): + print("GC:", + threading.current_thread() is main_thread, + threading.main_thread() is main_thread, + threading.enumerate() == [main_thread]) + + RefCycle() + gc.collect() # sanity check + x = RefCycle() + """ + _, out, err = assert_python_ok("-c", code) + data = out.decode() + self.assertEqual(err, b"") + self.assertEqual(data.splitlines(), + ["GC: True True True"] * 2) + def test_tstate_lock(self): # Test an implementation detail of Thread objects. started = _thread.allocate_lock() diff --git a/Lib/threading.py b/Lib/threading.py index e4bf974495b..418116faceb 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1158,8 +1158,8 @@ def run(self): self.function(*self.args, **self.kwargs) self.finished.set() + # Special thread class to represent the main thread -# This is garbage collected through an exit handler class _MainThread(Thread): @@ -1272,7 +1272,6 @@ def _shutdown(): while t: t.join() t = _pickSomeNonDaemonThread() - _main_thread._delete() def _pickSomeNonDaemonThread(): for t in enumerate(): diff --git a/Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst b/Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst new file mode 100644 index 00000000000..af48d159fef --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst @@ -0,0 +1 @@ +``threading.current_thread()`` should not return a dummy thread at shutdown. From webhook-mailer at python.org Mon Oct 2 10:58:03 2017 From: webhook-mailer at python.org (Victor Stinner) Date: Mon, 02 Oct 2017 14:58:03 -0000 Subject: [Python-checkins] bpo-11063: Fix _uuid module on macOS (#3855) Message-ID: https://github.com/python/cpython/commit/4337a0d9955f0855ba38ef30feec3858d304abf0 commit: 4337a0d9955f0855ba38ef30feec3858d304abf0 branch: master author: Victor Stinner committer: GitHub date: 2017-10-02T07:57:59-07:00 summary: bpo-11063: Fix _uuid module on macOS (#3855) On macOS, use uuid_generate_time() instead of uuid_generate_time_safe() of libuuid, since uuid_generate_time_safe() is not available. files: M Lib/uuid.py M Modules/_uuidmodule.c diff --git a/Lib/uuid.py b/Lib/uuid.py index b2fbd38c353..3123ff88a16 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -509,7 +509,7 @@ def _load_system_functions(): pass elif _uuid is not None: _generate_time_safe = _uuid.generate_time_safe - _has_uuid_generate_time_safe = True + _has_uuid_generate_time_safe = _uuid.has_uuid_generate_time_safe return try: diff --git a/Modules/_uuidmodule.c b/Modules/_uuidmodule.c index e263b40d8ff..88c40ce3537 100644 --- a/Modules/_uuidmodule.c +++ b/Modules/_uuidmodule.c @@ -4,14 +4,27 @@ #include +/* bpo-11063: libuuid on macOS doesn't provide uuid_generate_time_safe(), + only uuid_generate_time(). */ +#ifndef __APPLE__ +# define HAVE_TIME_SAFE +#endif + + static PyObject * py_uuid_generate_time_safe(void) { +#ifdef HAVE_TIME_SAFE uuid_t out; int res; res = uuid_generate_time_safe(out); return Py_BuildValue("y#i", (const char *) out, sizeof(out), res); +#else + uuid_t out; + uuid_generate_time(out); + return Py_BuildValue("y#O", (const char *) out, sizeof(out), Py_None); +#endif } @@ -30,6 +43,21 @@ static struct PyModuleDef uuidmodule = { PyMODINIT_FUNC PyInit__uuid(void) { + PyObject *mod; assert(sizeof(uuid_t) == 16); - return PyModule_Create(&uuidmodule); +#ifdef HAVE_TIME_SAFE + int has_uuid_generate_time_safe = 1; +#else + int has_uuid_generate_time_safe = 0; +#endif + mod = PyModule_Create(&uuidmodule); + if (mod == NULL) { + return NULL; + } + if (PyModule_AddIntConstant(mod, "has_uuid_generate_time_safe", + has_uuid_generate_time_safe) < 0) { + return NULL; + } + + return mod; } From webhook-mailer at python.org Mon Oct 2 11:20:05 2017 From: webhook-mailer at python.org (Antoine Pitrou) Date: Mon, 02 Oct 2017 15:20:05 -0000 Subject: [Python-checkins] [3.6] bpo-31516: current_thread() should not return a dummy thread at shutdown (GH-3673) (#3856) Message-ID: https://github.com/python/cpython/commit/ac6245a31f9a757db0520722c592cb7fdcb55eb0 commit: ac6245a31f9a757db0520722c592cb7fdcb55eb0 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Antoine Pitrou date: 2017-10-02T17:20:01+02:00 summary: [3.6] bpo-31516: current_thread() should not return a dummy thread at shutdown (GH-3673) (#3856) bpo-31516: current_thread() should not return a dummy thread at shutdown (cherry picked from commit 1023dbbcb7f05e76053486ae7ef7f73b4cdc5398) files: A Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst M Lib/test/test_threading.py M Lib/threading.py diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 9cadc0f1c02..b42314fdbb2 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -542,6 +542,35 @@ def f(): self.assertEqual(err, b"") self.assertEqual(data, "Thread-1\nTrue\nTrue\n") + def test_main_thread_during_shutdown(self): + # bpo-31516: current_thread() should still point to the main thread + # at shutdown + code = """if 1: + import gc, threading + + main_thread = threading.current_thread() + assert main_thread is threading.main_thread() # sanity check + + class RefCycle: + def __init__(self): + self.cycle = self + + def __del__(self): + print("GC:", + threading.current_thread() is main_thread, + threading.main_thread() is main_thread, + threading.enumerate() == [main_thread]) + + RefCycle() + gc.collect() # sanity check + x = RefCycle() + """ + _, out, err = assert_python_ok("-c", code) + data = out.decode() + self.assertEqual(err, b"") + self.assertEqual(data.splitlines(), + ["GC: True True True"] * 2) + def test_tstate_lock(self): # Test an implementation detail of Thread objects. started = _thread.allocate_lock() diff --git a/Lib/threading.py b/Lib/threading.py index 95978d310a2..bb2556544b0 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1182,8 +1182,8 @@ def run(self): self.function(*self.args, **self.kwargs) self.finished.set() + # Special thread class to represent the main thread -# This is garbage collected through an exit handler class _MainThread(Thread): @@ -1293,7 +1293,6 @@ def _shutdown(): while t: t.join() t = _pickSomeNonDaemonThread() - _main_thread._delete() def _pickSomeNonDaemonThread(): for t in enumerate(): diff --git a/Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst b/Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst new file mode 100644 index 00000000000..af48d159fef --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst @@ -0,0 +1 @@ +``threading.current_thread()`` should not return a dummy thread at shutdown. From webhook-mailer at python.org Mon Oct 2 11:27:38 2017 From: webhook-mailer at python.org (Victor Stinner) Date: Mon, 02 Oct 2017 15:27:38 -0000 Subject: [Python-checkins] bpo-31510: Fix multiprocessing test_many_processes() on macOS (#3857) Message-ID: https://github.com/python/cpython/commit/e6cfdefa0c2f5bda177e49b228c2c7528f7c239c commit: e6cfdefa0c2f5bda177e49b228c2c7528f7c239c branch: master author: Victor Stinner committer: GitHub date: 2017-10-02T08:27:34-07:00 summary: bpo-31510: Fix multiprocessing test_many_processes() on macOS (#3857) On macOS, a process can exit with -SIGKILL if it is killed "early" with SIGTERM. files: M Lib/test/_test_multiprocessing.py diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index fda20f1f408..8e004e21a4f 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -501,8 +501,13 @@ def test_many_processes(self): for p in procs: join_process(p) if os.name != 'nt': + exitcodes = [-signal.SIGTERM] + if sys.platform == 'darwin': + # bpo-31510: On macOS, killing a freshly started process with + # SIGTERM sometimes kills the process with SIGKILL. + exitcodes.append(-signal.SIGKILL) for p in procs: - self.assertEqual(p.exitcode, -signal.SIGTERM) + self.assertIn(p.exitcode, exitcodes) def test_lose_target_ref(self): c = DummyCallable() From webhook-mailer at python.org Mon Oct 2 11:54:00 2017 From: webhook-mailer at python.org (Steve Dower) Date: Mon, 02 Oct 2017 15:54:00 -0000 Subject: [Python-checkins] bpo-31662: Fix typos in uploadrelease.bat script Message-ID: https://github.com/python/cpython/commit/efb560eee28b6b2418e1231573ca62574d6dc07b commit: efb560eee28b6b2418e1231573ca62574d6dc07b branch: master author: Anselm Kruis committer: Steve Dower date: 2017-10-02T08:53:55-07:00 summary: bpo-31662: Fix typos in uploadrelease.bat script files: M Tools/msi/uploadrelease.bat diff --git a/Tools/msi/uploadrelease.bat b/Tools/msi/uploadrelease.bat index 4753fd35032..4902b6cf3f7 100644 --- a/Tools/msi/uploadrelease.bat +++ b/Tools/msi/uploadrelease.bat @@ -22,9 +22,9 @@ if "%1" EQU "-t" (set TARGET=%~2) && shift && shift && goto CheckOpts if "%1" EQU "--target" (set TARGET=%~2) && shift && shift && goto CheckOpts if "%1" EQU "--dry-run" (set DRYRUN=true) && shift && goto CheckOpts if "%1" EQU "--skip-gpg" (set NOGPG=true) && shift && goto CheckOpts -if "%1" EQU "--skip-purge" (set PURGE_OPTION=) && shift && godo CheckOpts -if "%1" EQU "--skip-test" (set NOTEST=true) && shift && godo CheckOpts -if "%1" EQU "-T" (set NOTEST=true) && shift && godo CheckOpts +if "%1" EQU "--skip-purge" (set PURGE_OPTION=) && shift && goto CheckOpts +if "%1" EQU "--skip-test" (set NOTEST=true) && shift && goto CheckOpts +if "%1" EQU "-T" (set NOTEST=true) && shift && goto CheckOpts if "%1" NEQ "" echo Unexpected argument "%1" & exit /B 1 if not defined PLINK where plink > "%TEMP%\plink.loc" 2> nul && set /P PLINK= < "%TEMP%\plink.loc" & del "%TEMP%\plink.loc" From webhook-mailer at python.org Mon Oct 2 12:20:31 2017 From: webhook-mailer at python.org (Steve Dower) Date: Mon, 02 Oct 2017 16:20:31 -0000 Subject: [Python-checkins] [3.6] bpo-31662: Fix typos in uploadrelease.bat script (#3858) Message-ID: https://github.com/python/cpython/commit/d6201cb0e865dad116ffe46e5ea3d02e8eeb42c1 commit: d6201cb0e865dad116ffe46e5ea3d02e8eeb42c1 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Steve Dower date: 2017-10-02T09:20:28-07:00 summary: [3.6] bpo-31662: Fix typos in uploadrelease.bat script (#3858) (cherry picked from commit efb560eee28b6b2418e1231573ca62574d6dc07b) files: M Tools/msi/uploadrelease.bat diff --git a/Tools/msi/uploadrelease.bat b/Tools/msi/uploadrelease.bat index 610b092b863..6441db9ee6f 100644 --- a/Tools/msi/uploadrelease.bat +++ b/Tools/msi/uploadrelease.bat @@ -22,9 +22,9 @@ if "%1" EQU "-t" (set TARGET=%~2) && shift && shift && goto CheckOpts if "%1" EQU "--target" (set TARGET=%~2) && shift && shift && goto CheckOpts if "%1" EQU "--dry-run" (set DRYRUN=true) && shift && goto CheckOpts if "%1" EQU "--skip-gpg" (set NOGPG=true) && shift && goto CheckOpts -if "%1" EQU "--skip-purge" (set PURGE_OPTION=) && shift && godo CheckOpts -if "%1" EQU "--skip-test" (set NOTEST=true) && shift && godo CheckOpts -if "%1" EQU "-T" (set NOTEST=true) && shift && godo CheckOpts +if "%1" EQU "--skip-purge" (set PURGE_OPTION=) && shift && goto CheckOpts +if "%1" EQU "--skip-test" (set NOTEST=true) && shift && goto CheckOpts +if "%1" EQU "-T" (set NOTEST=true) && shift && goto CheckOpts if "%1" NEQ "" echo Unexpected argument "%1" & exit /B 1 if not defined PLINK where plink > "%TEMP%\plink.loc" 2> nul && set /P PLINK= < "%TEMP%\plink.loc" & del "%TEMP%\plink.loc" From webhook-mailer at python.org Mon Oct 2 17:31:50 2017 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Mon, 02 Oct 2017 21:31:50 -0000 Subject: [Python-checkins] [2.7] bpo-31478: Prevent unwanted behavior in _random.Random.seed() in case the arg has a bad __abs__() method (GH-3596) (#3845) Message-ID: https://github.com/python/cpython/commit/13da1a60f13e173f65bb0da5ab325641d5bb99ec commit: 13da1a60f13e173f65bb0da5ab325641d5bb99ec branch: 2.7 author: Oren Milman committer: Serhiy Storchaka date: 2017-10-03T00:31:42+03:00 summary: [2.7] bpo-31478: Prevent unwanted behavior in _random.Random.seed() in case the arg has a bad __abs__() method (GH-3596) (#3845) files: A Misc/NEWS.d/next/Core and Builtins/2017-10-01-18-59-40.bpo-31478.owtqoO.rst M Lib/test/test_random.py M Modules/_randommodule.c diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 90d334a835a..d2a4f213f13 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -307,6 +307,22 @@ def test_randbelow_logic(self, _log=log, int=int): class MersenneTwister_TestBasicOps(TestBasicOps): gen = random.Random() + @test_support.cpython_only + def test_bug_31478(self): + # _random.Random.seed() should ignore the __abs__() method of a + # long/int subclass argument. + class BadInt(int): + def __abs__(self): + 1/0 + class BadLong(long): + def __abs__(self): + 1/0 + self.gen.seed(42) + expected_value = self.gen.random() + for seed_arg in [42L, BadInt(42), BadLong(42)]: + self.gen.seed(seed_arg) + self.assertEqual(self.gen.random(), expected_value) + def test_setstate_first_arg(self): self.assertRaises(ValueError, self.gen.setstate, (1, None, None)) diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-10-01-18-59-40.bpo-31478.owtqoO.rst b/Misc/NEWS.d/next/Core and Builtins/2017-10-01-18-59-40.bpo-31478.owtqoO.rst new file mode 100644 index 00000000000..b5b32d6989f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-10-01-18-59-40.bpo-31478.owtqoO.rst @@ -0,0 +1,2 @@ +Prevent unwanted behavior in `_random.Random.seed()` in case the argument +has a bad ``__abs__()`` method. Patch by Oren Milman. diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 852b810ae21..2e49db6ef73 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -230,9 +230,15 @@ random_seed(RandomObject *self, PyObject *args) } /* If the arg is an int or long, use its absolute value; else use * the absolute value of its hash code. + * Calling int.__abs__() or long.__abs__() prevents calling arg.__abs__(), + * which might return an invalid value. See issue #31478. */ - if (PyInt_Check(arg) || PyLong_Check(arg)) - n = PyNumber_Absolute(arg); + if (PyInt_Check(arg)) { + n = PyInt_Type.tp_as_number->nb_absolute(arg); + } + else if (PyLong_Check(arg)) { + n = PyLong_Type.tp_as_number->nb_absolute(arg); + } else { long hash = PyObject_Hash(arg); if (hash == -1) From webhook-mailer at python.org Tue Oct 3 04:48:31 2017 From: webhook-mailer at python.org (Ned Deily) Date: Tue, 03 Oct 2017 08:48:31 -0000 Subject: [Python-checkins] Fix build issues in Doc/make.bat (#3663) Message-ID: https://github.com/python/cpython/commit/564747d91b08a0c53cfec6def85b7b3edb9c65e7 commit: 564747d91b08a0c53cfec6def85b7b3edb9c65e7 branch: 3.6 author: Steve Dower committer: Ned Deily date: 2017-10-02T20:27:33-04:00 summary: Fix build issues in Doc/make.bat (#3663) files: M Doc/make.bat diff --git a/Doc/make.bat b/Doc/make.bat index 0472a3de82f..6cb315fda40 100644 --- a/Doc/make.bat +++ b/Doc/make.bat @@ -58,7 +58,7 @@ if "%1" EQU "help" goto help if "%1" EQU "check" goto check if "%1" EQU "serve" goto serve if "%1" == "clean" ( - rmdir /q /s %BUILDDIR% + rmdir /q /s "%BUILDDIR%" goto end ) @@ -107,6 +107,8 @@ echo.be passed by setting the SPHINXOPTS environment variable. goto end :build +if not exist "%BUILDDIR%" mkdir "%BUILDDIR%" + if exist ..\Misc\NEWS ( echo.Copying Misc\NEWS to build\NEWS copy ..\Misc\NEWS build\NEWS > nul @@ -123,10 +125,10 @@ if exist ..\Misc\NEWS ( if NOT "%PAPER%" == "" ( set SPHINXOPTS=-D latex_elements.papersize=%PAPER% %SPHINXOPTS% ) -cmd /C %SPHINXBUILD% %SPHINXOPTS% -b%1 -dbuild\doctrees . %BUILDDIR%\%* +cmd /S /C "%SPHINXBUILD% %SPHINXOPTS% -b%1 -dbuild\doctrees . "%BUILDDIR%\%1" %2 %3 %4 %5 %6 %7 %8 %9" if "%1" EQU "htmlhelp" ( - cmd /C "%HTMLHELP%" build\htmlhelp\python%DISTVERSION:.=%.hhp + "%HTMLHELP%" "%BUILDDIR%\htmlhelp\python%DISTVERSION:.=%.hhp" rem hhc.exe seems to always exit with code 1, reset to 0 for less than 2 if not errorlevel 2 cmd /C exit /b 0 ) @@ -146,19 +148,19 @@ if NOT "%2" EQU "" ( ) cmd /C %this% html -if EXIST %BUILDDIR%\html\index.html ( - echo.Opening %BUILDDIR%\html\index.html in the default web browser... - start %BUILDDIR%\html\index.html +if EXIST "%BUILDDIR%\html\index.html" ( + echo.Opening "%BUILDDIR%\html\index.html" in the default web browser... + start "%BUILDDIR%\html\index.html" ) goto end :check -cmd /C %PYTHON% tools\rstlint.py -i tools +cmd /S /C "%PYTHON% tools\rstlint.py -i tools" goto end :serve -cmd /C %PYTHON% ..\Tools\scripts\serve.py %BUILDDIR%\html +cmd /S /C "%PYTHON% ..\Tools\scripts\serve.py "%BUILDDIR%\html"" goto end :end From solipsis at pitrou.net Tue Oct 3 05:07:06 2017 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 03 Oct 2017 09:07:06 +0000 Subject: [Python-checkins] Daily reference leaks (4243df51fe43): sum=4 Message-ID: <20171003090705.100623.79CB4B79EBD7D3F4@psf.io> results for 4243df51fe43 on branch "default" -------------------------------------------- test_collections leaked [-7, 8, 0] memory blocks, sum=1 test_functools leaked [0, 3, 1] memory blocks, sum=4 test_multiprocessing_spawn leaked [0, 1, -2] memory blocks, sum=-1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflog25jzGd', '--timeout', '7200'] From webhook-mailer at python.org Tue Oct 3 05:53:19 2017 From: webhook-mailer at python.org (Antoine Pitrou) Date: Tue, 03 Oct 2017 09:53:19 -0000 Subject: [Python-checkins] bpo-31540: Allow passing multiprocessing context to ProcessPoolExecutor (#3682) Message-ID: https://github.com/python/cpython/commit/e8c368df22c344183627e7ef882bea1683fe6dbe commit: e8c368df22c344183627e7ef882bea1683fe6dbe branch: master author: Thomas Moreau committer: Antoine Pitrou date: 2017-10-03T11:53:17+02:00 summary: bpo-31540: Allow passing multiprocessing context to ProcessPoolExecutor (#3682) files: A Misc/NEWS.d/next/Library/2017-09-22-16-02-00.bpo-31540.ybDHT5.rst M .travis.yml M Doc/library/concurrent.futures.rst M Lib/concurrent/futures/process.py M Lib/test/test_concurrent_futures.py diff --git a/.travis.yml b/.travis.yml index 2e0ad87affb..185846029c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,7 +56,7 @@ matrix: ./venv/bin/python -m test.pythoninfo script: # Skip tests that re-run the entire test suite. - - ./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 + - ./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 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 diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index d85576b8bed..30556fbb345 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -191,13 +191,16 @@ that :class:`ProcessPoolExecutor` will not work in the interactive interpreter. Calling :class:`Executor` or :class:`Future` methods from a callable submitted to a :class:`ProcessPoolExecutor` will result in deadlock. -.. class:: ProcessPoolExecutor(max_workers=None) +.. class:: ProcessPoolExecutor(max_workers=None, mp_context=None) An :class:`Executor` subclass that executes calls asynchronously using a pool of at most *max_workers* processes. If *max_workers* is ``None`` or not given, it will default to the number of processors on the machine. If *max_workers* is lower or equal to ``0``, then a :exc:`ValueError` will be raised. + *mp_context* can be a multiprocessing context or None. It will be used to + launch the workers. If *mp_context* is ``None`` or not given, the default + multiprocessing context is used. .. versionchanged:: 3.3 When one of the worker processes terminates abruptly, a @@ -205,6 +208,10 @@ to a :class:`ProcessPoolExecutor` will result in deadlock. was undefined but operations on the executor or its futures would often freeze or deadlock. + .. versionchanged:: 3.7 + The *mp_context* argument was added to allow users to control the + start_method for worker processes created by the pool. + .. _processpoolexecutor-example: diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 50ee296ac89..67ebbf51521 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -50,8 +50,7 @@ from concurrent.futures import _base import queue from queue import Full -import multiprocessing -from multiprocessing import SimpleQueue +import multiprocessing as mp from multiprocessing.connection import wait import threading import weakref @@ -74,11 +73,11 @@ # threads/processes finish. _threads_queues = weakref.WeakKeyDictionary() -_shutdown = False +_global_shutdown = False def _python_exit(): - global _shutdown - _shutdown = True + global _global_shutdown + _global_shutdown = True items = list(_threads_queues.items()) for t, q in items: q.put(None) @@ -158,12 +157,10 @@ def _process_worker(call_queue, result_queue): This worker is run in a separate process. Args: - call_queue: A multiprocessing.Queue of _CallItems that will be read and + call_queue: A ctx.Queue of _CallItems that will be read and evaluated by the worker. - result_queue: A multiprocessing.Queue of _ResultItems that will written + result_queue: A ctx.Queue of _ResultItems that will written to by the worker. - shutdown: A multiprocessing.Event that will be set as a signal to the - worker that it should exit when call_queue is empty. """ while True: call_item = call_queue.get(block=True) @@ -180,6 +177,11 @@ def _process_worker(call_queue, result_queue): result_queue.put(_ResultItem(call_item.work_id, result=r)) + # Liberate the resource as soon as possible, to avoid holding onto + # open files or shared memory that is not needed anymore + del call_item + + def _add_call_item_to_queue(pending_work_items, work_ids, call_queue): @@ -231,20 +233,21 @@ def _queue_management_worker(executor_reference, executor_reference: A weakref.ref to the ProcessPoolExecutor that owns this thread. Used to determine if the ProcessPoolExecutor has been garbage collected and that this function can exit. - process: A list of the multiprocessing.Process instances used as + process: A list of the ctx.Process instances used as workers. pending_work_items: A dict mapping work ids to _WorkItems e.g. {5: <_WorkItem...>, 6: <_WorkItem...>, ...} work_ids_queue: A queue.Queue of work ids e.g. Queue([5, 6, ...]). - call_queue: A multiprocessing.Queue that will be filled with _CallItems + call_queue: A ctx.Queue that will be filled with _CallItems derived from _WorkItems for processing by the process workers. - result_queue: A multiprocessing.Queue of _ResultItems generated by the + result_queue: A ctx.SimpleQueue of _ResultItems generated by the process workers. """ executor = None def shutting_down(): - return _shutdown or executor is None or executor._shutdown_thread + return (_global_shutdown or executor is None + or executor._shutdown_thread) def shutdown_worker(): # This is an upper bound @@ -254,7 +257,7 @@ def shutdown_worker(): # Release the queue's resources as soon as possible. call_queue.close() # If .join() is not called on the created processes then - # some multiprocessing.Queue methods may deadlock on Mac OS X. + # some ctx.Queue methods may deadlock on Mac OS X. for p in processes.values(): p.join() @@ -377,13 +380,15 @@ class BrokenProcessPool(RuntimeError): class ProcessPoolExecutor(_base.Executor): - def __init__(self, max_workers=None): + def __init__(self, max_workers=None, mp_context=None): """Initializes a new ProcessPoolExecutor instance. Args: max_workers: The maximum number of processes that can be used to execute the given calls. If None or not given then as many worker processes will be created as the machine has processors. + mp_context: A multiprocessing context to launch the workers. This + object should provide SimpleQueue, Queue and Process. """ _check_system_limits() @@ -394,17 +399,20 @@ def __init__(self, max_workers=None): raise ValueError("max_workers must be greater than 0") self._max_workers = max_workers + if mp_context is None: + mp_context = mp.get_context() + self._mp_context = mp_context # Make the call queue slightly larger than the number of processes to # prevent the worker processes from idling. But don't make it too big # because futures in the call queue cannot be cancelled. - self._call_queue = multiprocessing.Queue(self._max_workers + - EXTRA_QUEUED_CALLS) + queue_size = self._max_workers + EXTRA_QUEUED_CALLS + self._call_queue = mp_context.Queue(queue_size) # Killed worker processes can produce spurious "broken pipe" # tracebacks in the queue's own worker thread. But we detect killed # processes anyway, so silence the tracebacks. self._call_queue._ignore_epipe = True - self._result_queue = SimpleQueue() + self._result_queue = mp_context.SimpleQueue() self._work_ids = queue.Queue() self._queue_management_thread = None # Map of pids to processes @@ -426,23 +434,23 @@ def weakref_cb(_, q=self._result_queue): # Start the processes so that their sentinels are known. self._adjust_process_count() self._queue_management_thread = threading.Thread( - target=_queue_management_worker, - args=(weakref.ref(self, weakref_cb), - self._processes, - self._pending_work_items, - self._work_ids, - self._call_queue, - self._result_queue)) + target=_queue_management_worker, + args=(weakref.ref(self, weakref_cb), + self._processes, + self._pending_work_items, + self._work_ids, + self._call_queue, + self._result_queue)) self._queue_management_thread.daemon = True self._queue_management_thread.start() _threads_queues[self._queue_management_thread] = self._result_queue def _adjust_process_count(self): for _ in range(len(self._processes), self._max_workers): - p = multiprocessing.Process( - target=_process_worker, - args=(self._call_queue, - self._result_queue)) + p = self._mp_context.Process( + target=_process_worker, + args=(self._call_queue, + self._result_queue)) p.start() self._processes[p.pid] = p diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index e4c9ace9356..ed8ad41f8e6 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -19,6 +19,7 @@ from concurrent.futures._base import ( PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future) from concurrent.futures.process import BrokenProcessPool +from multiprocessing import get_context def create_future(state=PENDING, exception=None, result=None): @@ -56,6 +57,15 @@ def my_method(self): pass +class EventfulGCObj(): + def __init__(self, ctx): + mgr = get_context(ctx).Manager() + self.event = mgr.Event() + + def __del__(self): + self.event.set() + + def make_dummy_object(_): return MyObject() @@ -77,7 +87,13 @@ def setUp(self): self.t1 = time.time() try: - self.executor = self.executor_type(max_workers=self.worker_count) + if hasattr(self, "ctx"): + self.executor = self.executor_type( + max_workers=self.worker_count, + mp_context=get_context(self.ctx)) + else: + self.executor = self.executor_type( + max_workers=self.worker_count) except NotImplementedError as e: self.skipTest(str(e)) self._prime_executor() @@ -107,8 +123,29 @@ class ThreadPoolMixin(ExecutorMixin): executor_type = futures.ThreadPoolExecutor -class ProcessPoolMixin(ExecutorMixin): +class ProcessPoolForkMixin(ExecutorMixin): + executor_type = futures.ProcessPoolExecutor + ctx = "fork" + + def setUp(self): + if sys.platform == "win32": + self.skipTest("require unix system") + super().setUp() + + +class ProcessPoolSpawnMixin(ExecutorMixin): + executor_type = futures.ProcessPoolExecutor + ctx = "spawn" + + +class ProcessPoolForkserverMixin(ExecutorMixin): executor_type = futures.ProcessPoolExecutor + ctx = "forkserver" + + def setUp(self): + if sys.platform == "win32": + self.skipTest("require unix system") + super().setUp() class ExecutorShutdownTest: @@ -124,9 +161,17 @@ def test_interpreter_shutdown(self): from concurrent.futures import {executor_type} from time import sleep from test.test_concurrent_futures import sleep_and_print - t = {executor_type}(5) - t.submit(sleep_and_print, 1.0, "apple") - """.format(executor_type=self.executor_type.__name__)) + if __name__ == "__main__": + context = '{context}' + if context == "": + t = {executor_type}(5) + else: + from multiprocessing import get_context + context = get_context(context) + t = {executor_type}(5, mp_context=context) + t.submit(sleep_and_print, 1.0, "apple") + """.format(executor_type=self.executor_type.__name__, + context=getattr(self, "ctx", ""))) # Errors in atexit hooks don't change the process exit code, check # stderr manually. self.assertFalse(err) @@ -194,7 +239,7 @@ def test_thread_names_default(self): t.join() -class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest, BaseTestCase): +class ProcessPoolShutdownTest(ExecutorShutdownTest): def _prime_executor(self): pass @@ -233,6 +278,22 @@ def test_del_shutdown(self): call_queue.join_thread() +class ProcessPoolForkShutdownTest(ProcessPoolForkMixin, BaseTestCase, + ProcessPoolShutdownTest): + pass + + +class ProcessPoolForkserverShutdownTest(ProcessPoolForkserverMixin, + BaseTestCase, + ProcessPoolShutdownTest): + pass + + +class ProcessPoolSpawnShutdownTest(ProcessPoolSpawnMixin, BaseTestCase, + ProcessPoolShutdownTest): + pass + + class WaitTests: def test_first_completed(self): @@ -352,7 +413,17 @@ def future_func(): sys.setswitchinterval(oldswitchinterval) -class ProcessPoolWaitTests(ProcessPoolMixin, WaitTests, BaseTestCase): +class ProcessPoolForkWaitTests(ProcessPoolForkMixin, WaitTests, BaseTestCase): + pass + + +class ProcessPoolForkserverWaitTests(ProcessPoolForkserverMixin, WaitTests, + BaseTestCase): + pass + + +class ProcessPoolSpawnWaitTests(ProcessPoolSpawnMixin, BaseTestCase, + WaitTests): pass @@ -440,7 +511,19 @@ class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests, BaseTestCase pass -class ProcessPoolAsCompletedTests(ProcessPoolMixin, AsCompletedTests, BaseTestCase): +class ProcessPoolForkAsCompletedTests(ProcessPoolForkMixin, AsCompletedTests, + BaseTestCase): + pass + + +class ProcessPoolForkserverAsCompletedTests(ProcessPoolForkserverMixin, + AsCompletedTests, + BaseTestCase): + pass + + +class ProcessPoolSpawnAsCompletedTests(ProcessPoolSpawnMixin, AsCompletedTests, + BaseTestCase): pass @@ -540,7 +623,7 @@ def test_default_workers(self): (os.cpu_count() or 1) * 5) -class ProcessPoolExecutorTest(ProcessPoolMixin, ExecutorTest, BaseTestCase): +class ProcessPoolExecutorTest(ExecutorTest): def test_killed_child(self): # When a child process is abruptly terminated, the whole pool gets # "broken". @@ -595,6 +678,34 @@ def test_traceback(self): self.assertIn('raise RuntimeError(123) # some comment', f1.getvalue()) + def test_ressources_gced_in_workers(self): + # Ensure that argument for a job are correctly gc-ed after the job + # is finished + obj = EventfulGCObj(self.ctx) + future = self.executor.submit(id, obj) + future.result() + + self.assertTrue(obj.event.wait(timeout=1)) + + +class ProcessPoolForkExecutorTest(ProcessPoolForkMixin, + ProcessPoolExecutorTest, + BaseTestCase): + pass + + +class ProcessPoolForkserverExecutorTest(ProcessPoolForkserverMixin, + ProcessPoolExecutorTest, + BaseTestCase): + pass + + +class ProcessPoolSpawnExecutorTest(ProcessPoolSpawnMixin, + ProcessPoolExecutorTest, + BaseTestCase): + pass + + class FutureTests(BaseTestCase): def test_done_callback_with_result(self): diff --git a/Misc/NEWS.d/next/Library/2017-09-22-16-02-00.bpo-31540.ybDHT5.rst b/Misc/NEWS.d/next/Library/2017-09-22-16-02-00.bpo-31540.ybDHT5.rst new file mode 100644 index 00000000000..0b4259f8847 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-09-22-16-02-00.bpo-31540.ybDHT5.rst @@ -0,0 +1,4 @@ +Allow passing a context object in +:class:`concurrent.futures.ProcessPoolExecutor` constructor. +Also, free job ressources in :class:`concurrent.futures.ProcessPoolExecutor` +earlier to improve memory usage when a worker waits for new jobs. From webhook-mailer at python.org Tue Oct 3 06:46:37 2017 From: webhook-mailer at python.org (INADA Naoki) Date: Tue, 03 Oct 2017 10:46:37 -0000 Subject: [Python-checkins] bpo-31415: Add `-X importtime` option (GH-3490) Message-ID: https://github.com/python/cpython/commit/1a87de7fcfa3c19f08e29047337c350b4a32b259 commit: 1a87de7fcfa3c19f08e29047337c350b4a32b259 branch: master author: INADA Naoki committer: GitHub date: 2017-10-03T19:46:34+09:00 summary: bpo-31415: Add `-X importtime` option (GH-3490) It shows show import time of each module. It's useful for optimizing startup time. Typical usage: python -X importtime -c 'import requests' files: A Misc/NEWS.d/next/Core and Builtins/2017-09-11-14-28-56.bpo-31415.GBdz7o.rst M Doc/using/cmdline.rst M Python/import.c diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 5adad159e65..9c1c269d1df 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -407,6 +407,10 @@ Miscellaneous options * ``-X showalloccount`` to output the total count of allocated objects for each type when the program finishes. This only works when Python was built with ``COUNT_ALLOCS`` defined. + * ``-X importtime`` to show how long each import takes. It shows module name, + cumulative time (including nested imports) and self time (exluding nested + imports). Note that its output may be broken in multi threaded application. + Typical usage is ``python3 -X importtime -c 'import asyncio'``. It also allows passing arbitrary values and retrieving them through the :data:`sys._xoptions` dictionary. @@ -423,6 +427,9 @@ Miscellaneous options .. versionadded:: 3.6 The ``-X showalloccount`` option. + .. versionadded:: 3.7 + The ``-X importtime`` option. + Options you shouldn't use ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-09-11-14-28-56.bpo-31415.GBdz7o.rst b/Misc/NEWS.d/next/Core and Builtins/2017-09-11-14-28-56.bpo-31415.GBdz7o.rst new file mode 100644 index 00000000000..52aa16a972b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-09-11-14-28-56.bpo-31415.GBdz7o.rst @@ -0,0 +1,2 @@ +Add ``-X importtime`` option to show how long each import takes. It can +be used to optimize application's startup time. diff --git a/Python/import.c b/Python/import.c index e50ea4d03cc..7554bf86272 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1667,8 +1667,38 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, } } else { + static int ximporttime = 0; + static int import_level; + static _PyTime_t accumulated; + _Py_IDENTIFIER(importtime); + + _PyTime_t t1 = 0, accumulated_copy = accumulated; + Py_XDECREF(mod); + /* XOptions is initialized after first some imports. + * So we can't have negative cache. + * Anyway, importlib.__find_and_load is much slower than + * _PyDict_GetItemId() + */ + if (ximporttime == 0) { + PyObject *xoptions = PySys_GetXOptions(); + if (xoptions) { + PyObject *value = _PyDict_GetItemId(xoptions, &PyId_importtime); + ximporttime = (value == Py_True); + } + if (ximporttime) { + fputs("import time: self [us] | cumulative | imported package\n", + stderr); + } + } + + if (ximporttime) { + import_level++; + t1 = _PyTime_GetMonotonicClock(); + accumulated = 0; + } + if (PyDTrace_IMPORT_FIND_LOAD_START_ENABLED()) PyDTrace_IMPORT_FIND_LOAD_START(PyUnicode_AsUTF8(abs_name)); @@ -1680,6 +1710,18 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, PyDTrace_IMPORT_FIND_LOAD_DONE(PyUnicode_AsUTF8(abs_name), mod != NULL); + if (ximporttime) { + _PyTime_t cum = _PyTime_GetMonotonicClock() - t1; + + import_level--; + fprintf(stderr, "import time: %9ld | %10ld | %*s%s\n", + (long)_PyTime_AsMicroseconds(cum - accumulated, _PyTime_ROUND_CEILING), + (long)_PyTime_AsMicroseconds(cum, _PyTime_ROUND_CEILING), + import_level*2, "", PyUnicode_AsUTF8(abs_name)); + + accumulated = accumulated_copy + cum; + } + if (mod == NULL) { goto error; } From webhook-mailer at python.org Tue Oct 3 07:13:47 2017 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Tue, 03 Oct 2017 11:13:47 -0000 Subject: [Python-checkins] bpo-31619: Fixed a ValueError when convert a string with large number of underscores (#3827) Message-ID: https://github.com/python/cpython/commit/85c0b8941f0c8ef3ed787c9d504712c6ad3eb5d3 commit: 85c0b8941f0c8ef3ed787c9d504712c6ad3eb5d3 branch: master author: Serhiy Storchaka committer: GitHub date: 2017-10-03T14:13:44+03:00 summary: bpo-31619: Fixed a ValueError when convert a string with large number of underscores (#3827) to integer with binary base. files: A Misc/NEWS.d/next/Core and Builtins/2017-09-29-20-32-24.bpo-31619.6gQ1kv.rst M Lib/test/test_int.py M Objects/longobject.c diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index 854117efd74..c048b712da8 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -508,5 +508,13 @@ def check(s, base=None): check('123\ud800') check('123\ud800', 10) + def test_issue31619(self): + self.assertEqual(int('1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1', 2), + 0b1010101010101010101010101010101) + self.assertEqual(int('1_2_3_4_5_6_7_0_1_2_3', 8), 0o12345670123) + self.assertEqual(int('1_2_3_4_5_6_7_8_9', 16), 0x123456789) + self.assertEqual(int('1_2_3_4_5_6_7', 32), 1144132807) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-09-29-20-32-24.bpo-31619.6gQ1kv.rst b/Misc/NEWS.d/next/Core and Builtins/2017-09-29-20-32-24.bpo-31619.6gQ1kv.rst new file mode 100644 index 00000000000..3efcc9d134d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-09-29-20-32-24.bpo-31619.6gQ1kv.rst @@ -0,0 +1,2 @@ +Fixed a ValueError when convert a string with large number of underscores +to integer with binary base. diff --git a/Objects/longobject.c b/Objects/longobject.c index 3b07585669e..c71b783cc03 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2057,15 +2057,15 @@ long_from_binary_base(const char **str, int base, PyLongObject **res) } *str = p; - /* n <- # of Python digits needed, = ceiling(n/PyLong_SHIFT). */ - n = digits * bits_per_char + PyLong_SHIFT - 1; - if (n / bits_per_char < p - start) { + /* n <- the number of Python digits needed, + = ceiling((digits * bits_per_char) / PyLong_SHIFT). */ + if (digits > (PY_SSIZE_T_MAX - (PyLong_SHIFT - 1)) / bits_per_char) { PyErr_SetString(PyExc_ValueError, "int string too large to convert"); *res = NULL; return 0; } - n = n / PyLong_SHIFT; + n = (digits * bits_per_char + PyLong_SHIFT - 1) / PyLong_SHIFT; z = _PyLong_New(n); if (z == NULL) { *res = NULL; From webhook-mailer at python.org Tue Oct 3 08:38:49 2017 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Tue, 03 Oct 2017 12:38:49 -0000 Subject: [Python-checkins] [3.6] bpo-31619: Fixed a ValueError when convert a string with large number of underscores (GH-3827) (#3863) Message-ID: https://github.com/python/cpython/commit/b5a630f3dd30ed628e088efe7523e650087adba2 commit: b5a630f3dd30ed628e088efe7523e650087adba2 branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Serhiy Storchaka date: 2017-10-03T15:38:46+03:00 summary: [3.6] bpo-31619: Fixed a ValueError when convert a string with large number of underscores (GH-3827) (#3863) to integer with binary base. (cherry picked from commit 85c0b8941f0c8ef3ed787c9d504712c6ad3eb5d3) files: A Misc/NEWS.d/next/Core and Builtins/2017-09-29-20-32-24.bpo-31619.6gQ1kv.rst M Lib/test/test_int.py M Objects/longobject.c diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index 14bbd6192a0..a36076e0104 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -506,5 +506,13 @@ def check(s, base=None): check('123\ud800') check('123\ud800', 10) + def test_issue31619(self): + self.assertEqual(int('1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1', 2), + 0b1010101010101010101010101010101) + self.assertEqual(int('1_2_3_4_5_6_7_0_1_2_3', 8), 0o12345670123) + self.assertEqual(int('1_2_3_4_5_6_7_8_9', 16), 0x123456789) + self.assertEqual(int('1_2_3_4_5_6_7', 32), 1144132807) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-09-29-20-32-24.bpo-31619.6gQ1kv.rst b/Misc/NEWS.d/next/Core and Builtins/2017-09-29-20-32-24.bpo-31619.6gQ1kv.rst new file mode 100644 index 00000000000..3efcc9d134d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-09-29-20-32-24.bpo-31619.6gQ1kv.rst @@ -0,0 +1,2 @@ +Fixed a ValueError when convert a string with large number of underscores +to integer with binary base. diff --git a/Objects/longobject.c b/Objects/longobject.c index ad239ce84e2..450087b5b15 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2049,15 +2049,15 @@ long_from_binary_base(const char **str, int base, PyLongObject **res) } *str = p; - /* n <- # of Python digits needed, = ceiling(n/PyLong_SHIFT). */ - n = digits * bits_per_char + PyLong_SHIFT - 1; - if (n / bits_per_char < p - start) { + /* n <- the number of Python digits needed, + = ceiling((digits * bits_per_char) / PyLong_SHIFT). */ + if (digits > (PY_SSIZE_T_MAX - (PyLong_SHIFT - 1)) / bits_per_char) { PyErr_SetString(PyExc_ValueError, "int string too large to convert"); *res = NULL; return 0; } - n = n / PyLong_SHIFT; + n = (digits * bits_per_char + PyLong_SHIFT - 1) / PyLong_SHIFT; z = _PyLong_New(n); if (z == NULL) { *res = NULL; From webhook-mailer at python.org Tue Oct 3 12:46:59 2017 From: webhook-mailer at python.org (Mariatta) Date: Tue, 03 Oct 2017 16:46:59 -0000 Subject: [Python-checkins] bpo-31657: Add test coverage for the __debug__ case (GH-3450) Message-ID: https://github.com/python/cpython/commit/543386b7f077d210ea0722079d68beb6c066730a commit: 543386b7f077d210ea0722079d68beb6c066730a branch: master author: diana committer: Mariatta date: 2017-10-03T09:46:56-07:00 summary: bpo-31657: Add test coverage for the __debug__ case (GH-3450) Update the compile tests for optimization levels to also check that __debug__ blocks are included or excluded based on the optimization level. Patch by Diana Clarke. files: M Lib/test/test_builtin.py diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 9d949b74cb8..87dcda7b434 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -328,19 +328,22 @@ def test_compile(self): codestr = '''def f(): """doc""" + debug_enabled = False + if __debug__: + debug_enabled = True try: assert False except AssertionError: - return (True, f.__doc__) + return (True, f.__doc__, debug_enabled) else: - return (False, f.__doc__) + return (False, f.__doc__, debug_enabled) ''' def f(): """doc""" - values = [(-1, __debug__, f.__doc__), - (0, True, 'doc'), - (1, False, 'doc'), - (2, False, None)] - for optval, debugval, docstring in values: + values = [(-1, __debug__, f.__doc__, __debug__), + (0, True, 'doc', True), + (1, False, 'doc', False), + (2, False, None, False)] + for optval, assertval, docstring, debugval in values: # test both direct compilation and compilation via AST codeobjs = [] codeobjs.append(compile(codestr, "", "exec", optimize=optval)) @@ -350,7 +353,7 @@ def f(): """doc""" ns = {} exec(code, ns) rv = ns['f']() - self.assertEqual(rv, (debugval, docstring)) + self.assertEqual(rv, (assertval, docstring, debugval)) def test_delattr(self): sys.spam = 1 From webhook-mailer at python.org Tue Oct 3 14:37:26 2017 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Tue, 03 Oct 2017 18:37:26 -0000 Subject: [Python-checkins] bpo-31673: Fixed typo in the name of Tkinter's method adderrorinfo(). (#3864) Message-ID: https://github.com/python/cpython/commit/929b40a601db868530d6beaafb3256822103a7fb commit: 929b40a601db868530d6beaafb3256822103a7fb branch: master author: Serhiy Storchaka committer: GitHub date: 2017-10-03T21:37:22+03:00 summary: bpo-31673: Fixed typo in the name of Tkinter's method adderrorinfo(). (#3864) files: A Misc/NEWS.d/next/Library/2017-10-03-14-37-46.bpo-31673.RFCrka.rst M Modules/_tkinter.c M Modules/clinic/_tkinter.c.h diff --git a/Misc/NEWS.d/next/Library/2017-10-03-14-37-46.bpo-31673.RFCrka.rst b/Misc/NEWS.d/next/Library/2017-10-03-14-37-46.bpo-31673.RFCrka.rst new file mode 100644 index 00000000000..8fce050c041 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-10-03-14-37-46.bpo-31673.RFCrka.rst @@ -0,0 +1 @@ +Fixed typo in the name of Tkinter's method adderrorinfo(). diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 91d3dd583ed..07ebaddd8c5 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1640,7 +1640,7 @@ _tkinter_tkapp_record_impl(TkappObject *self, const char *script) } /*[clinic input] -_tkinter.tkapp.adderrinfo +_tkinter.tkapp.adderrorinfo msg: str / @@ -1648,8 +1648,8 @@ _tkinter.tkapp.adderrinfo [clinic start generated code]*/ static PyObject * -_tkinter_tkapp_adderrinfo_impl(TkappObject *self, const char *msg) -/*[clinic end generated code: output=0e222ee2050eb357 input=4971399317d4c136]*/ +_tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg) +/*[clinic end generated code: output=52162eaca2ee53cb input=f4b37aec7c7e8c77]*/ { CHECK_STRING_LENGTH(msg); CHECK_TCL_APPARTMENT; @@ -3253,7 +3253,7 @@ static PyMethodDef Tkapp_methods[] = _TKINTER_TKAPP_EVAL_METHODDEF _TKINTER_TKAPP_EVALFILE_METHODDEF _TKINTER_TKAPP_RECORD_METHODDEF - _TKINTER_TKAPP_ADDERRINFO_METHODDEF + _TKINTER_TKAPP_ADDERRORINFO_METHODDEF {"setvar", Tkapp_SetVar, METH_VARARGS}, {"globalsetvar", Tkapp_GlobalSetVar, METH_VARARGS}, {"getvar", Tkapp_GetVar, METH_VARARGS}, diff --git a/Modules/clinic/_tkinter.c.h b/Modules/clinic/_tkinter.c.h index 040a745b28e..6b8dabb0b56 100644 --- a/Modules/clinic/_tkinter.c.h +++ b/Modules/clinic/_tkinter.c.h @@ -80,27 +80,27 @@ _tkinter_tkapp_record(TkappObject *self, PyObject *arg) return return_value; } -PyDoc_STRVAR(_tkinter_tkapp_adderrinfo__doc__, -"adderrinfo($self, msg, /)\n" +PyDoc_STRVAR(_tkinter_tkapp_adderrorinfo__doc__, +"adderrorinfo($self, msg, /)\n" "--\n" "\n"); -#define _TKINTER_TKAPP_ADDERRINFO_METHODDEF \ - {"adderrinfo", (PyCFunction)_tkinter_tkapp_adderrinfo, METH_O, _tkinter_tkapp_adderrinfo__doc__}, +#define _TKINTER_TKAPP_ADDERRORINFO_METHODDEF \ + {"adderrorinfo", (PyCFunction)_tkinter_tkapp_adderrorinfo, METH_O, _tkinter_tkapp_adderrorinfo__doc__}, static PyObject * -_tkinter_tkapp_adderrinfo_impl(TkappObject *self, const char *msg); +_tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg); static PyObject * -_tkinter_tkapp_adderrinfo(TkappObject *self, PyObject *arg) +_tkinter_tkapp_adderrorinfo(TkappObject *self, PyObject *arg) { PyObject *return_value = NULL; const char *msg; - if (!PyArg_Parse(arg, "s:adderrinfo", &msg)) { + if (!PyArg_Parse(arg, "s:adderrorinfo", &msg)) { goto exit; } - return_value = _tkinter_tkapp_adderrinfo_impl(self, msg); + return_value = _tkinter_tkapp_adderrorinfo_impl(self, msg); exit: return return_value; @@ -638,4 +638,4 @@ _tkinter_getbusywaitinterval(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */ -/*[clinic end generated code: output=3b9241f7c703ae4f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ca36236c57713ba0 input=a9049054013a1b77]*/ From webhook-mailer at python.org Tue Oct 3 15:39:40 2017 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Tue, 03 Oct 2017 19:39:40 -0000 Subject: [Python-checkins] [3.6] bpo-31673: Fixed typo in the name of Tkinter's method adderrorinfo(). (GH-3864). (#3873) Message-ID: https://github.com/python/cpython/commit/fcc832a4fafcbbaca5484ed0274935e14c9dcf6b commit: fcc832a4fafcbbaca5484ed0274935e14c9dcf6b branch: 3.6 author: Serhiy Storchaka committer: GitHub date: 2017-10-03T22:39:37+03:00 summary: [3.6] bpo-31673: Fixed typo in the name of Tkinter's method adderrorinfo(). (GH-3864). (#3873) (cherry picked from commit 929b40a601db868530d6beaafb3256822103a7fb) files: A Misc/NEWS.d/next/Library/2017-10-03-14-37-46.bpo-31673.RFCrka.rst M Modules/_tkinter.c M Modules/clinic/_tkinter.c.h diff --git a/Misc/NEWS.d/next/Library/2017-10-03-14-37-46.bpo-31673.RFCrka.rst b/Misc/NEWS.d/next/Library/2017-10-03-14-37-46.bpo-31673.RFCrka.rst new file mode 100644 index 00000000000..8fce050c041 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-10-03-14-37-46.bpo-31673.RFCrka.rst @@ -0,0 +1 @@ +Fixed typo in the name of Tkinter's method adderrorinfo(). diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 4a1324cb7e6..ef6f8bcfcc9 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1668,7 +1668,7 @@ _tkinter_tkapp_record_impl(TkappObject *self, const char *script) } /*[clinic input] -_tkinter.tkapp.adderrinfo +_tkinter.tkapp.adderrorinfo msg: str / @@ -1676,8 +1676,8 @@ _tkinter.tkapp.adderrinfo [clinic start generated code]*/ static PyObject * -_tkinter_tkapp_adderrinfo_impl(TkappObject *self, const char *msg) -/*[clinic end generated code: output=0e222ee2050eb357 input=4971399317d4c136]*/ +_tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg) +/*[clinic end generated code: output=52162eaca2ee53cb input=f4b37aec7c7e8c77]*/ { CHECK_STRING_LENGTH(msg); CHECK_TCL_APPARTMENT; @@ -3304,7 +3304,7 @@ static PyMethodDef Tkapp_methods[] = _TKINTER_TKAPP_EVAL_METHODDEF _TKINTER_TKAPP_EVALFILE_METHODDEF _TKINTER_TKAPP_RECORD_METHODDEF - _TKINTER_TKAPP_ADDERRINFO_METHODDEF + _TKINTER_TKAPP_ADDERRORINFO_METHODDEF {"setvar", Tkapp_SetVar, METH_VARARGS}, {"globalsetvar", Tkapp_GlobalSetVar, METH_VARARGS}, {"getvar", Tkapp_GetVar, METH_VARARGS}, diff --git a/Modules/clinic/_tkinter.c.h b/Modules/clinic/_tkinter.c.h index edd53800058..c407f17da4c 100644 --- a/Modules/clinic/_tkinter.c.h +++ b/Modules/clinic/_tkinter.c.h @@ -80,27 +80,27 @@ _tkinter_tkapp_record(TkappObject *self, PyObject *arg) return return_value; } -PyDoc_STRVAR(_tkinter_tkapp_adderrinfo__doc__, -"adderrinfo($self, msg, /)\n" +PyDoc_STRVAR(_tkinter_tkapp_adderrorinfo__doc__, +"adderrorinfo($self, msg, /)\n" "--\n" "\n"); -#define _TKINTER_TKAPP_ADDERRINFO_METHODDEF \ - {"adderrinfo", (PyCFunction)_tkinter_tkapp_adderrinfo, METH_O, _tkinter_tkapp_adderrinfo__doc__}, +#define _TKINTER_TKAPP_ADDERRORINFO_METHODDEF \ + {"adderrorinfo", (PyCFunction)_tkinter_tkapp_adderrorinfo, METH_O, _tkinter_tkapp_adderrorinfo__doc__}, static PyObject * -_tkinter_tkapp_adderrinfo_impl(TkappObject *self, const char *msg); +_tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg); static PyObject * -_tkinter_tkapp_adderrinfo(TkappObject *self, PyObject *arg) +_tkinter_tkapp_adderrorinfo(TkappObject *self, PyObject *arg) { PyObject *return_value = NULL; const char *msg; - if (!PyArg_Parse(arg, "s:adderrinfo", &msg)) { + if (!PyArg_Parse(arg, "s:adderrorinfo", &msg)) { goto exit; } - return_value = _tkinter_tkapp_adderrinfo_impl(self, msg); + return_value = _tkinter_tkapp_adderrorinfo_impl(self, msg); exit: return return_value; @@ -638,4 +638,4 @@ _tkinter_getbusywaitinterval(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */ -/*[clinic end generated code: output=836c578b71d69097 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b0be55aacff2be9b input=a9049054013a1b77]*/ From webhook-mailer at python.org Tue Oct 3 15:39:59 2017 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Tue, 03 Oct 2017 19:39:59 -0000 Subject: [Python-checkins] bpo-31675: Fix memory leaks in Tkinter's methods splitlist() and split() (#3866) Message-ID: https://github.com/python/cpython/commit/27c623c845dd6e4b8e1782666ca3a956636da266 commit: 27c623c845dd6e4b8e1782666ca3a956636da266 branch: master author: Serhiy Storchaka committer: GitHub date: 2017-10-03T22:39:55+03:00 summary: bpo-31675: Fix memory leaks in Tkinter's methods splitlist() and split() (#3866) when pass a string larger than 2 GiB. Decrease memory requirements for Tcl's bigmem tests. files: A Misc/NEWS.d/next/Library/2017-10-03-15-06-24.bpo-31675.Nh7jJ3.rst M Lib/test/test_tcl.py M Modules/_tkinter.c diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index 8ffd1853147..db99b75eec6 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -662,32 +662,44 @@ def setUp(self): @support.bigmemtest(size=INT_MAX + 1, memuse=5, dry_run=False) def test_huge_string_call(self, size): value = ' ' * size - self.assertRaises(OverflowError, self.interp.call, 'set', '_', value) + self.assertRaises(OverflowError, self.interp.call, 'string', 'index', value, 0) @support.cpython_only @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") - @support.bigmemtest(size=INT_MAX + 1, memuse=9, dry_run=False) + @support.bigmemtest(size=INT_MAX + 1, memuse=2, dry_run=False) def test_huge_string_builtins(self, size): + tk = self.interp.tk value = '1' + ' ' * size - self.assertRaises(OverflowError, self.interp.tk.getint, value) - self.assertRaises(OverflowError, self.interp.tk.getdouble, value) - self.assertRaises(OverflowError, self.interp.tk.getboolean, value) - self.assertRaises(OverflowError, self.interp.eval, value) - self.assertRaises(OverflowError, self.interp.evalfile, value) - self.assertRaises(OverflowError, self.interp.record, value) - self.assertRaises(OverflowError, self.interp.adderrorinfo, value) - self.assertRaises(OverflowError, self.interp.setvar, value, 'x', 'a') - self.assertRaises(OverflowError, self.interp.setvar, 'x', value, 'a') - self.assertRaises(OverflowError, self.interp.unsetvar, value) - self.assertRaises(OverflowError, self.interp.unsetvar, 'x', value) - self.assertRaises(OverflowError, self.interp.adderrorinfo, value) - self.assertRaises(OverflowError, self.interp.exprstring, value) - self.assertRaises(OverflowError, self.interp.exprlong, value) - self.assertRaises(OverflowError, self.interp.exprboolean, value) - self.assertRaises(OverflowError, self.interp.splitlist, value) - self.assertRaises(OverflowError, self.interp.split, value) - self.assertRaises(OverflowError, self.interp.createcommand, value, max) - self.assertRaises(OverflowError, self.interp.deletecommand, value) + self.assertRaises(OverflowError, tk.getint, value) + self.assertRaises(OverflowError, tk.getdouble, value) + self.assertRaises(OverflowError, tk.getboolean, value) + self.assertRaises(OverflowError, tk.eval, value) + self.assertRaises(OverflowError, tk.evalfile, value) + self.assertRaises(OverflowError, tk.record, value) + self.assertRaises(OverflowError, tk.adderrorinfo, value) + self.assertRaises(OverflowError, tk.setvar, value, 'x', 'a') + self.assertRaises(OverflowError, tk.setvar, 'x', value, 'a') + self.assertRaises(OverflowError, tk.unsetvar, value) + self.assertRaises(OverflowError, tk.unsetvar, 'x', value) + self.assertRaises(OverflowError, tk.adderrorinfo, value) + self.assertRaises(OverflowError, tk.exprstring, value) + self.assertRaises(OverflowError, tk.exprlong, value) + self.assertRaises(OverflowError, tk.exprboolean, value) + self.assertRaises(OverflowError, tk.splitlist, value) + self.assertRaises(OverflowError, tk.split, value) + self.assertRaises(OverflowError, tk.createcommand, value, max) + self.assertRaises(OverflowError, tk.deletecommand, value) + + @support.cpython_only + @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") + @support.bigmemtest(size=INT_MAX + 1, memuse=6, dry_run=False) + def test_huge_string_builtins2(self, size): + # These commands require larger memory for possible error messages + tk = self.interp.tk + value = '1' + ' ' * size + self.assertRaises(OverflowError, tk.evalfile, value) + self.assertRaises(OverflowError, tk.unsetvar, value) + self.assertRaises(OverflowError, tk.unsetvar, 'x', value) def setUpModule(): diff --git a/Misc/NEWS.d/next/Library/2017-10-03-15-06-24.bpo-31675.Nh7jJ3.rst b/Misc/NEWS.d/next/Library/2017-10-03-15-06-24.bpo-31675.Nh7jJ3.rst new file mode 100644 index 00000000000..4e4430773af --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-10-03-15-06-24.bpo-31675.Nh7jJ3.rst @@ -0,0 +1,2 @@ +Fixed memory leaks in Tkinter's methods splitlist() and split() when pass a +string larger than 2 GiB. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 07ebaddd8c5..005214e27f7 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -2257,7 +2257,11 @@ _tkinter_tkapp_splitlist(TkappObject *self, PyObject *arg) if (!PyArg_Parse(arg, "et:splitlist", "utf-8", &list)) return NULL; - CHECK_STRING_LENGTH(list); + if (strlen(list) >= INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string is too long"); + PyMem_Free(list); + return NULL; + } if (Tcl_SplitList(Tkapp_Interp(self), list, &argc, &argv) == TCL_ERROR) { PyMem_Free(list); @@ -2328,7 +2332,11 @@ _tkinter_tkapp_split(TkappObject *self, PyObject *arg) if (!PyArg_Parse(arg, "et:split", "utf-8", &list)) return NULL; - CHECK_STRING_LENGTH(list); + if (strlen(list) >= INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string is too long"); + PyMem_Free(list); + return NULL; + } v = Split(list); PyMem_Free(list); return v; From webhook-mailer at python.org Tue Oct 3 16:50:49 2017 From: webhook-mailer at python.org (Serhiy Storchaka) Date: Tue, 03 Oct 2017 20:50:49 -0000 Subject: [Python-checkins] [3.6] bpo-31675: Fix memory leaks in Tkinter's methods splitlist() and split() (GH-3866) (#3874) Message-ID: https://github.com/python/cpython/commit/a65b2420f681c45db43e94bfe3dc50ad1dfcd03d commit: a65b2420f681c45db43e94bfe3dc50ad1dfcd03d branch: 3.6 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Serhiy Storchaka date: 2017-10-03T23:50:46+03:00 summary: [3.6] bpo-31675: Fix memory leaks in Tkinter's methods splitlist() and split() (GH-3866) (#3874) when pass a string larger than 2 GiB. Decrease memory requirements for Tcl's bigmem tests. (cherry picked from commit 27c623c845dd6e4b8e1782666ca3a956636da266) files: A Misc/NEWS.d/next/Library/2017-10-03-15-06-24.bpo-31675.Nh7jJ3.rst M Lib/test/test_tcl.py M Modules/_tkinter.c diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index 8ffd1853147..db99b75eec6 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -662,32 +662,44 @@ def setUp(self): @support.bigmemtest(size=INT_MAX + 1, memuse=5, dry_run=False) def test_huge_string_call(self, size): value = ' ' * size - self.assertRaises(OverflowError, self.interp.call, 'set', '_', value) + self.assertRaises(OverflowError, self.interp.call, 'string', 'index', value, 0) @support.cpython_only @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") - @support.bigmemtest(size=INT_MAX + 1, memuse=9, dry_run=False) + @support.bigmemtest(size=INT_MAX + 1, memuse=2, dry_run=False) def test_huge_string_builtins(self, size): + tk = self.interp.tk value = '1' + ' ' * size - self.assertRaises(OverflowError, self.interp.tk.getint, value) - self.assertRaises(OverflowError, self.interp.tk.getdouble, value) - self.assertRaises(OverflowError, self.interp.tk.getboolean, value) - self.assertRaises(OverflowError, self.interp.eval, value) - self.assertRaises(OverflowError, self.interp.evalfile, value) - self.assertRaises(OverflowError, self.interp.record, value) - self.assertRaises(OverflowError, self.interp.adderrorinfo, value) - self.assertRaises(OverflowError, self.interp.setvar, value, 'x', 'a') - self.assertRaises(OverflowError, self.interp.setvar, 'x', value, 'a') - self.assertRaises(OverflowError, self.interp.unsetvar, value) - self.assertRaises(OverflowError, self.interp.unsetvar, 'x', value) - self.assertRaises(OverflowError, self.interp.adderrorinfo, value) - self.assertRaises(OverflowError, self.interp.exprstring, value) - self.assertRaises(OverflowError, self.interp.exprlong, value) - self.assertRaises(OverflowError, self.interp.exprboolean, value) - self.assertRaises(OverflowError, self.interp.splitlist, value) - self.assertRaises(OverflowError, self.interp.split, value) - self.assertRaises(OverflowError, self.interp.createcommand, value, max) - self.assertRaises(OverflowError, self.interp.deletecommand, value) + self.assertRaises(OverflowError, tk.getint, value) + self.assertRaises(OverflowError, tk.getdouble, value) + self.assertRaises(OverflowError, tk.getboolean, value) + self.assertRaises(OverflowError, tk.eval, value) + self.assertRaises(OverflowError, tk.evalfile, value) + self.assertRaises(OverflowError, tk.record, value) + self.assertRaises(OverflowError, tk.adderrorinfo, value) + self.assertRaises(OverflowError, tk.setvar, value, 'x', 'a') + self.assertRaises(OverflowError, tk.setvar, 'x', value, 'a') + self.assertRaises(OverflowError, tk.unsetvar, value) + self.assertRaises(OverflowError, tk.unsetvar, 'x', value) + self.assertRaises(OverflowError, tk.adderrorinfo, value) + self.assertRaises(OverflowError, tk.exprstring, value) + self.assertRaises(OverflowError, tk.exprlong, value) + self.assertRaises(OverflowError, tk.exprboolean, value) + self.assertRaises(OverflowError, tk.splitlist, value) + self.assertRaises(OverflowError, tk.split, value) + self.assertRaises(OverflowError, tk.createcommand, value, max) + self.assertRaises(OverflowError, tk.deletecommand, value) + + @support.cpython_only + @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") + @support.bigmemtest(size=INT_MAX + 1, memuse=6, dry_run=False) + def test_huge_string_builtins2(self, size): + # These commands require larger memory for possible error messages + tk = self.interp.tk + value = '1' + ' ' * size + self.assertRaises(OverflowError, tk.evalfile, value) + self.assertRaises(OverflowError, tk.unsetvar, value) + self.assertRaises(OverflowError, tk.unsetvar, 'x', value) def setUpModule(): diff --git a/Misc/NEWS.d/next/Library/2017-10-03-15-06-24.bpo-31675.Nh7jJ3.rst b/Misc/NEWS.d/next/Library/2017-10-03-15-06-24.bpo-31675.Nh7jJ3.rst new file mode 100644 index 00000000000..4e4430773af --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-10-03-15-06-24.bpo-31675.Nh7jJ3.rst @@ -0,0 +1,2 @@ +Fixed memory leaks in Tkinter's methods splitlist() and split() when pass a +string larger than 2 GiB. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index ef6f8bcfcc9..68ee26e790c 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -2291,7 +2291,11 @@ _tkinter_tkapp_splitlist(TkappObject *self, PyObject *arg) if (!PyArg_Parse(arg, "et:splitlist", "utf-8", &list)) return NULL; - CHECK_STRING_LENGTH(list); + if (strlen(list) >= INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string is too long"); + PyMem_Free(list); + return NULL; + } if (Tcl_SplitList(Tkapp_Interp(self), list, &argc, &argv) == TCL_ERROR) { PyMem_Free(list); @@ -2362,7 +2366,11 @@ _tkinter_tkapp_split(TkappObject *self, PyObject *arg) if (!PyArg_Parse(arg, "et:split", "utf-8", &list)) return NULL; - CHECK_STRING_LENGTH(list); + if (strlen(list) >= INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string is too long"); + PyMem_Free(list); + return NULL; + } v = Split(list); PyMem_Free(list); return v; From lp_benchmark_robot at intel.com Tue Oct 3 20:08:09 2017 From: lp_benchmark_robot at intel.com (lp_benchmark_robot at intel.com) Date: Tue, 3 Oct 2017 17:08:09 -0700 Subject: [Python-checkins] [2 up, 63 flat] Results for Python (master branch) 2017-10-02 Message-ID: Results for project python/master, build date: 2017-10-02 17:32:36-07:00. - commit: efb560e - previous commit: 288d1da - revision date: 2017-10-02 08:53:55-07:00 - environment: Broadwell-EP - cpu: Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20GHz 2x22 cores, stepping 1, LLC 55 MB - mem: 128 GB - os: Ubuntu 16.04.2 LTS - kernel: 4.4.0-62-generic x86_64 GNU/Linux Baseline results were generated using release v3.6.0, with hash 5c4568a from 2016-12-22 23:38:47+00:00. +-----+------------------------+--------+------------+------------+------------+ | | |relative|change since|change since|current rev | | | benchmark|std_dev*| last run | baseline |run with PGO| +-----+------------------------+--------+------------+------------+------------+ | :-| | 2to3| 1.225% | -0.026% | +3.831% | +8.986% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method| 0.410% | -1.365% | +16.525% | +14.842% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_slots| 0.708% | -0.961% | +18.132% | +12.566% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_method_unknown| 0.456% | -0.932% | +16.753% | +13.597% | +-----+------------------------+--------+------------+------------+------------+ | :-| | call_simple| 2.509% | -0.695% | +2.884% | +16.273% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chameleon| 1.690% | -0.637% | +11.299% | +9.501% | +-----+------------------------+--------+------------+------------+------------+ | :-| | chaos| 1.616% | +0.041% | +7.921% | +9.972% | +-----+------------------------+--------+------------+------------+------------+ | :-| | crypto_pyaes| 0.500% | +1.025% | +3.584% | +4.890% | +-----+------------------------+--------+------------+------------+------------+ | :-| | deltablue| 3.116% | +1.264% | +6.947% | +18.367% | +-----+------------------------+--------+------------+------------+------------+ | :-| | django_template| 4.624% | -0.571% | +10.309% | +13.616% | +-----+------------------------+--------+------------+------------+------------+ | :-| | dulwich_log| 1.131% | -0.375% | +4.501% | +6.181% | +-----+------------------------+--------+------------+------------+------------+ | :-| | fannkuch| 0.282% | +0.051% | +7.385% | +3.032% | +-----+------------------------+--------+------------+------------+------------+ | :-| | float| 0.705% | -0.293% | +3.976% | +5.862% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_text| 1.134% | +1.276% | +8.742% | +10.467% | +-----+------------------------+--------+------------+------------+------------+ | :-| | genshi_xml| 1.435% | +0.202% | +7.668% | +8.004% | +-----+------------------------+--------+------------+------------+------------+ | :-| | go| 0.766% | -0.478% | +7.462% | +10.737% | +-----+------------------------+--------+------------+------------+------------+ | :-| | hexiom| 0.746% | +0.290% | +9.768% | +10.443% | +-----+------------------------+--------+------------+------------+------------+ | :-| | html5lib| 3.083% | +0.905% | +9.294% | +8.423% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_dumps| 1.594% | -0.577% | +4.828% | +8.253% | +-----+------------------------+--------+------------+------------+------------+ | :-| | json_loads| 0.710% | +1.051% | +2.840% | +9.515% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_format| 1.497% | -0.157% | +8.655% | +11.008% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_silent| 2.621% | -0.214% | +46.369% | +13.099% | +-----+------------------------+--------+------------+------------+------------+ | :-| | logging_simple| 1.469% | +1.272% | +9.887% | +11.792% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mako| 0.509% | -1.799% | +17.679% | +12.545% | +-----+------------------------+--------+------------+------------+------------+ | :-| | mdp| 1.033% | +1.228% | +8.468% | +9.111% | +-----+------------------------+--------+------------+------------+------------+ | :-| | meteor_contest| 2.019% | +0.072% | +3.724% | +5.526% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nbody| 0.417% | +0.038% | -0.593% | -1.231% | +-----+------------------------+--------+------------+------------+------------+ | :-| | nqueens| 0.853% | +0.139% | +1.753% | +8.541% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pathlib| 1.403% | -0.286% | +6.390% | +9.188% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle| 4.744% | -1.518% | +0.377% | +19.832% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_dict| 0.224% | -0.259% | +3.457% | +18.982% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_list| 0.773% | +0.354% | +6.939% | +17.385% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pickle_pure_python| 4.979% | -0.134% | +11.929% | +9.408% | +-----+------------------------+--------+------------+------------+------------+ | :-| | pidigits| 0.250% | +0.034% | +0.482% | +9.823% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup| 0.129% | +1.025% | +11.001% | +4.553% | +-----+------------------------+--------+------------+------------+------------+ | :-| | python_startup_no_site| 0.090% | +0.866% | +2.282% | +4.575% | +-----+------------------------+--------+------------+------------+------------+ | :-| | raytrace| 1.579% | -0.253% | +10.221% | +12.435% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_compile| 4.828% | +1.197% | -8.361% | +11.271% | +-----+------------------------+--------+------------+------------+------------+ | :-) | regex_dna| 0.472% | +4.089% | +1.931% | +8.651% | +-----+------------------------+--------+------------+------------+------------+ | :-| | regex_effbot| 2.682% | +4.328% | +0.338% | +3.634% | +-----+------------------------+--------+------------+------------+------------+ | :-) | regex_v8| 1.106% | +4.640% | +11.607% | +2.718% | +-----+------------------------+--------+------------+------------+------------+ | :-| | richards| 1.027% | -0.148% | +7.231% | +15.071% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_fft| 1.715% | -0.410% | +1.822% | +0.012% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_lu| 1.722% | +0.182% | +27.044% | +7.198% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_monte_carlo| 2.806% | +1.051% | +5.812% | +5.600% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sor| 0.609% | +0.640% | +15.947% | +6.287% | +-----+------------------------+--------+------------+------------+------------+ | :-| | scimark_sparse_mat_mult| 2.963% | -0.557% | +3.691% | -3.038% | +-----+------------------------+--------+------------+------------+------------+ | :-| | spectral_norm| 0.987% | -0.628% | +5.906% | +2.374% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_declarative| 0.954% | -0.112% | +6.431% | +8.464% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlalchemy_imperative| 2.878% | +0.080% | +6.143% | +5.985% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sqlite_synth| 3.717% | -2.731% | +18.416% | +10.633% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_expand| 2.529% | +0.286% | +11.733% | +9.054% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_integrate| 1.479% | -0.010% | +10.512% | +6.477% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_str| 4.077% | +0.273% | +11.929% | +9.198% | +-----+------------------------+--------+------------+------------+------------+ | :-| | sympy_sum| 5.811% | -0.107% | +11.167% | +12.002% | +-----+------------------------+--------+------------+------------+------------+ | :-| | telco| 6.267% | +0.047% | +22.976% | +10.627% | +-----+------------------------+--------+------------+------------+------------+ | :-| | tornado_http| 1.541% | -0.219% | +6.349% | +6.742% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpack_sequence| 2.422% | -1.579% | +0.678% | -0.461% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle| 4.083% | +4.794% | +11.120% | +19.763% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_list| 0.484% | +2.204% | +0.383% | +16.651% | +-----+------------------------+--------+------------+------------+------------+ | :-| | unpickle_pure_python| 3.332% | -0.589% | +7.515% | +6.342% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_generate| 1.261% | -0.346% | +6.682% | +7.625% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_iterparse| 2.966% | -1.467% | -0.331% | +7.975% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_parse| 3.503% | +0.352% | -10.761% | +13.711% | +-----+------------------------+--------+------------+------------+------------+ | :-| | xml_etree_process| 1.485% | +0.256% | +7.174% | +8.329% | +-----+------------------------+--------+------------+------------+------------+ * Relative Standard Deviation (Standard Deviation/Average) If this is not displayed properly please visit our results page here: http://languagesperformance.intel.com/2-up-63-flat-results-for-python-master-branch-2017-10-02 Our lab does a nightly source pull and build of the Python project and measures performance changes against the previous stable version and the previous nightly measurement. This is provided as a service to the community so that quality issues with current hardware can be identified quickly. Intel technologies' features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. From webhook-mailer at python.org Tue Oct 3 22:56:22 2017 From: webhook-mailer at python.org (Ned Deily) Date: Wed, 04 Oct 2017 02:56:22 -0000 Subject: [Python-checkins] Remove retired and security branches from active docs (#3879) Message-ID: https://github.com/python/cpython/commit/e2d0dd2cf98cfa558435693b9f066edd7cf7d71a commit: e2d0dd2cf98cfa558435693b9f066edd7cf7d71a branch: master author: Ned Deily committer: GitHub date: 2017-10-03T22:56:19-04:00 summary: Remove retired and security branches from active docs (#3879) files: M Doc/tools/static/switchers.js M Doc/tools/templates/indexsidebar.html diff --git a/Doc/tools/static/switchers.js b/Doc/tools/static/switchers.js index bd31faca4c6..c2b342b919a 100644 --- a/Doc/tools/static/switchers.js +++ b/Doc/tools/static/switchers.js @@ -12,9 +12,6 @@ var all_versions = { '3.7': 'dev (3.7)', '3.6': '3.6', - '3.5': '3.5', - '3.4': '3.4', - '3.3': '3.3', '2.7': '2.7', }; diff --git a/Doc/tools/templates/indexsidebar.html b/Doc/tools/templates/indexsidebar.html index 72a4d7ae996..4d01842dc67 100644 --- a/Doc/tools/templates/indexsidebar.html +++ b/Doc/tools/templates/indexsidebar.html @@ -3,7 +3,6 @@

{% trans %}Docs for other versions{% endtrans %}

From webhook-mailer at python.org Tue Oct 3 23:03:55 2017 From: webhook-mailer at python.org (Ned Deily) Date: Wed, 04 Oct 2017 03:03:55 -0000 Subject: [Python-checkins] Remove retired and security branches from active docs (#3880) Message-ID: https://github.com/python/cpython/commit/598c4d1c10abc2cba73d16d9f7f2bc565d79d19a commit: 598c4d1c10abc2cba73d16d9f7f2bc565d79d19a branch: 3.6 author: Ned Deily committer: GitHub date: 2017-10-03T23:03:52-04:00 summary: Remove retired and security branches from active docs (#3880) files: M Doc/tools/static/switchers.js M Doc/tools/templates/indexsidebar.html diff --git a/Doc/tools/static/switchers.js b/Doc/tools/static/switchers.js index bd31faca4c6..c2b342b919a 100644 --- a/Doc/tools/static/switchers.js +++ b/Doc/tools/static/switchers.js @@ -12,9 +12,6 @@ var all_versions = { '3.7': 'dev (3.7)', '3.6': '3.6', - '3.5': '3.5', - '3.4': '3.4', - '3.3': '3.3', '2.7': '2.7', }; diff --git a/Doc/tools/templates/indexsidebar.html b/Doc/tools/templates/indexsidebar.html index 413c0a7699c..a3c4bc8e3a9 100644 --- a/Doc/tools/templates/indexsidebar.html +++ b/Doc/tools/templates/indexsidebar.html @@ -3,7 +3,6 @@

{% trans %}Docs for other versions{% endtrans %}

From webhook-mailer at python.org Tue Oct 3 23:06:17 2017 From: webhook-mailer at python.org (Ned Deily) Date: Wed, 04 Oct 2017 03:06:17 -0000 Subject: [Python-checkins] Remove retired and security branches from active docs (#3881) Message-ID: https://github.com/python/cpython/commit/8d614bebb67f89af5523127fa146c576ab3a8894 commit: 8d614bebb67f89af5523127fa146c576ab3a8894 branch: 2.7 author: Ned Deily committer: GitHub date: 2017-10-03T23:06:13-04:00 summary: Remove retired and security branches from active docs (#3881) files: M Doc/tools/static/switchers.js M Doc/tools/templates/indexsidebar.html diff --git a/Doc/tools/static/switchers.js b/Doc/tools/static/switchers.js index bd31faca4c6..c2b342b919a 100644 --- a/Doc/tools/static/switchers.js +++ b/Doc/tools/static/switchers.js @@ -12,9 +12,6 @@ var all_versions = { '3.7': 'dev (3.7)', '3.6': '3.6', - '3.5': '3.5', - '3.4': '3.4', - '3.3': '3.3', '2.7': '2.7', }; diff --git a/Doc/tools/templates/indexsidebar.html b/Doc/tools/templates/indexsidebar.html index 76071e85d79..847a2eddc2e 100644 --- a/Doc/tools/templates/indexsidebar.html +++ b/Doc/tools/templates/indexsidebar.html @@ -2,7 +2,6 @@

{% trans %}Download these documents{% endtrans %}

{% trans %}Docs for other versions{% endtrans %}