From 30970e9e4436fca6320667e74b8667287b59e026 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 23 Oct 2011 20:07:13 +0100 Subject: [PATCH 01/17] Issue #10925: Add equivalent pure Python code for the builtin int-to-float conversion to test_long. --- Lib/test/test_long.py | 80 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index 04066ec1e79..05b3e3e03fc 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -43,6 +43,53 @@ DBL_MIN_EXP = sys.float_info.min_exp DBL_MANT_DIG = sys.float_info.mant_dig DBL_MIN_OVERFLOW = 2**DBL_MAX_EXP - 2**(DBL_MAX_EXP - DBL_MANT_DIG - 1) + +# Pure Python version of correctly-rounded integer-to-float conversion. +def int_to_float(n): + """ + Correctly-rounded integer-to-float conversion. + + """ + # Constants, depending only on the floating-point format in use. + # We use an extra 2 bits of precision for rounding purposes. + PRECISION = sys.float_info.mant_dig + 2 + SHIFT_MAX = sys.float_info.max_exp - PRECISION + Q_MAX = 1 << PRECISION + ROUND_HALF_TO_EVEN_CORRECTION = [0, -1, -2, 1, 0, -1, 2, 1] + + # Reduce to the case where n is positive. + if n == 0: + return 0.0 + elif n < 0: + return -int_to_float(-n) + + # Convert n to a 'floating-point' number q * 2**shift, where q is an + # integer with 'PRECISION' significant bits. When shifting n to create q, + # the least significant bit of q is treated as 'sticky'. That is, the + # least significant bit of q is set if either the corresponding bit of n + # was already set, or any one of the bits of n lost in the shift was set. + shift = n.bit_length() - PRECISION + q = n << -shift if shift < 0 else (n >> shift) | bool(n & ~(-1 << shift)) + + # Round half to even (actually rounds to the nearest multiple of 4, + # rounding ties to a multiple of 8). + q += ROUND_HALF_TO_EVEN_CORRECTION[q & 7] + + # Detect overflow. + if shift + (q == Q_MAX) > SHIFT_MAX: + raise OverflowError("integer too large to convert to float") + + # Checks: q is exactly representable, and q**2**shift doesn't overflow. + assert q % 4 == 0 and q // 4 <= 2**(sys.float_info.mant_dig) + assert q * 2**shift <= sys.float_info.max + + # Some circularity here, since float(q) is doing an int-to-float + # conversion. But here q is of bounded size, and is exactly representable + # as a float. In a low-level C-like language, this operation would be a + # simple cast (e.g., from unsigned long long to double). + return math.ldexp(float(q), shift) + + # pure Python version of correctly-rounded true division def truediv(a, b): """Correctly-rounded true division for integers.""" @@ -367,6 +414,23 @@ class LongTest(unittest.TestCase): return 1729 self.assertEqual(int(LongTrunc()), 1729) + def check_float_conversion(self, n): + # Check that int -> float conversion behaviour matches + # that of the pure Python version above. + try: + actual = float(n) + except OverflowError: + actual = 'overflow' + + try: + expected = int_to_float(n) + except OverflowError: + expected = 'overflow' + + msg = ("Error in conversion of integer {} to float. " + "Got {}, expected {}.".format(n, actual, expected)) + self.assertEqual(actual, expected, msg) + @support.requires_IEEE_754 def test_float_conversion(self): @@ -421,6 +485,22 @@ class LongTest(unittest.TestCase): y = 2**p * 2**53 self.assertEqual(int(float(x)), y) + # Compare builtin float conversion with pure Python int_to_float + # function above. + test_values = [ + int_dbl_max-1, int_dbl_max, int_dbl_max+1, + halfway-1, halfway, halfway + 1, + top_power-1, top_power, top_power+1, + 2*top_power-1, 2*top_power, top_power*top_power, + ] + test_values.extend(exact_values) + for p in range(-4, 8): + for x in range(-128, 128): + test_values.append(2**(p+53) + x) + for value in test_values: + self.check_float_conversion(value) + self.check_float_conversion(-value) + def test_float_overflow(self): for x in -2.0, -1.0, 0.0, 1.0, 2.0: self.assertEqual(float(int(x)), x) From 8d48b43ea9abe494527acea05dcd6b8d067278ea Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 23 Oct 2011 20:47:14 +0100 Subject: [PATCH 02/17] Issue #12965: Fix some inaccurate comments in Objects/longobject.c. Thanks Stefan Krah. --- Objects/longobject.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 43e5f0191c2..ab49f28f532 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -322,8 +322,15 @@ PyLong_FromDouble(double dval) #define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN) #define PY_ABS_SSIZE_T_MIN (0-(size_t)PY_SSIZE_T_MIN) -/* Get a C long int from a long int object. - Returns -1 and sets an error condition if overflow occurs. */ +/* Get a C long int from a long int object or any object that has an __int__ + method. + + On overflow, return -1 and set *overflow to 1 or -1 depending on the sign of + the result. Otherwise *overflow is 0. + + For other errors (e.g., TypeError), return -1 and set an error condition. + In this case *overflow will be 0. +*/ long PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) @@ -412,6 +419,9 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) return res; } +/* Get a C long int from a long int object or any object that has an __int__ + method. Return -1 and set an error if overflow occurs. */ + long PyLong_AsLong(PyObject *obj) { @@ -923,7 +933,7 @@ _PyLong_AsByteArray(PyLongObject* v, } -/* Create a new long (or int) object from a C pointer */ +/* Create a new long int object from a C pointer */ PyObject * PyLong_FromVoidPtr(void *p) @@ -941,15 +951,11 @@ PyLong_FromVoidPtr(void *p) } -/* Get a C pointer from a long object (or an int object in some cases) */ +/* Get a C pointer from a long int object. */ void * PyLong_AsVoidPtr(PyObject *vv) { - /* This function will allow int or long objects. If vv is neither, - then the PyLong_AsLong*() functions will raise the exception: - PyExc_SystemError, "bad argument to internal function" - */ #if SIZEOF_VOID_P <= SIZEOF_LONG long x; @@ -1130,8 +1136,8 @@ PyLong_FromSize_t(size_t ival) return (PyObject *)v; } -/* Get a C PY_LONG_LONG int from a long int object. - Return -1 and set an error if overflow occurs. */ +/* Get a C long long int from a long int object or any object that has an + __int__ method. Return -1 and set an error if overflow occurs. */ PY_LONG_LONG PyLong_AsLongLong(PyObject *vv) @@ -1287,12 +1293,14 @@ PyLong_AsUnsignedLongLongMask(register PyObject *op) } #undef IS_LITTLE_ENDIAN -/* Get a C long long int from a Python long or Python int object. - On overflow, returns -1 and sets *overflow to 1 or -1 depending - on the sign of the result. Otherwise *overflow is 0. +/* Get a C long long int from a long int object or any object that has an + __int__ method. - For other errors (e.g., type error), returns -1 and sets an error - condition. + On overflow, return -1 and set *overflow to 1 or -1 depending on the sign of + the result. Otherwise *overflow is 0. + + For other errors (e.g., TypeError), return -1 and set an error condition. + In this case *overflow will be 0. */ PY_LONG_LONG From 2bb96f593a067dafc7f02fef659ff22994b83399 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Sun, 23 Oct 2011 22:11:00 +0200 Subject: [PATCH 03/17] Cleanup code: remove int/long idioms and simplify a while statement. --- Lib/ftplib.py | 17 ++++------------- Lib/optparse.py | 5 +---- Lib/pickletools.py | 5 +---- Lib/xdrlib.py | 6 +----- Lib/xmlrpc/client.py | 12 +++--------- 5 files changed, 10 insertions(+), 35 deletions(-) diff --git a/Lib/ftplib.py b/Lib/ftplib.py index f87f6909c63..b470216be70 100644 --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -175,10 +175,8 @@ class FTP: # Internal: "sanitize" a string for printing def sanitize(self, s): - if s[:5] == 'pass ' or s[:5] == 'PASS ': - i = len(s) - while i > 5 and s[i-1] in {'\r', '\n'}: - i = i-1 + if s[:5] in {'pass ', 'PASS '}: + i = len(s.rstrip('\r\n')) s = s[:5] + '*'*(i-5) + s[i:] return repr(s) @@ -596,10 +594,7 @@ class FTP: resp = self.sendcmd('SIZE ' + filename) if resp[:3] == '213': s = resp[3:].strip() - try: - return int(s) - except (OverflowError, ValueError): - return int(s) + return int(s) def mkd(self, dirname): '''Make a directory, return its full pathname.''' @@ -861,11 +856,7 @@ def parse150(resp): m = _150_re.match(resp) if not m: return None - s = m.group(1) - try: - return int(s) - except (OverflowError, ValueError): - return int(s) + return int(m.group(1)) _227_re = None diff --git a/Lib/optparse.py b/Lib/optparse.py index b09a13cd344..946b6a58d37 100644 --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -417,11 +417,8 @@ def _parse_num(val, type): def _parse_int(val): return _parse_num(val, int) -def _parse_long(val): - return _parse_num(val, int) - _builtin_cvt = { "int" : (_parse_int, _("integer")), - "long" : (_parse_long, _("long integer")), + "long" : (_parse_int, _("integer")), "float" : (float, _("floating-point")), "complex" : (complex, _("complex")) } diff --git a/Lib/pickletools.py b/Lib/pickletools.py index 3061675c220..515d3759313 100644 --- a/Lib/pickletools.py +++ b/Lib/pickletools.py @@ -510,10 +510,7 @@ def read_decimalnl_short(f): elif s == b"01": return True - try: - return int(s) - except OverflowError: - return int(s) + return int(s) def read_decimalnl_long(f): r""" diff --git a/Lib/xdrlib.py b/Lib/xdrlib.py index 4e486770405..86e624f85da 100644 --- a/Lib/xdrlib.py +++ b/Lib/xdrlib.py @@ -141,11 +141,7 @@ class Unpacker: data = self.__buf[i:j] if len(data) < 4: raise EOFError - x = struct.unpack('>L', data)[0] - try: - return int(x) - except OverflowError: - return x + return struct.unpack('>L', data)[0] def unpack_int(self): i = self.__pos diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py index 19d4d6986fc..3cd000af723 100644 --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -535,15 +535,6 @@ class Marshaller: write("") dispatch[type(None)] = dump_nil - def dump_int(self, value, write): - # in case ints are > 32 bits - if value > MAXINT or value < MININT: - raise OverflowError("int exceeds XML-RPC limits") - write("") - write(str(value)) - write("\n") - #dispatch[int] = dump_int - def dump_bool(self, value, write): write("") write(value and "1" or "0") @@ -558,6 +549,9 @@ class Marshaller: write("\n") dispatch[int] = dump_long + # backward compatible + dump_int = dump_long + def dump_double(self, value, write): write("") write(repr(value)) From 6d57d212a89b38d31f6bca7b83cf789d8063f6f2 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Sun, 23 Oct 2011 22:23:57 +0200 Subject: [PATCH 04/17] Documentation typo. --- Doc/library/ftplib.rst | 2 +- Doc/whatsnew/3.3.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst index d13f2f0754e..3cc295a6062 100644 --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -427,7 +427,7 @@ FTP_TLS Objects .. method:: FTP_TLS.ccc() - Revert control channel back to plaintex. This can be useful to take + Revert control channel back to plaintext. This can be useful to take advantage of firewalls that know how to handle NAT with non-secure FTP without opening fixed ports. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 95a5583d34b..0427e81b743 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -267,7 +267,7 @@ ftplib The :class:`~ftplib.FTP_TLS` class now provides a new :func:`~ftplib.FTP_TLS.ccc` function to revert control channel back to -plaintex. This can be useful to take advantage of firewalls that know how to +plaintext. This can be useful to take advantage of firewalls that know how to handle NAT with non-secure FTP without opening fixed ports. (Contributed by Giampaolo Rodolà in :issue:`12139`) From 023611f34ead5bdfbeec73b1598df0023090106a Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Sun, 23 Oct 2011 22:40:37 +0200 Subject: [PATCH 05/17] Issue 13141: Demonstrate recommended style for socketserver examples. --- Doc/library/socketserver.rst | 64 +++++++++++++++++++----------------- Misc/NEWS | 6 ++++ 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst index 1d151a7fe66..177c0b11c47 100644 --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -348,7 +348,7 @@ This is the server side:: def handle(self): # self.request is the TCP socket connected to the client self.data = self.request.recv(1024).strip() - print("%s wrote:" % self.client_address[0]) + print("{} wrote:".format(self.client_address[0])) print(self.data) # just send back the same data, but upper-cased self.request.send(self.data.upper()) @@ -372,7 +372,7 @@ objects that simplify communication by providing the standard file interface):: # self.rfile is a file-like object created by the handler; # we can now use e.g. readline() instead of raw recv() calls self.data = self.rfile.readline().strip() - print("%s wrote:" % self.client_address[0]) + print("{} wrote:".format(self.client_address[0])) print(self.data) # Likewise, self.wfile is a file-like object used to write back # to the client @@ -395,16 +395,18 @@ This is the client side:: # Create a socket (SOCK_STREAM means a TCP socket) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - # Connect to server and send data - sock.connect((HOST, PORT)) - sock.send(bytes(data + "\n","utf8")) + try: + # Connect to server and send data + sock.connect((HOST, PORT)) + sock.send(bytes(data + "\n", "utf-8")) - # Receive data from the server and shut down - received = sock.recv(1024) - sock.close() + # Receive data from the server and shut down + received = str(sock.recv(1024), "utf-8") + finally: + sock.close() - print("Sent: %s" % data) - print("Received: %s" % received) + print("Sent: {}".format(data)) + print("Received: {}".format(received)) The output of the example should look something like this: @@ -421,10 +423,10 @@ Client:: $ python TCPClient.py hello world with TCP Sent: hello world with TCP - Received: b'HELLO WORLD WITH TCP' + Received: HELLO WORLD WITH TCP $ python TCPClient.py python is nice Sent: python is nice - Received: b'PYTHON IS NICE' + Received: PYTHON IS NICE :class:`socketserver.UDPServer` Example @@ -445,7 +447,7 @@ This is the server side:: def handle(self): data = self.request[0].strip() socket = self.request[1] - print("%s wrote:" % self.client_address[0]) + print("{} wrote:".format(self.client_address[0])) print(data) socket.sendto(data.upper(), self.client_address) @@ -467,11 +469,11 @@ This is the client side:: # As you can see, there is no connect() call; UDP has no connections. # Instead, data is directly sent to the recipient via sendto(). - sock.sendto(bytes(data + "\n","utf8"), (HOST, PORT)) - received = sock.recv(1024) + sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT)) + received = str(sock.recv(1024), "utf-8") - print("Sent: %s" % data) - print("Received: %s" % received) + print("Sent: {}".format(data)) + print("Received: {}".format(received)) The output of the example should look exactly like for the TCP server example. @@ -491,9 +493,9 @@ An example for the :class:`ThreadingMixIn` class:: class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): def handle(self): - data = self.request.recv(1024) + data = str(self.request.recv(1024), 'ascii') cur_thread = threading.current_thread() - response = bytes("%s: %s" % (cur_thread.getName(), data),'ascii') + response = bytes("{}: {}".format(cur_thread.name, data), 'ascii') self.request.send(response) class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): @@ -502,10 +504,12 @@ An example for the :class:`ThreadingMixIn` class:: def client(ip, port, message): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, port)) - sock.send(message) - response = sock.recv(1024) - print("Received: %s" % response) - sock.close() + try: + sock.send(bytes(message, 'ascii')) + response = str(sock.recv(1024), 'ascii') + print("Received: {}".format(response)) + finally: + sock.close() if __name__ == "__main__": # Port 0 means to select an arbitrary unused port @@ -518,13 +522,13 @@ An example for the :class:`ThreadingMixIn` class:: # more thread for each request server_thread = threading.Thread(target=server.serve_forever) # Exit the server thread when the main thread terminates - server_thread.setDaemon(True) + server_thread.daemon = True server_thread.start() print("Server loop running in thread:", server_thread.name) - client(ip, port, b"Hello World 1") - client(ip, port, b"Hello World 2") - client(ip, port, b"Hello World 3") + client(ip, port, "Hello World 1") + client(ip, port, "Hello World 2") + client(ip, port, "Hello World 3") server.shutdown() @@ -533,9 +537,9 @@ The output of the example should look something like this:: $ python ThreadedTCPServer.py Server loop running in thread: Thread-1 - Received: b"Thread-2: b'Hello World 1'" - Received: b"Thread-3: b'Hello World 2'" - Received: b"Thread-4: b'Hello World 3'" + Received: Thread-2: Hello World 1 + Received: Thread-3: Hello World 2 + Received: Thread-4: Hello World 3 The :class:`ForkingMixIn` class is used in the same way, except that the server diff --git a/Misc/NEWS b/Misc/NEWS index c078623d3b4..100fcecf8da 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -190,6 +190,12 @@ Extension Modules - Issue #12950: Fix passing file descriptors in multiprocessing, under OpenIndiana/Illumos. +Documentation +------------- + +- Issue #13141: Demonstrate recommended style for socketserver examples. + + What's New in Python 3.2.2? =========================== From 26358cc403801eed9db9934823bbef7b16108d89 Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Sun, 23 Oct 2011 23:42:51 +0300 Subject: [PATCH 06/17] Remove obsolete FAQ. --- Doc/faq/extending.rst | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/Doc/faq/extending.rst b/Doc/faq/extending.rst index fa8e6e77ed2..bbc322ada14 100644 --- a/Doc/faq/extending.rst +++ b/Doc/faq/extending.rst @@ -447,34 +447,3 @@ In Python 2.2, you can inherit from built-in classes such as :class:`int`, The Boost Python Library (BPL, http://www.boost.org/libs/python/doc/index.html) provides a way of doing this from C++ (i.e. you can inherit from an extension class written in C++ using the BPL). - - -When importing module X, why do I get "undefined symbol: PyUnicodeUCS2*"? -------------------------------------------------------------------------- - -You are using a version of Python that uses a 4-byte representation for Unicode -characters, but some C extension module you are importing was compiled using a -Python that uses a 2-byte representation for Unicode characters (the default). - -If instead the name of the undefined symbol starts with ``PyUnicodeUCS4``, the -problem is the reverse: Python was built using 2-byte Unicode characters, and -the extension module was compiled using a Python with 4-byte Unicode characters. - -This can easily occur when using pre-built extension packages. RedHat Linux -7.x, in particular, provided a "python2" binary that is compiled with 4-byte -Unicode. This only causes the link failure if the extension uses any of the -``PyUnicode_*()`` functions. It is also a problem if an extension uses any of -the Unicode-related format specifiers for :c:func:`Py_BuildValue` (or similar) or -parameter specifications for :c:func:`PyArg_ParseTuple`. - -You can check the size of the Unicode character a Python interpreter is using by -checking the value of sys.maxunicode: - - >>> import sys - >>> if sys.maxunicode > 65535: - ... print('UCS4 build') - ... else: - ... print('UCS2 build') - -The only way to solve this problem is to use extension modules compiled with a -Python binary built using the same size for Unicode characters. From dcbb822c08e75dbb45afe1c435af95961f22387a Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Sun, 23 Oct 2011 23:37:46 +0200 Subject: [PATCH 07/17] Fix documentation formatting. --- Doc/whatsnew/3.3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 0427e81b743..8ee5071d029 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -180,7 +180,7 @@ Some smaller changes made to the core Python language are: * Stub Added support for Unicode name aliases and named sequences. -Both :func:`unicodedata.lookup()` and '\N{...}' now resolve name aliases, +Both :func:`unicodedata.lookup()` and ``\N{...}`` now resolve name aliases, and :func:`unicodedata.lookup()` resolves named sequences too. (Contributed by Ezio Melotti in :issue:`12753`) From 2d99dac479fe89a2cbc616cc9c99b5d37c105d24 Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Mon, 24 Oct 2011 00:44:03 +0300 Subject: [PATCH 08/17] Use ``...`` for string literals. --- Doc/whatsnew/3.3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 8ee5071d029..78fae2f3677 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -180,7 +180,7 @@ Some smaller changes made to the core Python language are: * Stub Added support for Unicode name aliases and named sequences. -Both :func:`unicodedata.lookup()` and ``\N{...}`` now resolve name aliases, +Both :func:`unicodedata.lookup()` and ``'\N{...}'`` now resolve name aliases, and :func:`unicodedata.lookup()` resolves named sequences too. (Contributed by Ezio Melotti in :issue:`12753`) From 24d659daafd0e6c1514ee912f06f7b7310545e09 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 23 Oct 2011 23:49:42 +0200 Subject: [PATCH 09/17] Use InterruptedError instead of checking for EINTR --- Lib/_pyio.py | 17 ++++------------- Lib/asyncore.py | 13 ++++--------- Lib/multiprocessing/util.py | 9 +++------ Lib/socket.py | 8 +++----- Lib/subprocess.py | 6 ++---- Lib/test/test_socket.py | 2 +- 6 files changed, 17 insertions(+), 38 deletions(-) diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 0611bd6f820..3bd35d2e924 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -14,7 +14,6 @@ except ImportError: import io from io import (__all__, SEEK_SET, SEEK_CUR, SEEK_END) -from errno import EINTR # open() uses st_blksize whenever we can DEFAULT_BUFFER_SIZE = 8 * 1024 # bytes @@ -948,9 +947,7 @@ class BufferedReader(_BufferedIOMixin): # Read until EOF or until read() would block. try: chunk = self.raw.read() - except IOError as e: - if e.errno != EINTR: - raise + except InterruptedError: continue if chunk in empty_values: nodata_val = chunk @@ -972,9 +969,7 @@ class BufferedReader(_BufferedIOMixin): while avail < n: try: chunk = self.raw.read(wanted) - except IOError as e: - if e.errno != EINTR: - raise + except InterruptedError: continue if chunk in empty_values: nodata_val = chunk @@ -1007,9 +1002,7 @@ class BufferedReader(_BufferedIOMixin): while True: try: current = self.raw.read(to_read) - except IOError as e: - if e.errno != EINTR: - raise + except InterruptedError: continue break if current: @@ -1120,9 +1113,7 @@ class BufferedWriter(_BufferedIOMixin): while self._write_buf: try: n = self.raw.write(self._write_buf) - except IOError as e: - if e.errno != EINTR: - raise + except InterruptedError: continue if n > len(self._write_buf) or n < 0: raise IOError("write() returned incorrect number of bytes") diff --git a/Lib/asyncore.py b/Lib/asyncore.py index e6998157499..6d4bbbe309c 100644 --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -54,7 +54,7 @@ import warnings import os from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ - ENOTCONN, ESHUTDOWN, EINTR, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ + ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ errorcode _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, @@ -143,11 +143,8 @@ def poll(timeout=0.0, map=None): try: r, w, e = select.select(r, w, e, timeout) - except select.error as err: - if err.args[0] != EINTR: - raise - else: - return + except InterruptedError: + return for fd in r: obj = map.get(fd) @@ -190,9 +187,7 @@ def poll2(timeout=0.0, map=None): pollster.register(fd, flags) try: r = pollster.poll(timeout) - except select.error as err: - if err.args[0] != EINTR: - raise + except InterruptedError: r = [] for fd, flags in r: obj = map.get(fd) diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py index c48718026ba..5c26683bf34 100644 --- a/Lib/multiprocessing/util.py +++ b/Lib/multiprocessing/util.py @@ -327,15 +327,12 @@ class ForkAwareLocal(threading.local): # Automatic retry after EINTR # -def _eintr_retry(func, _errors=(EnvironmentError, select.error)): +def _eintr_retry(func): @functools.wraps(func) def wrapped(*args, **kwargs): while True: try: return func(*args, **kwargs) - except _errors as e: - # select.error has no `errno` attribute - if e.args[0] == errno.EINTR: - continue - raise + except InterruptedError: + continue return wrapped diff --git a/Lib/socket.py b/Lib/socket.py index 57150349a53..b2954b5a877 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -53,7 +53,6 @@ try: except ImportError: errno = None EBADF = getattr(errno, 'EBADF', 9) -EINTR = getattr(errno, 'EINTR', 4) EAGAIN = getattr(errno, 'EAGAIN', 11) EWOULDBLOCK = getattr(errno, 'EWOULDBLOCK', 11) @@ -280,11 +279,10 @@ class SocketIO(io.RawIOBase): except timeout: self._timeout_occurred = True raise + except InterruptedError: + continue except error as e: - n = e.args[0] - if n == EINTR: - continue - if n in _blocking_errnos: + if e.args[0] in _blocking_errnos: return None raise diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 2c5c888910c..a0aadb91a23 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -450,10 +450,8 @@ def _eintr_retry_call(func, *args): while True: try: return func(*args) - except (OSError, IOError) as e: - if e.errno == errno.EINTR: - continue - raise + except InterruptedError: + continue def call(*popenargs, timeout=None, **kwargs): diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 3d3dd0b65a3..d7a521c1cea 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3584,7 +3584,7 @@ class FileObjectInterruptedTestCase(unittest.TestCase): @staticmethod def _raise_eintr(): - raise socket.error(errno.EINTR) + raise socket.error(errno.EINTR, "interrupted") def _textiowrap_mock_socket(self, mock, buffering=-1): raw = socket.SocketIO(mock, "r") From 767c0a82adb240db69cba2dc2bd8bc0ada095c96 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 23 Oct 2011 23:52:23 +0200 Subject: [PATCH 10/17] Mention InterruptedError in the doc for new function signal.sigwaitinfo --- Doc/library/signal.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst index cbb9534d1e9..4fc3fd6405c 100644 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -353,8 +353,8 @@ The :mod:`signal` module defines the following functions: signals in *sigset* is already pending for the calling thread, the function will return immediately with information about that signal. The signal handler is not called for the delivered signal. The function raises an - :exc:`OSError` with error number set to :const:`errno.EINTR` if it is - interrupted by a signal that is not in *sigset*. + :exc:`InterruptedError` if it is interrupted by a signal that is not in + *sigset*. The return value is an object representing the data contained in the :c:type:`siginfo_t` structure, namely: :attr:`si_signo`, :attr:`si_code`, From 01fd26c7463483a9ce021606eb4e03096ecdfafd Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Mon, 24 Oct 2011 00:07:02 +0200 Subject: [PATCH 11/17] Improve description of PEP 3151 --- Doc/whatsnew/3.3.rst | 59 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 78fae2f3677..ce476084340 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -113,40 +113,44 @@ PEP 3151: Reworking the OS and IO exception hierarchy ===================================================== :pep:`3151` - Reworking the OS and IO exception hierarchy -PEP written and implemented by Antoine Pitrou. + PEP written and implemented by Antoine Pitrou. -New subclasses of :exc:`OSError` exceptions: +The hierarchy of exceptions raised by operating system errors is now both +simplified and finer-grained. - * :exc:`BlockingIOError` - * :exc:`ChildProcessError` - * :exc:`ConnectionError` +You don't have to worry anymore about choosing the appropriate exception +type between :exc:`OSError`, :exc:`IOError`, :exc:`EnvironmentError`, +:exc:`WindowsError`, :exc:`mmap.error`, :exc:`socket.error` or +:exc:`select.error`. All these exception types are now only one: +:exc:`OSError`. The other names are kept as aliases for compatibility +reasons. - * :exc:`BrokenPipeError` - * :exc:`ConnectionAbortedError` - * :exc:`ConnectionRefusedError` - * :exc:`ConnectionResetError` +Also, it is now easier to catch a specific error condition. Instead of +inspecting the ``errno`` attribute (or ``args[0]``) for a particular +constant from the :mod:`errno` module, you can catch the adequate +:exc:`OSError` subclass. The available subclasses are the following: - * :exc:`FileExistsError` - * :exc:`FileNotFoundError` - * :exc:`InterruptedError` - * :exc:`IsADirectoryError` - * :exc:`NotADirectoryError` - * :exc:`PermissionError` - * :exc:`ProcessLookupError` - * :exc:`TimeoutError` +* :exc:`BlockingIOError` +* :exc:`ChildProcessError` +* :exc:`ConnectionError` +* :exc:`FileExistsError` +* :exc:`FileNotFoundError` +* :exc:`InterruptedError` +* :exc:`IsADirectoryError` +* :exc:`NotADirectoryError` +* :exc:`PermissionError` +* :exc:`ProcessLookupError` +* :exc:`TimeoutError` -The following exceptions have been merged into :exc:`OSError`: +And the :exc:`ConnectionError` itself has finer-grained subclasses: - * :exc:`EnvironmentError` - * :exc:`IOError` - * :exc:`WindowsError` - * :exc:`VMSError` - * :exc:`socket.error` - * :exc:`select.error` - * :exc:`mmap.error` +* :exc:`BrokenPipeError` +* :exc:`ConnectionAbortedError` +* :exc:`ConnectionRefusedError` +* :exc:`ConnectionResetError` Thanks to the new exceptions, common usages of the :mod:`errno` can now be -avoided. For example, the following code written for Python 3.2: :: +avoided. For example, the following code written for Python 3.2:: from errno import ENOENT, EACCES, EPERM @@ -161,7 +165,8 @@ avoided. For example, the following code written for Python 3.2: :: else: raise -can now be written without the :mod:`errno` import: :: +can now be written without the :mod:`errno` import and without manual +inspection of exception attributes:: try: with open("document.txt") as f: From fd9b4166bb2adeaeed49782b1855e1acb41924a0 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Mon, 24 Oct 2011 00:14:43 +0200 Subject: [PATCH 12/17] Improve / clean up the PEP 393 description --- Doc/whatsnew/3.3.rst | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index ce476084340..fb1c7ce626b 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -52,25 +52,27 @@ This article explains the new features in Python 3.3, compared to 3.2. PEP 393: Flexible String Representation ======================================= -[Abstract copied from the PEP: The Unicode string type is changed to support -multiple internal representations, depending on the character with the largest -Unicode ordinal (1, 2, or 4 bytes). This allows a space-efficient -representation in common cases, but gives access to full UCS-4 on all systems. -For compatibility with existing APIs, several representations may exist in -parallel; over time, this compatibility should be phased out.] +The Unicode string type is changed to support multiple internal +representations, depending on the character with the largest Unicode ordinal +(1, 2, or 4 bytes) in the represented string. This allows a space-efficient +representation in common cases, but gives access to full UCS-4 on all +systems. For compatibility with existing APIs, several representations may +exist in parallel; over time, this compatibility should be phased out. -PEP 393 is fully backward compatible. The legacy API should remain -available at least five years. Applications using the legacy API will not -fully benefit of the memory reduction, or worse may use a little bit more -memory, because Python may have to maintain two versions of each string (in -the legacy format and in the new efficient storage). +On the Python side, there should be no downside to this change. -XXX Add list of changes introduced by :pep:`393` here: +On the C API side, PEP 393 is fully backward compatible. The legacy API +should remain available at least five years. Applications using the legacy +API will not fully benefit of the memory reduction, or - worse - may use +a bit more memory, because Python may have to maintain two versions of each +string (in the legacy format and in the new efficient storage). + +Changes introduced by :pep:`393` are the following: * Python now always supports the full range of Unicode codepoints, including non-BMP ones (i.e. from ``U+0000`` to ``U+10FFFF``). The distinction between narrow and wide builds no longer exists and Python now behaves like a wide - build. + build, even under Windows. * The storage of Unicode strings now depends on the highest codepoint in the string: @@ -86,7 +88,8 @@ XXX Add list of changes introduced by :pep:`393` here: XXX The result should be moved in the PEP and a small summary about performances and a link to the PEP should be added here. -* Some of the problems visible on narrow builds have been fixed, for example: +* With the death of narrow builds, the problems specific to narrow builds have + also been fixed, for example: * :func:`len` now always returns 1 for non-BMP characters, so ``len('\U0010FFFF') == 1``; @@ -94,10 +97,11 @@ XXX Add list of changes introduced by :pep:`393` here: * surrogate pairs are not recombined in string literals, so ``'\uDBFF\uDFFF' != '\U0010FFFF'``; - * indexing or slicing a non-BMP characters doesn't return surrogates anymore, + * indexing or slicing non-BMP characters returns the expected value, so ``'\U0010FFFF'[0]`` now returns ``'\U0010FFFF'`` and not ``'\uDBFF'``; - * several other functions in the stdlib now handle correctly non-BMP codepoints. + * several other functions in the standard library now handle correctly + non-BMP codepoints. * The value of :data:`sys.maxunicode` is now always ``1114111`` (``0x10FFFF`` in hexadecimal). The :c:func:`PyUnicode_GetMax` function still returns From 037ffbf1823cc90fbb8d8c92050aca46d7583fae Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Mon, 24 Oct 2011 00:25:41 +0200 Subject: [PATCH 13/17] Improve the porting section --- Doc/whatsnew/3.3.rst | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index fb1c7ce626b..6a378a96eb5 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -49,6 +49,8 @@ This article explains the new features in Python 3.3, compared to 3.2. +.. _pep-393: + PEP 393: Flexible String Representation ======================================= @@ -540,7 +542,10 @@ Porting to Python 3.3 ===================== This section lists previously described changes and other bugfixes -that may require changes to your code: +that may require changes to your code. + +Porting Python code +------------------- * Issue #12326: On Linux, sys.platform doesn't contain the major version anymore. It is now always 'linux', instead of 'linux2' or 'linux3' depending @@ -548,6 +553,24 @@ that may require changes to your code: with sys.platform.startswith('linux'), or directly sys.platform == 'linux' if you don't need to support older Python versions. +Porting C code +-------------- + +* Due to :ref:`PEP 393 `, the :c:type:`Py_UNICODE` type and all + functions using this type are deprecated (but will stay available for + at least five years). If you were using low-level Unicode APIs to + construct and access unicode objects and you want to benefit of the + memory footprint reduction provided by the PEP 393, you have to convert + your code to the new :doc:`Unicode API <../c-api/unicode>`. + + However, if you only have been using high-level functions such as + :c:func:`PyUnicode_Concat()`, :c:func:`PyUnicode_Join` or + :c:func:`PyUnicode_FromFormat()`, your code will automatically take + advantage of the new unicode representations. + +Other issues +------------ + .. Issue #11591: When :program:`python` was started with :option:`-S`, ``import site`` will not add site-specific paths to the module search paths. In previous versions, it did. See changeset for doc changes in @@ -557,8 +580,3 @@ that may require changes to your code: removed. Code checking sys.flags.division_warning will need updating. Contributed by Éric Araujo. -* :pep:`393`: The :c:type:`Py_UNICODE` type and all functions using this type - are deprecated. To fully benefit of the memory footprint reduction provided - by the PEP 393, you have to convert your code to the new Unicode API. Read - the porting guide: XXX. - From 39411f60a2d716a6e61f7a9b4c445b3d8492b9ef Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Mon, 24 Oct 2011 10:31:52 +0100 Subject: [PATCH 14/17] Issue #13248, issue #8540: Remove deprecated Context._clamp attribute from Decimal module. --- Lib/decimal.py | 22 ---------------------- Lib/test/test_decimal.py | 15 +++------------ Misc/NEWS | 2 ++ 3 files changed, 5 insertions(+), 34 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py index 8acb4ad8639..e9461824eb5 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -3903,28 +3903,6 @@ class Context(object): return nc __copy__ = copy - # _clamp is provided for backwards compatibility with third-party - # code. May be removed in Python >= 3.3. - def _get_clamp(self): - "_clamp mirrors the clamp attribute. Its use is deprecated." - import warnings - warnings.warn('Use of the _clamp attribute is deprecated. ' - 'Please use clamp instead.', - DeprecationWarning) - return self.clamp - - def _set_clamp(self, clamp): - "_clamp mirrors the clamp attribute. Its use is deprecated." - import warnings - warnings.warn('Use of the _clamp attribute is deprecated. ' - 'Please use clamp instead.', - DeprecationWarning) - self.clamp = clamp - - # don't bother with _del_clamp; no sane 3rd party code should - # be deleting the _clamp attribute - _clamp = property(_get_clamp, _set_clamp) - def _raise_error(self, condition, explanation = None, *args): """Handles an error diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 96bbafe7395..014e9c7b924 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -1834,18 +1834,9 @@ class ContextAPItests(unittest.TestCase): # only, the attribute should be gettable/settable via both # `clamp` and `_clamp`; in Python 3.3, `_clamp` should be # removed. - c = Context(clamp = 0) - self.assertEqual(c.clamp, 0) - - with check_warnings(("", DeprecationWarning)): - c._clamp = 1 - self.assertEqual(c.clamp, 1) - with check_warnings(("", DeprecationWarning)): - self.assertEqual(c._clamp, 1) - c.clamp = 0 - self.assertEqual(c.clamp, 0) - with check_warnings(("", DeprecationWarning)): - self.assertEqual(c._clamp, 0) + c = Context() + with self.assertRaises(AttributeError): + clamp_value = c._clamp def test_abs(self): c = Context() diff --git a/Misc/NEWS b/Misc/NEWS index be4a27c2d73..2ab804770a3 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -338,6 +338,8 @@ Core and Builtins Library ------- +- Issue #8540: Remove deprecated Context._clamp attribute in Decimal module. + - Issue #13235: Added PendingDeprecationWarning to warn() method and function. - Issue #9168: now smtpd is able to bind privileged port. From c45fb25fba9ef8a1d322099db86be98775d37bec Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Mon, 24 Oct 2011 13:14:55 +0200 Subject: [PATCH 15/17] Issue #13255: wrong docstrings in array module. --- Misc/NEWS | 2 ++ Modules/arraymodule.c | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 100fcecf8da..3909420e12e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,8 @@ Core and Builtins Library ------- +- Issue #13255: wrong docstrings in array module. + - Issue #9168: now smtpd is able to bind privileged port. - Issue #12529: fix cgi.parse_header issue on strings with double-quotes and diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index fe6106c9a41..31c4f391647 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -1484,7 +1484,7 @@ PyDoc_STRVAR(fromunicode_doc, \n\ Extends this array with data from the unicode string ustr.\n\ The array must be a unicode type array; otherwise a ValueError\n\ -is raised. Use array.frombytes(ustr.decode(...)) to\n\ +is raised. Use array.frombytes(ustr.encode(...)) to\n\ append Unicode data to an array of some other type."); @@ -1506,7 +1506,7 @@ PyDoc_STRVAR(tounicode_doc, \n\ Convert the array to a unicode string. The array must be\n\ a unicode type array; otherwise a ValueError is raised. Use\n\ -array.tostring().decode() to obtain a unicode string from\n\ +array.tobytes().decode() to obtain a unicode string from\n\ an array of some other type."); @@ -2557,7 +2557,7 @@ count() -- return number of occurrences of an object\n\ extend() -- extend array by appending multiple elements from an iterable\n\ fromfile() -- read items from a file object\n\ fromlist() -- append items from the list\n\ -fromstring() -- append items from the string\n\ +frombytes() -- append items from the string\n\ index() -- return index of first occurrence of an object\n\ insert() -- insert a new item into the array at a provided position\n\ pop() -- remove and return item (default last)\n\ @@ -2565,7 +2565,7 @@ remove() -- remove first occurrence of an object\n\ reverse() -- reverse the order of the items in the array\n\ tofile() -- write all items to a file object\n\ tolist() -- return the array converted to an ordinary list\n\ -tostring() -- return the array converted to a string\n\ +tobytes() -- return the array converted to a string\n\ \n\ Attributes:\n\ \n\ From d6ca6c2b32118fec10d28b1a23d97f8e6b536d04 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Mon, 24 Oct 2011 08:51:15 -0400 Subject: [PATCH 16/17] note callable is back in 3.2 --- Doc/library/2to3.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst index b3efeab21c9..fe1c2bedeec 100644 --- a/Doc/library/2to3.rst +++ b/Doc/library/2to3.rst @@ -123,7 +123,9 @@ and off individually. They are described here in more detail. .. 2to3fixer:: callable Converts ``callable(x)`` to ``isinstance(x, collections.Callable)``, adding - an import to :mod:`collections` if needed. + an import to :mod:`collections` if needed. Note ``callable(x)`` has returned + in Python 3.2, so if you do not intend to support Python 3.1, you can disable + this fixer. .. 2to3fixer:: dict From f8859e1808eff603b727d1adbeb38f745c9fedb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Fran=C3=A7ois=20Natali?= Date: Mon, 24 Oct 2011 18:45:29 +0200 Subject: [PATCH 17/17] Issue #10332: multiprocessing: fix a race condition when a Pool is closed before all tasks have completed. --- Lib/multiprocessing/pool.py | 6 +++++- Lib/test/test_multiprocessing.py | 14 ++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py index e450319d4f4..04e7c447d17 100644 --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -321,7 +321,11 @@ class Pool(object): @staticmethod def _handle_workers(pool): - while pool._worker_handler._state == RUN and pool._state == RUN: + thread = threading.current_thread() + + # Keep maintaining workers until the cache gets drained, unless the pool + # is terminated. + while thread._state == RUN or (pool._cache and thread._state != TERMINATE): pool._maintain_pool() time.sleep(0.1) # send sentinel to stop workers diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py index 6940d0e2f7e..45bf4549fee 100644 --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -1217,6 +1217,20 @@ class _TestPoolWorkerLifetime(BaseTestCase): p.close() p.join() + def test_pool_worker_lifetime_early_close(self): + # Issue #10332: closing a pool whose workers have limited lifetimes + # before all the tasks completed would make join() hang. + p = multiprocessing.Pool(3, maxtasksperchild=1) + results = [] + for i in range(6): + results.append(p.apply_async(sqr, (i, 0.3))) + p.close() + p.join() + # check the results + for (j, res) in enumerate(results): + self.assertEqual(res.get(), sqr(j)) + + # # Test that manager has expected number of shared objects left # diff --git a/Misc/NEWS b/Misc/NEWS index 3909420e12e..f7a741a32aa 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,9 @@ Core and Builtins Library ------- +- Issue #10332: multiprocessing: fix a race condition when a Pool is closed + before all tasks have completed. + - Issue #13255: wrong docstrings in array module. - Issue #9168: now smtpd is able to bind privileged port.