https://github.com/python/cpython/commit/82f24ff344056198ff283039c3e9fedac1…
commit: 82f24ff344056198ff283039c3e9fedac1d7fc2d
branch: 3.8
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: warsaw <barry(a)python.org>
date: 2020-12-31T12:27:04-08:00
summary:
Fixes a typo in importlib.metadata. (GH-23921) (#24030)
Signed-off-by: Tao He <sighingnow(a)gmail.com>
(cherry picked from commit 3631d6deab064de0bb286ef2943885dca3c3075e)
Co-authored-by: Tao He <sighingnow(a)gmail.com>
Co-authored-by: Tao He <sighingnow(a)gmail.com>
files:
M Doc/library/importlib.metadata.rst
diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst
index 15e58b860d97d..c8b4d4173de03 100644
--- a/Doc/library/importlib.metadata.rst
+++ b/Doc/library/importlib.metadata.rst
@@ -198,9 +198,9 @@ Thus, an alternative way to get the version number is through the
There are all kinds of additional metadata available on the ``Distribution``
instance::
- >>> d.metadata['Requires-Python'] # doctest: +SKIP
+ >>> dist.metadata['Requires-Python'] # doctest: +SKIP
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
- >>> d.metadata['License'] # doctest: +SKIP
+ >>> dist.metadata['License'] # doctest: +SKIP
'MIT'
The full set of available metadata is not described here. See :pep:`566`
https://github.com/python/cpython/commit/55fadffb0b37480b44ae515a82f87d8fa2…
commit: 55fadffb0b37480b44ae515a82f87d8fa298c173
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: warsaw <barry(a)python.org>
date: 2020-12-31T12:27:17-08:00
summary:
Fixes a typo in importlib.metadata. (GH-23921) (#24029)
Signed-off-by: Tao He <sighingnow(a)gmail.com>
(cherry picked from commit 3631d6deab064de0bb286ef2943885dca3c3075e)
Co-authored-by: Tao He <sighingnow(a)gmail.com>
Co-authored-by: Tao He <sighingnow(a)gmail.com>
files:
M Doc/library/importlib.metadata.rst
diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst
index 21da143f3bebf..0dd3daaa54892 100644
--- a/Doc/library/importlib.metadata.rst
+++ b/Doc/library/importlib.metadata.rst
@@ -206,9 +206,9 @@ Thus, an alternative way to get the version number is through the
There are all kinds of additional metadata available on the ``Distribution``
instance::
- >>> d.metadata['Requires-Python'] # doctest: +SKIP
+ >>> dist.metadata['Requires-Python'] # doctest: +SKIP
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
- >>> d.metadata['License'] # doctest: +SKIP
+ >>> dist.metadata['License'] # doctest: +SKIP
'MIT'
The full set of available metadata is not described here. See :pep:`566`
https://github.com/python/cpython/commit/b5711c940f70af89f2b4cf081a3fcd8392…
commit: b5711c940f70af89f2b4cf081a3fcd83924f3ae7
branch: master
author: Jason R. Coombs <jaraco(a)jaraco.com>
committer: pablogsal <Pablogsal(a)gmail.com>
date: 2020-12-31T20:19:30Z
summary:
bpo-37193: Remove thread objects which finished process its request (GH-23127)
This reverts commit aca67da4fe68d5420401ac1782203d302875eb27.
files:
A Misc/NEWS.d/next/Library/2020-06-12-21-23-20.bpo-37193.wJximU.rst
M Lib/socketserver.py
M Lib/test/test_socketserver.py
diff --git a/Lib/socketserver.py b/Lib/socketserver.py
index 57c1ae6e9e8be..0d9583d56a4d7 100644
--- a/Lib/socketserver.py
+++ b/Lib/socketserver.py
@@ -628,6 +628,39 @@ def server_close(self):
self.collect_children(blocking=self.block_on_close)
+class _Threads(list):
+ """
+ Joinable list of all non-daemon threads.
+ """
+ def append(self, thread):
+ self.reap()
+ if thread.daemon:
+ return
+ super().append(thread)
+
+ def pop_all(self):
+ self[:], result = [], self[:]
+ return result
+
+ def join(self):
+ for thread in self.pop_all():
+ thread.join()
+
+ def reap(self):
+ self[:] = (thread for thread in self if thread.is_alive())
+
+
+class _NoThreads:
+ """
+ Degenerate version of _Threads.
+ """
+ def append(self, thread):
+ pass
+
+ def join(self):
+ pass
+
+
class ThreadingMixIn:
"""Mix-in class to handle each request in a new thread."""
@@ -636,9 +669,9 @@ class ThreadingMixIn:
daemon_threads = False
# If true, server_close() waits until all non-daemonic threads terminate.
block_on_close = True
- # For non-daemonic threads, list of threading.Threading objects
+ # Threads object
# used by server_close() to wait for all threads completion.
- _threads = None
+ _threads = _NoThreads()
def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread.
@@ -655,23 +688,17 @@ def process_request_thread(self, request, client_address):
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
+ if self.block_on_close:
+ vars(self).setdefault('_threads', _Threads())
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
- if not t.daemon and self.block_on_close:
- if self._threads is None:
- self._threads = []
- self._threads.append(t)
+ self._threads.append(t)
t.start()
def server_close(self):
super().server_close()
- if self.block_on_close:
- threads = self._threads
- self._threads = None
- if threads:
- for thread in threads:
- thread.join()
+ self._threads.join()
if hasattr(os, "fork"):
diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py
index 7cdd115a95153..954e0331352fb 100644
--- a/Lib/test/test_socketserver.py
+++ b/Lib/test/test_socketserver.py
@@ -277,6 +277,13 @@ class MyHandler(socketserver.StreamRequestHandler):
t.join()
s.server_close()
+ def test_close_immediately(self):
+ class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
+ pass
+
+ server = MyServer((HOST, 0), lambda: None)
+ server.server_close()
+
def test_tcpserver_bind_leak(self):
# Issue #22435: the server socket wouldn't be closed if bind()/listen()
# failed.
@@ -491,6 +498,22 @@ def shutdown_request(self, request):
self.assertEqual(server.shutdown_called, 1)
server.server_close()
+ def test_threads_reaped(self):
+ """
+ In #37193, users reported a memory leak
+ due to the saving of every request thread. Ensure that
+ not all threads are kept forever.
+ """
+ class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
+ pass
+
+ server = MyServer((HOST, 0), socketserver.StreamRequestHandler)
+ for n in range(10):
+ with socket.create_connection(server.server_address):
+ server.handle_request()
+ self.assertLess(len(server._threads), 10)
+ server.server_close()
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2020-06-12-21-23-20.bpo-37193.wJximU.rst b/Misc/NEWS.d/next/Library/2020-06-12-21-23-20.bpo-37193.wJximU.rst
new file mode 100644
index 0000000000000..fbf56d3194cd2
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-06-12-21-23-20.bpo-37193.wJximU.rst
@@ -0,0 +1,2 @@
+Fixed memory leak in ``socketserver.ThreadingMixIn`` introduced in Python
+3.7.
https://github.com/python/cpython/commit/3631d6deab064de0bb286ef2943885dca3…
commit: 3631d6deab064de0bb286ef2943885dca3c3075e
branch: master
author: Tao He <sighingnow(a)gmail.com>
committer: warsaw <barry(a)python.org>
date: 2020-12-31T11:37:53-08:00
summary:
Fixes a typo in importlib.metadata. (#23921)
Signed-off-by: Tao He <sighingnow(a)gmail.com>
files:
M Doc/library/importlib.metadata.rst
diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst
index 858ed0a483874..7f154ea02cc4f 100644
--- a/Doc/library/importlib.metadata.rst
+++ b/Doc/library/importlib.metadata.rst
@@ -207,9 +207,9 @@ Thus, an alternative way to get the version number is through the
There are all kinds of additional metadata available on the ``Distribution``
instance::
- >>> d.metadata['Requires-Python'] # doctest: +SKIP
+ >>> dist.metadata['Requires-Python'] # doctest: +SKIP
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
- >>> d.metadata['License'] # doctest: +SKIP
+ >>> dist.metadata['License'] # doctest: +SKIP
'MIT'
The full set of available metadata is not described here. See :pep:`566`
https://github.com/python/cpython/commit/f4936ad1c4d0ae1948e428aeddc7d30962…
commit: f4936ad1c4d0ae1948e428aeddc7d3096252dae4
branch: master
author: Erlend Egeberg Aasland <erlend.aasland(a)innova.no>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2020-12-31T15:16:50+02:00
summary:
bpo-42393: Raise OverflowError iso. DeprecationWarning on overflow in socket.ntohs and socket.htons (GH-23980)
files:
A Misc/NEWS.d/next/Library/2020-11-17-22-06-15.bpo-42393.BB0oXc.rst
M Doc/library/socket.rst
M Doc/whatsnew/3.10.rst
M Lib/test/test_socket.py
M Modules/socketmodule.c
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
index 4511ff9ea4a51..2255b827aa8eb 100755
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -907,11 +907,9 @@ The :mod:`socket` module also offers various network-related services:
where the host byte order is the same as network byte order, this is a no-op;
otherwise, it performs a 2-byte swap operation.
- .. deprecated:: 3.7
- In case *x* does not fit in 16-bit unsigned integer, but does fit in a
- positive C int, it is silently truncated to 16-bit unsigned integer.
- This silent truncation feature is deprecated, and will raise an
- exception in future versions of Python.
+ .. versionchanged:: 3.10
+ Raises :exc:`OverflowError` if *x* does not fit in a 16-bit unsigned
+ integer.
.. function:: htonl(x)
@@ -927,11 +925,9 @@ The :mod:`socket` module also offers various network-related services:
where the host byte order is the same as network byte order, this is a no-op;
otherwise, it performs a 2-byte swap operation.
- .. deprecated:: 3.7
- In case *x* does not fit in 16-bit unsigned integer, but does fit in a
- positive C int, it is silently truncated to 16-bit unsigned integer.
- This silent truncation feature is deprecated, and will raise an
- exception in future versions of Python.
+ .. versionchanged:: 3.10
+ Raises :exc:`OverflowError` if *x* does not fit in a 16-bit unsigned
+ integer.
.. function:: inet_aton(ip_string)
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index db34b33b84a49..aa547ff46481b 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -537,6 +537,12 @@ Changes in the Python API
silently in Python 3.9.
(Contributed by Ken Jin in :issue:`42195`.)
+* :meth:`socket.htons` and :meth:`socket.ntohs` now raise :exc:`OverflowError`
+ instead of :exc:`DeprecationWarning` if the given parameter will not fit in
+ a 16-bit unsigned integer.
+ (Contributed by Erlend E. Aasland in :issue:`42393`.)
+
+
CPython bytecode changes
========================
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index e4af713b4c5bf..bc280306b15d1 100755
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1121,9 +1121,11 @@ def testNtoHErrors(self):
s_good_values = [0, 1, 2, 0xffff]
l_good_values = s_good_values + [0xffffffff]
l_bad_values = [-1, -2, 1<<32, 1<<1000]
- s_bad_values = l_bad_values + [_testcapi.INT_MIN - 1,
- _testcapi.INT_MAX + 1]
- s_deprecated_values = [1<<16, _testcapi.INT_MAX]
+ s_bad_values = (
+ l_bad_values +
+ [_testcapi.INT_MIN-1, _testcapi.INT_MAX+1] +
+ [1 << 16, _testcapi.INT_MAX]
+ )
for k in s_good_values:
socket.ntohs(k)
socket.htons(k)
@@ -1136,9 +1138,6 @@ def testNtoHErrors(self):
for k in l_bad_values:
self.assertRaises(OverflowError, socket.ntohl, k)
self.assertRaises(OverflowError, socket.htonl, k)
- for k in s_deprecated_values:
- self.assertWarns(DeprecationWarning, socket.ntohs, k)
- self.assertWarns(DeprecationWarning, socket.htons, k)
def testGetServBy(self):
eq = self.assertEqual
diff --git a/Misc/NEWS.d/next/Library/2020-11-17-22-06-15.bpo-42393.BB0oXc.rst b/Misc/NEWS.d/next/Library/2020-11-17-22-06-15.bpo-42393.BB0oXc.rst
new file mode 100644
index 0000000000000..f291123d6dea9
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-11-17-22-06-15.bpo-42393.BB0oXc.rst
@@ -0,0 +1,3 @@
+Raise :exc:`OverflowError` instead of silent truncation in :meth:`socket.ntohs`
+and :meth:`socket.htons`. Silent truncation was deprecated in Python 3.7.
+Patch by Erlend E. Aasland
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index bb33db0fa47b8..c686286d779dc 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -6102,13 +6102,10 @@ socket_ntohs(PyObject *self, PyObject *args)
return NULL;
}
if (x > 0xffff) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "ntohs: Python int too large to convert to C "
- "16-bit unsigned integer (The silent truncation "
- "is deprecated)",
- 1)) {
- return NULL;
- }
+ PyErr_SetString(PyExc_OverflowError,
+ "ntohs: Python int too large to convert to C "
+ "16-bit unsigned integer");
+ return NULL;
}
return PyLong_FromUnsignedLong(ntohs((unsigned short)x));
}
@@ -6116,12 +6113,7 @@ socket_ntohs(PyObject *self, PyObject *args)
PyDoc_STRVAR(ntohs_doc,
"ntohs(integer) -> integer\n\
\n\
-Convert a 16-bit unsigned integer from network to host byte order.\n\
-Note that in case the received integer does not fit in 16-bit unsigned\n\
-integer, but does fit in a positive C int, it is silently truncated to\n\
-16-bit unsigned integer.\n\
-However, this silent truncation feature is deprecated, and will raise an\n\
-exception in future versions of Python.");
+Convert a 16-bit unsigned integer from network to host byte order.");
static PyObject *
@@ -6173,13 +6165,10 @@ socket_htons(PyObject *self, PyObject *args)
return NULL;
}
if (x > 0xffff) {
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "htons: Python int too large to convert to C "
- "16-bit unsigned integer (The silent truncation "
- "is deprecated)",
- 1)) {
- return NULL;
- }
+ PyErr_SetString(PyExc_OverflowError,
+ "htons: Python int too large to convert to C "
+ "16-bit unsigned integer");
+ return NULL;
}
return PyLong_FromUnsignedLong(htons((unsigned short)x));
}
@@ -6187,12 +6176,7 @@ socket_htons(PyObject *self, PyObject *args)
PyDoc_STRVAR(htons_doc,
"htons(integer) -> integer\n\
\n\
-Convert a 16-bit unsigned integer from host to network byte order.\n\
-Note that in case the received integer does not fit in 16-bit unsigned\n\
-integer, but does fit in a positive C int, it is silently truncated to\n\
-16-bit unsigned integer.\n\
-However, this silent truncation feature is deprecated, and will raise an\n\
-exception in future versions of Python.");
+Convert a 16-bit unsigned integer from host to network byte order.");
static PyObject *
https://github.com/python/cpython/commit/bc15cdbc6eb112cb72acf189769ecd539d…
commit: bc15cdbc6eb112cb72acf189769ecd539dd45652
branch: 3.8
author: Andre Delfino <adelfino(a)gmail.com>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2020-12-31T15:10:46+02:00
summary:
[3.8] bpo-41224: Add versionadded for Symbol.is_annotated (GH-23861). (GH-24016)
(cherry picked from commit 2edfc86f69d8a74f4821974678f664ff94a9dc22)
files:
M Doc/library/symtable.rst
diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst
index 7c6ac4dccf8b7..56cb23db1d0c9 100644
--- a/Doc/library/symtable.rst
+++ b/Doc/library/symtable.rst
@@ -160,6 +160,12 @@ Examining Symbol Tables
Return ``True`` if the symbol is local to its block.
+ .. method:: is_annotated()
+
+ Return ``True`` if the symbol is annotated.
+
+ .. versionadded:: 3.6
+
.. method:: is_free()
Return ``True`` if the symbol is referenced in its block, but not assigned
https://github.com/python/cpython/commit/7a7f3e0d6a197c81fff83ad777c74324ce…
commit: 7a7f3e0d6a197c81fff83ad777c74324ceb4198f
branch: 3.9
author: Andre Delfino <adelfino(a)gmail.com>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2020-12-31T15:10:10+02:00
summary:
[3.9] bpo-41224: Add versionadded for Symbol.is_annotated (GH-23861). (GH-24017)
(cherry picked from commit 2edfc86f69d8a74f4821974678f664ff94a9dc22)
files:
M Doc/library/symtable.rst
diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst
index 3efdecb5af710..e364232247c20 100644
--- a/Doc/library/symtable.rst
+++ b/Doc/library/symtable.rst
@@ -156,6 +156,12 @@ Examining Symbol Tables
Return ``True`` if the symbol is local to its block.
+ .. method:: is_annotated()
+
+ Return ``True`` if the symbol is annotated.
+
+ .. versionadded:: 3.6
+
.. method:: is_free()
Return ``True`` if the symbol is referenced in its block, but not assigned
https://github.com/python/cpython/commit/9655434cca5dfbea97bf6d355aec028e84…
commit: 9655434cca5dfbea97bf6d355aec028e840b289c
branch: master
author: Brandon Stansbury <brandonrstansbury(a)gmail.com>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2020-12-31T11:44:46+02:00
summary:
bpo-39068: Fix race condition in base64 (GH-17627)
There was a race condition in base64 in lazy initialization of multiple globals.
files:
A Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst
M Lib/base64.py
M Misc/ACKS
diff --git a/Lib/base64.py b/Lib/base64.py
index 539ad16f0e86d..e1256ad9358e7 100755
--- a/Lib/base64.py
+++ b/Lib/base64.py
@@ -344,7 +344,7 @@ def a85encode(b, *, foldspaces=False, wrapcol=0, pad=False, adobe=False):
global _a85chars, _a85chars2
# Delay the initialization of tables to not waste memory
# if the function is never called
- if _a85chars is None:
+ if _a85chars2 is None:
_a85chars = [bytes((i,)) for i in range(33, 118)]
_a85chars2 = [(a + b) for a in _a85chars for b in _a85chars]
@@ -452,7 +452,7 @@ def b85encode(b, pad=False):
global _b85chars, _b85chars2
# Delay the initialization of tables to not waste memory
# if the function is never called
- if _b85chars is None:
+ if _b85chars2 is None:
_b85chars = [bytes((i,)) for i in _b85alphabet]
_b85chars2 = [(a + b) for a in _b85chars for b in _b85chars]
return _85encode(b, _b85chars, _b85chars2, pad)
diff --git a/Misc/ACKS b/Misc/ACKS
index 80e51f93e3aa9..211455b4dfc3c 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1659,6 +1659,7 @@ Quentin Stafford-Fraser
Frank Stajano
Joel Stanley
Kyle Stanley
+Brandon Stansbury
Anthony Starks
David Steele
Oliver Steele
diff --git a/Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst b/Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst
new file mode 100644
index 0000000000000..fe6503fdce6b6
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-12-16-17-55-31.bpo-39068.Ti3f9P.rst
@@ -0,0 +1,2 @@
+Fix initialization race condition in :func:`a85encode` and :func:`b85encode`
+in :mod:`base64`. Patch by Brandon Stansbury.