From 702670e7e3f6c5f5f02f7557c291ced4e3cb236d Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 17 Jul 2020 13:17:43 +0100 Subject: [PATCH 01/33] server: reproduce select() out of range error --- cheroot/test/test_server.py | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 2108e2bb9a..be6a8ecb29 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -236,3 +236,49 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): peercreds_text_resp = requests.get(unix_base_uri + PEERCRED_TEXTS_URI) peercreds_text_resp.raise_for_status() assert peercreds_text_resp.text == expected_textcreds + + +def test_high_number_of_file_descriptors(): + """Test the server does not crash with a high file-descriptor value. + + This test should cause a server crash, as the server will try to + select() a file-descriptor higher than 1024. + """ + increased_nofile_limit = 2048 + sockets = [] + try: + import resource + import socket + + # We have to increase the nofile limit above 1024 + # Otherwise we see a 'Too many files open' error, instead of + # an error due to the file descriptor number being too high + (soft_limit, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE) + resource.setrlimit( + resource.RLIMIT_NOFILE, + (increased_nofile_limit, increased_nofile_limit), + ) + + # Hold a bunch of open file descriptors, so the next ones the server + # opens are higher than 1024 + for i in range(1024): + new_socket = socket.socket() + sockets.append(new_socket) + + # Create our server + httpserver = HTTPServer( + bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT), gateway=Gateway, + ) + httpserver.prepare() + # This will trigger a crash if select() is used in the implementation + httpserver.tick() + + finally: + # Stop our server, and close our open resources + httpserver.stop() + for socket in sockets: + socket.close() + + # Reset the limit back to the soft limit + # (setting the hard_limit is an error) + resource.setrlimit(resource.RLIMIT_NOFILE, (soft_limit, soft_limit)) From 3e9ac1fb19c4afcf5574ad5188b02aa10487e193 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 17 Jul 2020 14:45:10 +0100 Subject: [PATCH 02/33] feedback: move imports, make finally robust --- cheroot/test/test_server.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index be6a8ecb29..59182f317d 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -6,6 +6,7 @@ __metaclass__ = type import os +import resource import socket import tempfile import threading @@ -244,40 +245,42 @@ def test_high_number_of_file_descriptors(): This test should cause a server crash, as the server will try to select() a file-descriptor higher than 1024. """ + # Get current resource limits to restore them later + (soft_limit, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE) increased_nofile_limit = 2048 - sockets = [] - try: - import resource - import socket + # Create our server + httpserver = HTTPServer( + bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT), gateway=Gateway, + ) + # Hoard a lot of file descriptors by opening and storing a lot of sockets + test_sockets = [] + + try: # We have to increase the nofile limit above 1024 # Otherwise we see a 'Too many files open' error, instead of # an error due to the file descriptor number being too high - (soft_limit, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE) resource.setrlimit( resource.RLIMIT_NOFILE, (increased_nofile_limit, increased_nofile_limit), ) - # Hold a bunch of open file descriptors, so the next ones the server + # Open a lot of file descriptors, so the next ones the server # opens are higher than 1024 for i in range(1024): - new_socket = socket.socket() - sockets.append(new_socket) + test_sockets.append(socket.socket()) - # Create our server - httpserver = HTTPServer( - bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT), gateway=Gateway, - ) httpserver.prepare() # This will trigger a crash if select() is used in the implementation httpserver.tick() finally: - # Stop our server, and close our open resources + # Close our open resources + for test_socket in test_sockets: + test_socket.close() + + # Stop our server httpserver.stop() - for socket in sockets: - socket.close() # Reset the limit back to the soft limit # (setting the hard_limit is an error) From 0edbd0facf333d2c1ef16ce0cfca22a62c2e1c66 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 17 Jul 2020 14:48:24 +0100 Subject: [PATCH 03/33] feedback: don't change hard_limit when adjusting nofile resource --- cheroot/test/test_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 59182f317d..a083e77e20 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -262,7 +262,7 @@ def test_high_number_of_file_descriptors(): # an error due to the file descriptor number being too high resource.setrlimit( resource.RLIMIT_NOFILE, - (increased_nofile_limit, increased_nofile_limit), + (increased_nofile_limit, hard_limit), ) # Open a lot of file descriptors, so the next ones the server @@ -284,4 +284,4 @@ def test_high_number_of_file_descriptors(): # Reset the limit back to the soft limit # (setting the hard_limit is an error) - resource.setrlimit(resource.RLIMIT_NOFILE, (soft_limit, soft_limit)) + resource.setrlimit(resource.RLIMIT_NOFILE, (soft_limit, hard_limit)) From bcae452bd920e8c08b6368d9a63c5dc24f541e26 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 17 Jul 2020 14:54:57 +0100 Subject: [PATCH 04/33] feedback: add assertions to enforce we reach a file-descriptor over 1024 --- cheroot/test/test_server.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index a083e77e20..dbbc9448a4 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -269,10 +269,13 @@ def test_high_number_of_file_descriptors(): # opens are higher than 1024 for i in range(1024): test_sockets.append(socket.socket()) + assert test_sockets[-1].fileno() >= 1024 httpserver.prepare() # This will trigger a crash if select() is used in the implementation httpserver.tick() + with socket.socket() as sock: + assert sock.fileno() >= 1024 finally: # Close our open resources From 53e8a5f0517c73adb0bd9948706564cc2d50ab88 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 17 Jul 2020 16:17:33 +0100 Subject: [PATCH 05/33] make test_high_number_of_file_descriptors py27 compatible --- cheroot/test/test_server.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index dbbc9448a4..8c19d59b68 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -274,8 +274,12 @@ def test_high_number_of_file_descriptors(): httpserver.prepare() # This will trigger a crash if select() is used in the implementation httpserver.tick() - with socket.socket() as sock: + + sock = socket.socket() + try: assert sock.fileno() >= 1024 + finally: + sock.close() finally: # Close our open resources From 0fad95066414ee40f002112d3b96cedb5a62e4f7 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 17 Jul 2020 16:22:34 +0100 Subject: [PATCH 06/33] connections: replace select with selectors/selectors2 --- cheroot/connections.py | 45 +++++++++++++++++++++++++++++------------- setup.cfg | 1 + 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/cheroot/connections.py b/cheroot/connections.py index 28bc973b61..55cce50e1d 100644 --- a/cheroot/connections.py +++ b/cheroot/connections.py @@ -5,7 +5,10 @@ import io import os -import select +try: + import selectors +except ImportError: + import selectors2 as selectors import socket import time @@ -62,6 +65,7 @@ def __init__(self, server): """ self.server = server self.connections = [] + self._selector = selectors.DefaultSelector() def put(self, conn): """Put idle connection into the ConnectionManager to be managed. @@ -133,10 +137,9 @@ def get_conn(self, server_socket): ss_fileno = server_socket.fileno() socket_dict[ss_fileno] = server_socket try: - rlist, _, _ = select.select(list(socket_dict), [], [], 0.1) - # No available socket. - if not rlist: - return None + for sock in socket_dict: + self._selector.register(sock, selectors.EVENT_READ) + key_events = self._selector.select(timeout=0.1) except OSError: # Mark any connection which no longer appears valid. for fno, conn in list(socket_dict.items()): @@ -155,15 +158,29 @@ def get_conn(self, server_socket): # Wait for the next tick to occur. return None - - try: - # See if we have a new connection coming in. - rlist.remove(ss_fileno) - except ValueError: - # No new connection, but reuse existing socket. - conn = socket_dict[rlist.pop()] - else: - conn = server_socket + finally: + for sock in socket_dict: + self._selector.unregister(sock) + + # See if we have a new connection coming in. + new_connection = False + rlist = [] + for key, event in key_events: + if key.fd == ss_fileno: + # If we have a new connection, reuse the server socket + new_connection = True + conn = server_socket + else: + # Make a list of all the other sockets ready to read + rlist.append(key.fd) + + if new_connection is False: + if len(rlist) == 0: + # If we didn't get any readable sockets, wait for the next tick + return None + else: + # No new connection, but reuse existing socket. + conn = socket_dict[rlist.pop()] # All remaining connections in rlist should be marked as ready. for fno in rlist: diff --git a/setup.cfg b/setup.cfg index 1c0b9425b8..93bf839bf6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -65,6 +65,7 @@ setup_requires = # These are required in actual runtime: install_requires = backports.functools_lru_cache; python_version < '3.3' + selectors2; python_version< '3.4' six>=1.11.0 more_itertools>=2.6 jaraco.functools From 919d5637626f695518980766acadac2ae13619db Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 17 Jul 2020 16:52:16 +0100 Subject: [PATCH 07/33] only run test_high_number_of_file_descriptors on unix --- cheroot/test/test_server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 8c19d59b68..d481b45080 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -239,6 +239,7 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): assert peercreds_text_resp.text == expected_textcreds +@unix_only_sock_test def test_high_number_of_file_descriptors(): """Test the server does not crash with a high file-descriptor value. From 7047f0b1ebc5320295d193a418c6f42e82d051a3 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 17 Jul 2020 17:10:35 +0100 Subject: [PATCH 08/33] really only run test_high_number_of_file_descriptors on unix --- cheroot/test/test_server.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index d481b45080..215be7db55 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -6,7 +6,6 @@ __metaclass__ = type import os -import resource import socket import tempfile import threading @@ -20,7 +19,7 @@ from six.moves import urllib from .._compat import bton, ntob -from .._compat import IS_LINUX, IS_MACOS, SYS_PLATFORM +from .._compat import IS_LINUX, IS_MACOS, IS_WINDOWS, SYS_PLATFORM from ..server import IS_UID_GID_RESOLVABLE, Gateway, HTTPServer from ..testing import ( ANY_INTERFACE_IPV4, @@ -239,13 +238,22 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): assert peercreds_text_resp.text == expected_textcreds -@unix_only_sock_test +@pytest.mark.skipif( + IS_WINDOWS, + reason=( + 'This regression test is for a Linux bug, and the resource module ' + 'is not available on Windows.' + ), +) def test_high_number_of_file_descriptors(): """Test the server does not crash with a high file-descriptor value. This test should cause a server crash, as the server will try to select() a file-descriptor higher than 1024. """ + # Imported here, as it is not available on Windows + import resource + # Get current resource limits to restore them later (soft_limit, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE) increased_nofile_limit = 2048 From 6ca52e06c907636396bdef6b80f92deef77543cc Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Fri, 17 Jul 2020 17:42:57 +0100 Subject: [PATCH 09/33] feedback: use closing contextmanager for socket --- cheroot/test/test_server.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 215be7db55..dce7b2b879 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type +from contextlib import closing import os import socket import tempfile @@ -284,11 +285,8 @@ def test_high_number_of_file_descriptors(): # This will trigger a crash if select() is used in the implementation httpserver.tick() - sock = socket.socket() - try: + with closing(socket.socket()) as sock: assert sock.fileno() >= 1024 - finally: - sock.close() finally: # Close our open resources From 85b800d55b56cbfe19e54f52c009222fe2d79e4b Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 15:05:40 +0100 Subject: [PATCH 10/33] Update cheroot/test/test_server.py Co-authored-by: Sviatoslav Sydorenko --- cheroot/test/test_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index dce7b2b879..92ff91f9bc 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -285,7 +285,7 @@ def test_high_number_of_file_descriptors(): # This will trigger a crash if select() is used in the implementation httpserver.tick() - with closing(socket.socket()) as sock: + with closing(socket.socket()) as sock: # closing is here for py2-compat assert sock.fileno() >= 1024 finally: From e69b2606b7d642273cfd932f3e260a8d45deb6c8 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 15:06:00 +0100 Subject: [PATCH 11/33] Update cheroot/connections.py Co-authored-by: Sviatoslav Sydorenko --- cheroot/connections.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheroot/connections.py b/cheroot/connections.py index 55cce50e1d..d755f574d0 100644 --- a/cheroot/connections.py +++ b/cheroot/connections.py @@ -174,7 +174,7 @@ def get_conn(self, server_socket): # Make a list of all the other sockets ready to read rlist.append(key.fd) - if new_connection is False: + if not new_connection: if len(rlist) == 0: # If we didn't get any readable sockets, wait for the next tick return None From d273ae968635ba9cdd699aaabe6ee09cc6a785f1 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 15:06:11 +0100 Subject: [PATCH 12/33] Update cheroot/connections.py Co-authored-by: Sviatoslav Sydorenko --- cheroot/connections.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cheroot/connections.py b/cheroot/connections.py index d755f574d0..3e3d10d773 100644 --- a/cheroot/connections.py +++ b/cheroot/connections.py @@ -178,9 +178,9 @@ def get_conn(self, server_socket): if len(rlist) == 0: # If we didn't get any readable sockets, wait for the next tick return None - else: - # No new connection, but reuse existing socket. - conn = socket_dict[rlist.pop()] + + # No new connection, but reuse the existing socket. + conn = socket_dict[rlist.pop()] # All remaining connections in rlist should be marked as ready. for fno in rlist: From b66420398247d8c25308ecb66fc52b023ee6de9f Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 15:06:32 +0100 Subject: [PATCH 13/33] Update cheroot/test/test_server.py Co-authored-by: Sviatoslav Sydorenko --- cheroot/test/test_server.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 92ff91f9bc..83994e0022 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -246,7 +246,8 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): 'is not available on Windows.' ), ) -def test_high_number_of_file_descriptors(): +@pytest.mark.forked +def test_high_number_of_file_descriptors(http_server): """Test the server does not crash with a high file-descriptor value. This test should cause a server crash, as the server will try to From c4aec4fbb709df9256e2d899b57ef47ca79f5d1f Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 15:06:42 +0100 Subject: [PATCH 14/33] Update cheroot/test/test_server.py Co-authored-by: Sviatoslav Sydorenko --- cheroot/test/test_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 83994e0022..e43b1b7a19 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -243,7 +243,7 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): IS_WINDOWS, reason=( 'This regression test is for a Linux bug, and the resource module ' - 'is not available on Windows.' + 'is not available on Windows' ), ) @pytest.mark.forked From 153e6660539ec0ccc626a566fbfae03ea80dabe5 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 15:07:10 +0100 Subject: [PATCH 15/33] Update cheroot/test/test_server.py Co-authored-by: Sviatoslav Sydorenko --- cheroot/test/test_server.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index e43b1b7a19..25ef849e23 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -261,9 +261,7 @@ def test_high_number_of_file_descriptors(http_server): increased_nofile_limit = 2048 # Create our server - httpserver = HTTPServer( - bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT), gateway=Gateway, - ) + httpserver = http_server.send((ANY_INTERFACE_IPV4, EPHEMERAL_PORT)) # Hoard a lot of file descriptors by opening and storing a lot of sockets test_sockets = [] From 513ed2612b76ced39b3cd979ef9fd0c75f51e340 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 17:38:40 +0100 Subject: [PATCH 16/33] Update cheroot/test/test_server.py Co-authored-by: Sviatoslav Sydorenko --- cheroot/test/test_server.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 25ef849e23..55bf6b1230 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -253,8 +253,10 @@ def test_high_number_of_file_descriptors(http_server): This test should cause a server crash, as the server will try to select() a file-descriptor higher than 1024. """ - # Imported here, as it is not available on Windows - import resource + resource = pytest.importorskip( + 'resource', + reason='The "resource" module is Unix-specific', + ) # Get current resource limits to restore them later (soft_limit, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE) From ff26fdfccc244596f766bae095511d7ce58cf7ab Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 17:40:13 +0100 Subject: [PATCH 17/33] Apply suggestions from code review Co-authored-by: Sviatoslav Sydorenko --- cheroot/connections.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/cheroot/connections.py b/cheroot/connections.py index 3e3d10d773..6cc2088544 100644 --- a/cheroot/connections.py +++ b/cheroot/connections.py @@ -139,7 +139,7 @@ def get_conn(self, server_socket): try: for sock in socket_dict: self._selector.register(sock, selectors.EVENT_READ) - key_events = self._selector.select(timeout=0.1) + key_events = [key.fd for key, _event self._selector.select(timeout=0.1)] except OSError: # Mark any connection which no longer appears valid. for fno, conn in list(socket_dict.items()): @@ -163,19 +163,20 @@ def get_conn(self, server_socket): self._selector.unregister(sock) # See if we have a new connection coming in. - new_connection = False - rlist = [] - for key, event in key_events: - if key.fd == ss_fileno: - # If we have a new connection, reuse the server socket + try: + key_events.pop(ss_fileno) + except KeyError: + new_connection = False + else: new_connection = True + # If we have a new connection, reuse the server socket conn = server_socket - else: - # Make a list of all the other sockets ready to read - rlist.append(key.fd) + + # Make a list of all the other sockets ready to read + rlist = list(key_events.keys()) if not new_connection: - if len(rlist) == 0: + if not rlist: # If we didn't get any readable sockets, wait for the next tick return None From ee7261b6f8d1a4cf1fbbde10f311b061626d6da9 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 17:47:37 +0100 Subject: [PATCH 18/33] move selectors import to compat --- cheroot/_compat.py | 6 ++++++ cheroot/connections.py | 5 +---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cheroot/_compat.py b/cheroot/_compat.py index 63df078119..bc89db8161 100644 --- a/cheroot/_compat.py +++ b/cheroot/_compat.py @@ -8,6 +8,12 @@ import six +# Not used in this file, imported elsewhere as 'from ._compat import selectors' +try: + import selectors +except ImportError: + import selectors2 as selectors # noqa: F401 + try: import ssl IS_ABOVE_OPENSSL10 = ssl.OPENSSL_VERSION_INFO >= (1, 1) diff --git a/cheroot/connections.py b/cheroot/connections.py index 6cc2088544..0425599491 100644 --- a/cheroot/connections.py +++ b/cheroot/connections.py @@ -5,14 +5,11 @@ import io import os -try: - import selectors -except ImportError: - import selectors2 as selectors import socket import time from . import errors +from ._compat import selectors from .makefile import MakeFile import six From 5fbbb9ef002aa6435db2af9784cacaf9811f35d7 Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Sun, 19 Jul 2020 18:55:58 +0100 Subject: [PATCH 19/33] integrate feedback with tests, make work again --- cheroot/connections.py | 36 ++++++++++++++++-------------------- cheroot/test/test_server.py | 37 ++++++++++++++++++++++++------------- setup.cfg | 1 + 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/cheroot/connections.py b/cheroot/connections.py index 0425599491..57438386e9 100644 --- a/cheroot/connections.py +++ b/cheroot/connections.py @@ -134,9 +134,12 @@ def get_conn(self, server_socket): ss_fileno = server_socket.fileno() socket_dict[ss_fileno] = server_socket try: - for sock in socket_dict: - self._selector.register(sock, selectors.EVENT_READ) - key_events = [key.fd for key, _event self._selector.select(timeout=0.1)] + for fno in socket_dict: + self._selector.register(fno, selectors.EVENT_READ) + rlist = [ + key.fd for key, _event + in self._selector.select(timeout=0.1) + ] except OSError: # Mark any connection which no longer appears valid. for fno, conn in list(socket_dict.items()): @@ -156,29 +159,22 @@ def get_conn(self, server_socket): # Wait for the next tick to occur. return None finally: - for sock in socket_dict: - self._selector.unregister(sock) + for fno in socket_dict: + self._selector.unregister(fno) - # See if we have a new connection coming in. try: - key_events.pop(ss_fileno) - except KeyError: - new_connection = False - else: - new_connection = True - # If we have a new connection, reuse the server socket - conn = server_socket - - # Make a list of all the other sockets ready to read - rlist = list(key_events.keys()) - - if not new_connection: + # See if we have a new connection coming in. + rlist.remove(ss_fileno) + except ValueError: + # If we didn't get any readable sockets, wait for the next tick if not rlist: - # If we didn't get any readable sockets, wait for the next tick return None - # No new connection, but reuse the existing socket. + # No new connection, but reuse an existing socket. conn = socket_dict[rlist.pop()] + else: + # If we have a new connection, reuse the server socket + conn = server_socket # All remaining connections in rlist should be marked as ready. for fno in rlist: diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 55bf6b1230..a2f855c9d4 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -258,12 +258,18 @@ def test_high_number_of_file_descriptors(http_server): reason='The "resource" module is Unix-specific', ) + # We want to force the server to use a file-descriptor with a number above + # this value + high_fd_no = 1024 + # Get current resource limits to restore them later (soft_limit, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE) - increased_nofile_limit = 2048 # Create our server - httpserver = http_server.send((ANY_INTERFACE_IPV4, EPHEMERAL_PORT)) + httpserver = HTTPServer( + bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT), gateway=Gateway, + ) + httpserver.prepare() # Hoard a lot of file descriptors by opening and storing a lot of sockets test_sockets = [] @@ -273,21 +279,27 @@ def test_high_number_of_file_descriptors(http_server): # an error due to the file descriptor number being too high resource.setrlimit( resource.RLIMIT_NOFILE, - (increased_nofile_limit, hard_limit), + (high_fd_no * 2, hard_limit), ) - # Open a lot of file descriptors, so the next ones the server - # opens are higher than 1024 - for i in range(1024): - test_sockets.append(socket.socket()) - assert test_sockets[-1].fileno() >= 1024 + # Open a lot of file descriptors, so the next one the server opens is + # a hight number + for i in range(high_fd_no): + sock = socket.socket() + test_sockets.append(sock) + # If we reach a high enough number, we don't need to open more + if sock.fileno() >= high_fd_no: + break + # Check we opened enough descriptors to reach a high number + assert test_sockets[-1].fileno() >= high_fd_no - httpserver.prepare() # This will trigger a crash if select() is used in the implementation httpserver.tick() - with closing(socket.socket()) as sock: # closing is here for py2-compat - assert sock.fileno() >= 1024 + # We use closing here for py2-compat + with closing(socket.socket()) as sock: + # Check new sockets created are still above our target number + assert sock.fileno() >= high_fd_no finally: # Close our open resources @@ -297,6 +309,5 @@ def test_high_number_of_file_descriptors(http_server): # Stop our server httpserver.stop() - # Reset the limit back to the soft limit - # (setting the hard_limit is an error) + # Reset the resource limit back to the original soft limit resource.setrlimit(resource.RLIMIT_NOFILE, (soft_limit, hard_limit)) diff --git a/setup.cfg b/setup.cfg index 93bf839bf6..7d89eb99f7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -86,6 +86,7 @@ docs = testing = pytest>=4.6.6 + pytest-forked>=1.2.0 pytest-mock>=1.11.0 pytest-sugar>=0.9.3 pytest-testmon<1.0.0 From bdc33cbd8e76406d4f3ff238a61576bf576ad016 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 00:57:42 +0200 Subject: [PATCH 20/33] Use `http_server` fixture in `test_high_number_of_file_descriptors` --- cheroot/test/test_server.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index a2f855c9d4..af70abfcf0 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -266,9 +266,7 @@ def test_high_number_of_file_descriptors(http_server): (soft_limit, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE) # Create our server - httpserver = HTTPServer( - bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT), gateway=Gateway, - ) + httpserver = http_server.send((ANY_INTERFACE_IPV4, EPHEMERAL_PORT)) httpserver.prepare() # Hoard a lot of file descriptors by opening and storing a lot of sockets test_sockets = [] From aea6bf943a5a813a3c4a5ed3e1cb6670cdbffe32 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 00:58:50 +0200 Subject: [PATCH 21/33] Improve `test_high_number_of_file_descriptors` docstring --- cheroot/test/test_server.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index af70abfcf0..1bb816c815 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -250,8 +250,11 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): def test_high_number_of_file_descriptors(http_server): """Test the server does not crash with a high file-descriptor value. - This test should cause a server crash, as the server will try to - select() a file-descriptor higher than 1024. + This test shouldn't cause a server crash when trying to access + file-descriptor higher than 1024. + + The earlier implementation used to rely on `select()` syscall that + doesn't support file descriptors with numbers higher than 1024. """ resource = pytest.importorskip( 'resource', From 84f86162f76fd18f116822e56fd55fee38cd7bb6 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 00:59:18 +0200 Subject: [PATCH 22/33] Add LGTM ignore comments to `_compat` --- cheroot/_compat.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cheroot/_compat.py b/cheroot/_compat.py index bc89db8161..7f7a380a1a 100644 --- a/cheroot/_compat.py +++ b/cheroot/_compat.py @@ -8,11 +8,10 @@ import six -# Not used in this file, imported elsewhere as 'from ._compat import selectors' try: - import selectors + import selectors # lgtm [py/unused-import] except ImportError: - import selectors2 as selectors # noqa: F401 + import selectors2 as selectors # noqa: F401 # lgtm [py/unused-import] try: import ssl From 38a4ec37cc1bf0438dcedc11d9c5dd69d0c0a565 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 01:23:20 +0200 Subject: [PATCH 23/33] Revert "Use `http_server` fixture in `test_high_number_of_file_descriptors`" This reverts commit 7e0900c88f16fa4bab4baf85825ac3331cf911b9. --- cheroot/test/test_server.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 1bb816c815..ccba1f9996 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -247,7 +247,7 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): ), ) @pytest.mark.forked -def test_high_number_of_file_descriptors(http_server): +def test_high_number_of_file_descriptors(): """Test the server does not crash with a high file-descriptor value. This test shouldn't cause a server crash when trying to access @@ -269,7 +269,9 @@ def test_high_number_of_file_descriptors(http_server): (soft_limit, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE) # Create our server - httpserver = http_server.send((ANY_INTERFACE_IPV4, EPHEMERAL_PORT)) + httpserver = HTTPServer( + bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT), gateway=Gateway, + ) httpserver.prepare() # Hoard a lot of file descriptors by opening and storing a lot of sockets test_sockets = [] From ef5d44dd4fca140d2de01036e8a2eb251e2ed2df Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 02:04:14 +0200 Subject: [PATCH 24/33] Move high fd num test prerequisites to fixtures --- cheroot/test/test_server.py | 109 +++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 44 deletions(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index ccba1f9996..491bf7dc7c 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -241,13 +241,20 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): @pytest.mark.skipif( IS_WINDOWS, - reason=( - 'This regression test is for a Linux bug, and the resource module ' - 'is not available on Windows' - ), + reason='This regression test is for a Linux bug, ' + 'and the resource module is not available on Windows', ) @pytest.mark.forked -def test_high_number_of_file_descriptors(): +@pytest.mark.parametrize( + 'resource_limit', + ( + 1024, + 2048, + ), + indirect=('resource_limit', ), +) +@pytest.mark.usefixtures('many_open_sockets') +def test_high_number_of_file_descriptors(resource_limit): """Test the server does not crash with a high file-descriptor value. This test shouldn't cause a server crash when trying to access @@ -256,61 +263,75 @@ def test_high_number_of_file_descriptors(): The earlier implementation used to rely on `select()` syscall that doesn't support file descriptors with numbers higher than 1024. """ - resource = pytest.importorskip( - 'resource', - reason='The "resource" module is Unix-specific', - ) - - # We want to force the server to use a file-descriptor with a number above - # this value - high_fd_no = 1024 - - # Get current resource limits to restore them later - (soft_limit, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE) + # We want to force the server to use a file-descriptor with + # a number above resource_limit # Create our server httpserver = HTTPServer( bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT), gateway=Gateway, ) httpserver.prepare() - # Hoard a lot of file descriptors by opening and storing a lot of sockets - test_sockets = [] try: - # We have to increase the nofile limit above 1024 - # Otherwise we see a 'Too many files open' error, instead of - # an error due to the file descriptor number being too high - resource.setrlimit( - resource.RLIMIT_NOFILE, - (high_fd_no * 2, hard_limit), - ) - - # Open a lot of file descriptors, so the next one the server opens is - # a hight number - for i in range(high_fd_no): - sock = socket.socket() - test_sockets.append(sock) - # If we reach a high enough number, we don't need to open more - if sock.fileno() >= high_fd_no: - break - # Check we opened enough descriptors to reach a high number - assert test_sockets[-1].fileno() >= high_fd_no - # This will trigger a crash if select() is used in the implementation httpserver.tick() - + except: # noqa: E722 + raise # only needed for `else` to work + else: # We use closing here for py2-compat with closing(socket.socket()) as sock: # Check new sockets created are still above our target number - assert sock.fileno() >= high_fd_no - + assert sock.fileno() >= resource_limit finally: - # Close our open resources - for test_socket in test_sockets: - test_socket.close() - # Stop our server httpserver.stop() + +@pytest.fixture +def resource_limit(request): + """Set the resource limit two times bigger then requested.""" + resource = pytest.importorskip( + 'resource', + reason='The "resource" module is Unix-specific', + ) + + # Get current resource limits to restore them later + soft_limit, hard_limit = resource.getrlimit(resource.RLIMIT_NOFILE) + + # We have to increase the nofile limit above 1024 + # Otherwise we see a 'Too many files open' error, instead of + # an error due to the file descriptor number being too high + resource.setrlimit( + resource.RLIMIT_NOFILE, + (request.param * 2, hard_limit), + ) + + try: # noqa: WPS501 + yield request.param + finally: # Reset the resource limit back to the original soft limit resource.setrlimit(resource.RLIMIT_NOFILE, (soft_limit, hard_limit)) + + +@pytest.fixture +def many_open_sockets(resource_limit): + """Allocate a lot of file descriptors by opening dummy sockets.""" + # Hoard a lot of file descriptors by opening and storing a lot of sockets + test_sockets = [] + # Open a lot of file descriptors, so the next one the server + # opens is a high number + try: + for i in range(resource_limit): + sock = socket.socket() + test_sockets.append(sock) + # If we reach a high enough number, we don't need to open more + if sock.fileno() >= resource_limit: + break + # Check we opened enough descriptors to reach a high number + the_highest_fileno = test_sockets[-1].fileno() + assert the_highest_fileno >= resource_limit + yield the_highest_fileno + finally: + # Close our open resources + for test_socket in test_sockets: + test_socket.close() From 5617f5379a481b85dc633b04422ea462134e621d Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 02:15:30 +0200 Subject: [PATCH 25/33] Fix marking `select()` as code in docstring --- cheroot/test/test_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 491bf7dc7c..bc4b68ef8e 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -260,7 +260,7 @@ def test_high_number_of_file_descriptors(resource_limit): This test shouldn't cause a server crash when trying to access file-descriptor higher than 1024. - The earlier implementation used to rely on `select()` syscall that + The earlier implementation used to rely on ``select()`` syscall that doesn't support file descriptors with numbers higher than 1024. """ # We want to force the server to use a file-descriptor with From 24f5d13eb036bf0a7ffe6c079ac0693fa8b549f8 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 02:26:56 +0200 Subject: [PATCH 26/33] Add "syscall" to the list of known words --- docs/spelling_wordlist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index bfd2eb8713..9b872b9f3f 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -45,6 +45,7 @@ ssl stdout subclasses submodules +syscall systemd threadpool Tidelift From d0c56f25f1fe9b8facf57e129d4b3d72116ca658 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 17:04:38 +0200 Subject: [PATCH 27/33] Only install pytest-forked where it's supported --- setup.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 7d89eb99f7..cf2df16f9a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -86,7 +86,8 @@ docs = testing = pytest>=4.6.6 - pytest-forked>=1.2.0 + pytest-forked>=1.1.3; sys_platform != "win32" and python_version >= '3.0' and python_version <= '3.4' + pytest-forked>=1.2.0; sys_platform != "win32" and (python_version < '3.0' or python_version > '3.4') pytest-mock>=1.11.0 pytest-sugar>=0.9.3 pytest-testmon<1.0.0 From ba258dd752255563097d3a73f902009b1ce324dc Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 18:59:31 +0200 Subject: [PATCH 28/33] Apply updated add-trailing-comma edits --- cheroot/test/test_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index bc4b68ef8e..9ac6ae2050 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -251,7 +251,7 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): 1024, 2048, ), - indirect=('resource_limit', ), + indirect=('resource_limit',), ) @pytest.mark.usefixtures('many_open_sockets') def test_high_number_of_file_descriptors(resource_limit): From c8dea9bf5b7b727efb521332929c75586509ce71 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 20 Jul 2020 23:05:48 +0200 Subject: [PATCH 29/33] Conditionally decorate test with forked mark --- cheroot/test/test_server.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index 9ac6ae2050..7b0ef9137b 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -244,7 +244,6 @@ def test_peercreds_unix_sock_with_lookup(peercreds_enabled_server): reason='This regression test is for a Linux bug, ' 'and the resource module is not available on Windows', ) -@pytest.mark.forked @pytest.mark.parametrize( 'resource_limit', ( @@ -287,6 +286,12 @@ def test_high_number_of_file_descriptors(resource_limit): httpserver.stop() +if not IS_WINDOWS: + test_high_number_of_file_descriptors = pytest.mark.forked( + test_high_number_of_file_descriptors, + ) + + @pytest.fixture def resource_limit(request): """Set the resource limit two times bigger then requested.""" From 72252db0c4162d2186cc23940557b81bee78220d Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 21 Jul 2020 21:25:47 +0200 Subject: [PATCH 30/33] Bump setup-python GHA to v2.1.1 --- .github/workflows/python-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index b5e24fb418..858d9b8269 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -32,7 +32,7 @@ jobs: steps: - uses: actions/checkout@master - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v2.1.1 with: python-version: ${{ matrix.python-version }} - name: Pip cache From e996f20e29838ff1f95b597ee459d48c98ea2f22 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 21 Jul 2020 23:59:25 +0200 Subject: [PATCH 31/33] Add selectors34 fallback for py27 under 64-bit Win This change addresses a bug in selectors2 (that is resolved in master but is unreleased) with fd of the "long" type not being recognized as "int". Here's the traceback it causes: Traceback (most recent call last): File "C:\projects\cheroot\cheroot\server.py", line 1788, in serve self.tick() File "C:\projects\cheroot\cheroot\server.py", line 2023, in tick conn = self.connections.get_conn(self.socket) File "C:\projects\cheroot\cheroot\connections.py", line 163, in get_conn self._selector.unregister(fno) File "c:\projects\cheroot\.tox\python\lib\site-packages\selectors2.py", line 249, in unregister key = super(SelectSelector, self).unregister(fileobj) File "c:\projects\cheroot\.tox\python\lib\site-packages\selectors2.py", line 155, in unregister key = self._fd_to_key.pop(self._fileobj_lookup(fileobj)) File "c:\projects\cheroot\.tox\python\lib\site-packages\selectors2.py", line 127, in _fileobj_lookup return _fileobj_to_fd(fileobj) File "c:\projects\cheroot\.tox\python\lib\site-packages\selectors2.py", line 90, in _fileobj_to_fd raise ValueError("Invalid file object: {0!r}".format(fileobj)) ValueError: Invalid file object: 916L Refs: * https://github.com/sethmlarson/selectors2/pull/10 * https://twitter.com/webKnjaZ/status/1285695028136992769 * https://github.com/berkerpeksag/selectors34/blob/1.2.0/selectors34.py#L51 * https://github.com/cherrypy/cheroot/pull/301#issuecomment-662127125 --- cheroot/_compat.py | 6 +++++- setup.cfg | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cheroot/_compat.py b/cheroot/_compat.py index 7f7a380a1a..f879e5eee6 100644 --- a/cheroot/_compat.py +++ b/cheroot/_compat.py @@ -1,3 +1,4 @@ +# pylint: disable=unused-import """Compatibility code for using Cheroot with various versions of Python.""" from __future__ import absolute_import, division, print_function @@ -11,7 +12,10 @@ try: import selectors # lgtm [py/unused-import] except ImportError: - import selectors2 as selectors # noqa: F401 # lgtm [py/unused-import] + try: + import selectors2 as selectors # noqa: F401 # lgtm [py/unused-import] + except ImportError: + import selectors34 as selectors # noqa: F401 # lgtm [py/unused-import] try: import ssl diff --git a/setup.cfg b/setup.cfg index cf2df16f9a..e56717d9e1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -65,7 +65,8 @@ setup_requires = # These are required in actual runtime: install_requires = backports.functools_lru_cache; python_version < '3.3' - selectors2; python_version< '3.4' + selectors2; python_version < '3.4' and (sys_platform != "win32" or (sys_platform == "win32" and python_version >= '3.0')) + selectors34; python_version < '3.0' and sys_platform == "win32" six>=1.11.0 more_itertools>=2.6 jaraco.functools From dc2c17d00ae9f23bd3940ba6fcd98cb8ab4530de Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Wed, 22 Jul 2020 00:56:11 +0200 Subject: [PATCH 32/33] Revert "Add selectors34 fallback for py27 under 64-bit Win" This reverts commit e996f20e29838ff1f95b597ee459d48c98ea2f22. Thanks to @sethmlarson who published `selectors==2.0.2` on PyPI we no longer need a fallback to `selectors34`. Ref: https://twitter.com/sethmlarson/status/1285706586514751489 --- cheroot/_compat.py | 5 +---- setup.cfg | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cheroot/_compat.py b/cheroot/_compat.py index f879e5eee6..3ebbf2a81d 100644 --- a/cheroot/_compat.py +++ b/cheroot/_compat.py @@ -12,10 +12,7 @@ try: import selectors # lgtm [py/unused-import] except ImportError: - try: - import selectors2 as selectors # noqa: F401 # lgtm [py/unused-import] - except ImportError: - import selectors34 as selectors # noqa: F401 # lgtm [py/unused-import] + import selectors2 as selectors # noqa: F401 # lgtm [py/unused-import] try: import ssl diff --git a/setup.cfg b/setup.cfg index e56717d9e1..cf2df16f9a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -65,8 +65,7 @@ setup_requires = # These are required in actual runtime: install_requires = backports.functools_lru_cache; python_version < '3.3' - selectors2; python_version < '3.4' and (sys_platform != "win32" or (sys_platform == "win32" and python_version >= '3.0')) - selectors34; python_version < '3.0' and sys_platform == "win32" + selectors2; python_version< '3.4' six>=1.11.0 more_itertools>=2.6 jaraco.functools From f15243f7a146032617f2e2e476fda364bdb3b676 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Wed, 22 Jul 2020 01:16:32 +0200 Subject: [PATCH 33/33] Revert "Bump setup-python GHA to v2.1.1" This reverts commit 72252db0c4162d2186cc23940557b81bee78220d. --- .github/workflows/python-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 858d9b8269..b5e24fb418 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -32,7 +32,7 @@ jobs: steps: - uses: actions/checkout@master - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2.1.1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Pip cache