rdobuilder aa200f
From beb705719827843940ecebe48ef8b8ba65d2b91c Mon Sep 17 00:00:00 2001
rdobuilder aa200f
From: Tim Burke <tim.burke@gmail.com>
rdobuilder aa200f
Date: Wed, 9 Jun 2021 14:40:13 -0700
rdobuilder aa200f
Subject: [PATCH 1/6] Only wrap socket.timeout on Python < 3.10
rdobuilder aa200f
rdobuilder aa200f
On py310, socket.timeout is TimeoutError, which our is_timeout() helper
rdobuilder aa200f
func already knows is a timeout.
rdobuilder aa200f
rdobuilder aa200f
Note that this doesn't get us to py310 support (not by a long shot), but
rdobuilder aa200f
it's a step along the way.
rdobuilder aa200f
rdobuilder aa200f
Closes #687
rdobuilder aa200f
---
rdobuilder aa200f
 eventlet/greenio/base.py | 5 ++++-
rdobuilder aa200f
 1 file changed, 4 insertions(+), 1 deletion(-)
rdobuilder aa200f
rdobuilder aa200f
diff --git a/eventlet/greenio/base.py b/eventlet/greenio/base.py
rdobuilder aa200f
index 2eed86966..51a7ae13e 100644
rdobuilder aa200f
--- a/eventlet/greenio/base.py
rdobuilder aa200f
+++ b/eventlet/greenio/base.py
rdobuilder aa200f
@@ -29,7 +29,10 @@
rdobuilder aa200f
 _original_socket = eventlet.patcher.original('socket').socket
rdobuilder aa200f
 
rdobuilder aa200f
 
rdobuilder aa200f
-socket_timeout = eventlet.timeout.wrap_is_timeout(socket.timeout)
rdobuilder aa200f
+if sys.version_info >= (3, 10):
rdobuilder aa200f
+    socket_timeout = socket.timeout  # Really, TimeoutError
rdobuilder aa200f
+else:
rdobuilder aa200f
+    socket_timeout = eventlet.timeout.wrap_is_timeout(socket.timeout)
rdobuilder aa200f
 
rdobuilder aa200f
 
rdobuilder aa200f
 def socket_connect(descriptor, address):
rdobuilder aa200f
rdobuilder aa200f
From c22a27ace90a55d14e8c60ff37f9832e76266441 Mon Sep 17 00:00:00 2001
rdobuilder aa200f
From: Tim Burke <tim.burke@gmail.com>
rdobuilder aa200f
Date: Fri, 11 Jun 2021 12:56:07 -0700
rdobuilder aa200f
Subject: [PATCH 2/6] Get a working greenio._open on py310
rdobuilder aa200f
rdobuilder aa200f
_pyio.open is now a staticmethod, which means we can't get at the
rdobuilder aa200f
function code to wrap it up with a new environment.
rdobuilder aa200f
rdobuilder aa200f
Instead, create a new wrapper function which swaps out FileIO for
rdobuilder aa200f
GreenFileIO in the function's __globals__ before calling and replaces
rdobuilder aa200f
it in a finally.
rdobuilder aa200f
---
rdobuilder aa200f
 eventlet/greenio/py3.py | 30 +++++++++++++++++++++++-------
rdobuilder aa200f
 1 file changed, 23 insertions(+), 7 deletions(-)
rdobuilder aa200f
rdobuilder aa200f
diff --git a/eventlet/greenio/py3.py b/eventlet/greenio/py3.py
rdobuilder aa200f
index 7a75b52c0..c7f0aef50 100644
rdobuilder aa200f
--- a/eventlet/greenio/py3.py
rdobuilder aa200f
+++ b/eventlet/greenio/py3.py
rdobuilder aa200f
@@ -2,6 +2,7 @@
rdobuilder aa200f
 import errno
rdobuilder aa200f
 import os as _original_os
rdobuilder aa200f
 import socket as _original_socket
rdobuilder aa200f
+import sys
rdobuilder aa200f
 from io import (
rdobuilder aa200f
     BufferedRandom as _OriginalBufferedRandom,
rdobuilder aa200f
     BufferedReader as _OriginalBufferedReader,
rdobuilder aa200f
@@ -19,6 +20,7 @@
rdobuilder aa200f
     SOCKET_BLOCKING,
rdobuilder aa200f
 )
rdobuilder aa200f
 from eventlet.hubs import notify_close, notify_opened, IOClosed, trampoline
rdobuilder aa200f
+from eventlet.semaphore import Semaphore
rdobuilder aa200f
 from eventlet.support import get_errno
rdobuilder aa200f
 import six
rdobuilder aa200f
 
rdobuilder aa200f
@@ -182,21 +184,35 @@ def __exit__(self, *args):
rdobuilder aa200f
         self.close()
rdobuilder aa200f
 
rdobuilder aa200f
 
rdobuilder aa200f
-_open_environment = dict(globals())
rdobuilder aa200f
-_open_environment.update(dict(
rdobuilder aa200f
+_open_patching = dict(
rdobuilder aa200f
     BufferedRandom=_OriginalBufferedRandom,
rdobuilder aa200f
     BufferedWriter=_OriginalBufferedWriter,
rdobuilder aa200f
     BufferedReader=_OriginalBufferedReader,
rdobuilder aa200f
     TextIOWrapper=_OriginalTextIOWrapper,
rdobuilder aa200f
     FileIO=GreenFileIO,
rdobuilder aa200f
     os=_original_os,
rdobuilder aa200f
-))
rdobuilder aa200f
-
rdobuilder aa200f
-_open = FunctionType(
rdobuilder aa200f
-    six.get_function_code(_original_pyio.open),
rdobuilder aa200f
-    _open_environment,
rdobuilder aa200f
 )
rdobuilder aa200f
 
rdobuilder aa200f
+if sys.version_info < (3, 10):
rdobuilder aa200f
+    _open_environment = dict(globals())
rdobuilder aa200f
+    _open_environment.update(_open_patching)
rdobuilder aa200f
+    _open = FunctionType(
rdobuilder aa200f
+        six.get_function_code(_original_pyio.open),
rdobuilder aa200f
+        _open_environment,
rdobuilder aa200f
+    )
rdobuilder aa200f
+else:
rdobuilder aa200f
+    _open_lock = Semaphore()
rdobuilder aa200f
+    _open_originals = {k: _original_pyio.open.__func__.__globals__[k]
rdobuilder aa200f
+                       for k in _open_patching}
rdobuilder aa200f
+
rdobuilder aa200f
+    def _open(*a, **kw):
rdobuilder aa200f
+        with _open_lock:
rdobuilder aa200f
+            try:
rdobuilder aa200f
+                _original_pyio.open.__func__.__globals__.update(_open_patching)
rdobuilder aa200f
+                return _original_pyio.open(*a, **kw)
rdobuilder aa200f
+            finally:
rdobuilder aa200f
+                _original_pyio.open.__func__.__globals__.update(_open_originals)
rdobuilder aa200f
+
rdobuilder aa200f
 
rdobuilder aa200f
 def GreenPipe(name, mode="r", buffering=-1, encoding=None, errors=None,
rdobuilder aa200f
               newline=None, closefd=True, opener=None):
rdobuilder aa200f
rdobuilder aa200f
From ab4f8aaa704eb56b1e15730268fffbc8724c53ea Mon Sep 17 00:00:00 2001
rdobuilder aa200f
From: Tim Burke <tim.burke@gmail.com>
rdobuilder aa200f
Date: Fri, 11 Jun 2021 13:02:52 -0700
rdobuilder aa200f
Subject: [PATCH 3/6] Test using eventlet.is_timeout
rdobuilder aa200f
rdobuilder aa200f
...rather than requiring an is_timeout attribute on errors.
rdobuilder aa200f
rdobuilder aa200f
TimeoutErrors (which are covered by is_timeout) can't necessarily have
rdobuilder aa200f
attributes added to them.
rdobuilder aa200f
---
rdobuilder aa200f
 tests/__init__.py | 2 +-
rdobuilder aa200f
 1 file changed, 1 insertion(+), 1 deletion(-)
rdobuilder aa200f
rdobuilder aa200f
diff --git a/tests/__init__.py b/tests/__init__.py
rdobuilder aa200f
index c0b64fd9e..188366774 100644
rdobuilder aa200f
--- a/tests/__init__.py
rdobuilder aa200f
+++ b/tests/__init__.py
rdobuilder aa200f
@@ -383,7 +383,7 @@ def run_isolated(path, prefix='tests/isolated/', **kwargs):
rdobuilder aa200f
 
rdobuilder aa200f
 def check_is_timeout(obj):
rdobuilder aa200f
     value_text = getattr(obj, 'is_timeout', '(missing)')
rdobuilder aa200f
-    assert obj.is_timeout, 'type={0} str={1} .is_timeout={2}'.format(type(obj), str(obj), value_text)
rdobuilder aa200f
+    assert eventlet.is_timeout(obj), 'type={0} str={1} .is_timeout={2}'.format(type(obj), str(obj), value_text)
rdobuilder aa200f
 
rdobuilder aa200f
 
rdobuilder aa200f
 @contextlib.contextmanager
rdobuilder aa200f
rdobuilder aa200f
From ceef941b6b730add07eff4a3d4da5d203e255a71 Mon Sep 17 00:00:00 2001
rdobuilder aa200f
From: Tim Burke <tim.burke@gmail.com>
rdobuilder aa200f
Date: Fri, 11 Jun 2021 13:07:09 -0700
rdobuilder aa200f
Subject: [PATCH 4/6] Fix backdoor tests on py310
rdobuilder aa200f
rdobuilder aa200f
Python 3.10 started including build info on the version line, so the
rdobuilder aa200f
expectation in tests had to change. Also, start printing the banner as
rdobuilder aa200f
we read it to aid in future debugging.
rdobuilder aa200f
---
rdobuilder aa200f
 tests/backdoor_test.py | 17 +++++++++++++----
rdobuilder aa200f
 1 file changed, 13 insertions(+), 4 deletions(-)
rdobuilder aa200f
rdobuilder aa200f
diff --git a/tests/backdoor_test.py b/tests/backdoor_test.py
rdobuilder aa200f
index 03a569259..67a817947 100644
rdobuilder aa200f
--- a/tests/backdoor_test.py
rdobuilder aa200f
+++ b/tests/backdoor_test.py
rdobuilder aa200f
@@ -1,5 +1,6 @@
rdobuilder aa200f
 import os
rdobuilder aa200f
 import os.path
rdobuilder aa200f
+import sys
rdobuilder aa200f
 
rdobuilder aa200f
 import eventlet
rdobuilder aa200f
 
rdobuilder aa200f
@@ -21,10 +22,18 @@ def test_server(self):
rdobuilder aa200f
 
rdobuilder aa200f
     def _run_test_on_client_and_server(self, client, server_thread):
rdobuilder aa200f
         f = client.makefile('rw')
rdobuilder aa200f
-        assert 'Python' in f.readline()
rdobuilder aa200f
-        f.readline()  # build info
rdobuilder aa200f
-        f.readline()  # help info
rdobuilder aa200f
-        assert 'InteractiveConsole' in f.readline()
rdobuilder aa200f
+        line = f.readline()
rdobuilder aa200f
+        print(line.strip('\r\n'))
rdobuilder aa200f
+        assert 'Python' in line
rdobuilder aa200f
+        if sys.version_info < (3, 10):
rdobuilder aa200f
+            # Starting in py310, build info is included in version line
rdobuilder aa200f
+            line = f.readline()  # build info
rdobuilder aa200f
+            print(line.strip('\r\n'))
rdobuilder aa200f
+        line = f.readline()  # help info
rdobuilder aa200f
+        print(line.strip('\r\n'))
rdobuilder aa200f
+        line = f.readline()
rdobuilder aa200f
+        print(line.strip('\r\n'))
rdobuilder aa200f
+        assert 'InteractiveConsole' in line
rdobuilder aa200f
         self.assertEqual('>>> ', f.read(4))
rdobuilder aa200f
         f.write('print("hi")\n')
rdobuilder aa200f
         f.flush()
rdobuilder aa200f
rdobuilder aa200f
From aa6720a44cda816d1ac0a183ff94ebd51b6b1e53 Mon Sep 17 00:00:00 2001
rdobuilder aa200f
From: Tim Burke <tim.burke@gmail.com>
rdobuilder aa200f
Date: Fri, 11 Jun 2021 13:12:36 -0700
rdobuilder aa200f
Subject: [PATCH 5/6] Tolerate __builtins__ being a dict (rather than module)
rdobuilder aa200f
 in is_timeout
rdobuilder aa200f
rdobuilder aa200f
I'm still not sure how this happens, but somehow it does in
rdobuilder aa200f
socket_test.test_error_is_timeout. As a result, is_timeout wouldn't get
rdobuilder aa200f
a reference to TimeoutError, so the socket error would not be correctly
rdobuilder aa200f
identified as a timeout.
rdobuilder aa200f
---
rdobuilder aa200f
 eventlet/timeout.py | 5 ++++-
rdobuilder aa200f
 1 file changed, 4 insertions(+), 1 deletion(-)
rdobuilder aa200f
rdobuilder aa200f
diff --git a/eventlet/timeout.py b/eventlet/timeout.py
rdobuilder aa200f
index 6e1e08f63..969fdbcbd 100644
rdobuilder aa200f
--- a/eventlet/timeout.py
rdobuilder aa200f
+++ b/eventlet/timeout.py
rdobuilder aa200f
@@ -175,5 +175,8 @@ def fun(*args, **kwargs):
rdobuilder aa200f
 
rdobuilder aa200f
 
rdobuilder aa200f
 def is_timeout(obj):
rdobuilder aa200f
-    py3err = getattr(__builtins__, 'TimeoutError', Timeout)
rdobuilder aa200f
+    if isinstance(__builtins__, dict):  # seen when running tests on py310, but HOW??
rdobuilder aa200f
+        py3err = __builtins__.get('TimeoutError', Timeout)
rdobuilder aa200f
+    else:
rdobuilder aa200f
+        py3err = getattr(__builtins__, 'TimeoutError', Timeout)
rdobuilder aa200f
     return bool(getattr(obj, 'is_timeout', False)) or isinstance(obj, py3err)
rdobuilder aa200f
rdobuilder aa200f
From 900c8e195154efdae526ee7901469152141ab9d2 Mon Sep 17 00:00:00 2001
rdobuilder aa200f
From: Tim Burke <tim.burke@gmail.com>
rdobuilder aa200f
Date: Fri, 11 Jun 2021 13:33:00 -0700
rdobuilder aa200f
Subject: [PATCH 6/6] wsgi_test: Cap TLS version at 1.2
rdobuilder aa200f
rdobuilder aa200f
On py310, tests may attempt to use TLS 1.3 which apparently doesn't like
rdobuilder aa200f
the abrupt disconnect. Instead, it would complain:
rdobuilder aa200f
rdobuilder aa200f
    ssl.SSLEOFError: EOF occurred in violation of protocol
rdobuilder aa200f
---
rdobuilder aa200f
 tests/wsgi_test.py | 3 ++-
rdobuilder aa200f
 1 file changed, 2 insertions(+), 1 deletion(-)
rdobuilder aa200f
rdobuilder aa200f
diff --git a/tests/wsgi_test.py b/tests/wsgi_test.py
rdobuilder aa200f
index 1dd754bba..4173bcefa 100644
rdobuilder aa200f
--- a/tests/wsgi_test.py
rdobuilder aa200f
+++ b/tests/wsgi_test.py
rdobuilder aa200f
@@ -579,7 +579,8 @@ def wsgi_app(environ, start_response):
rdobuilder aa200f
         sock = eventlet.wrap_ssl(
rdobuilder aa200f
             eventlet.listen(('localhost', 0)),
rdobuilder aa200f
             certfile=certificate_file, keyfile=private_key_file,
rdobuilder aa200f
-            server_side=True)
rdobuilder aa200f
+            server_side=True,
rdobuilder aa200f
+            ssl_version=ssl.PROTOCOL_TLSv1_2)
rdobuilder aa200f
         server_coro = eventlet.spawn(server, sock, wsgi_app, self.logfile)
rdobuilder aa200f
 
rdobuilder aa200f
         client = eventlet.connect(('localhost', sock.getsockname()[1]))