#7 Backport upstream patch to add compatibility of Eventlet with Python 3.10
Merged 2 years ago by churchyard. Opened 2 years ago by thrnciar.
rpms/ thrnciar/python-eventlet py310-fix  into  rawhide

@@ -0,0 +1,31 @@ 

+ From e88a14f86390b22ee55a810d0cd1b68c32c54423 Mon Sep 17 00:00:00 2001

+ From: Tomas Hrnciar <thrnciar@redhat.com>

+ Date: Wed, 16 Jun 2021 13:29:20 +0200

+ Subject: [PATCH] import MutableMapping from collections.abc

+ 

+ ---

+  dns/namedict.py | 4 ++--

+  1 file changed, 2 insertions(+), 2 deletions(-)

+ 

+ diff --git a/dnspython-1.16.0/dns/namedict.py b/dnspython-1.16.0/dns/namedict.py

+ index 37a1310..ae8d6a4 100644

+ --- a/dns/namedict.py

+ +++ b/dns/namedict.py

+ @@ -27,12 +27,12 @@

+  

+  """DNS name dictionary"""

+  

+ -import collections

+ +from collections.abc import MutableMapping

+  import dns.name

+  from ._compat import xrange

+  

+  

+ -class NameDict(collections.MutableMapping):

+ +class NameDict(MutableMapping):

+      """A dictionary whose keys are dns.name.Name objects.

+  

+      In addition to being like a regular Python dictionary, this

+ -- 

+ 2.31.1

+ 

file added
+242
@@ -0,0 +1,242 @@ 

+ From beb705719827843940ecebe48ef8b8ba65d2b91c Mon Sep 17 00:00:00 2001

+ From: Tim Burke <tim.burke@gmail.com>

+ Date: Wed, 9 Jun 2021 14:40:13 -0700

+ Subject: [PATCH 1/6] Only wrap socket.timeout on Python < 3.10

+ 

+ On py310, socket.timeout is TimeoutError, which our is_timeout() helper

+ func already knows is a timeout.

+ 

+ Note that this doesn't get us to py310 support (not by a long shot), but

+ it's a step along the way.

+ 

+ Closes #687

+ ---

+  eventlet/greenio/base.py | 5 ++++-

+  1 file changed, 4 insertions(+), 1 deletion(-)

+ 

+ diff --git a/eventlet/greenio/base.py b/eventlet/greenio/base.py

+ index 2eed86966..51a7ae13e 100644

+ --- a/eventlet/greenio/base.py

+ +++ b/eventlet/greenio/base.py

+ @@ -29,7 +29,10 @@

+  _original_socket = eventlet.patcher.original('socket').socket

+  

+  

+ -socket_timeout = eventlet.timeout.wrap_is_timeout(socket.timeout)

+ +if sys.version_info >= (3, 10):

+ +    socket_timeout = socket.timeout  # Really, TimeoutError

+ +else:

+ +    socket_timeout = eventlet.timeout.wrap_is_timeout(socket.timeout)

+  

+  

+  def socket_connect(descriptor, address):

+ 

+ From c22a27ace90a55d14e8c60ff37f9832e76266441 Mon Sep 17 00:00:00 2001

+ From: Tim Burke <tim.burke@gmail.com>

+ Date: Fri, 11 Jun 2021 12:56:07 -0700

+ Subject: [PATCH 2/6] Get a working greenio._open on py310

+ 

+ _pyio.open is now a staticmethod, which means we can't get at the

+ function code to wrap it up with a new environment.

+ 

+ Instead, create a new wrapper function which swaps out FileIO for

+ GreenFileIO in the function's __globals__ before calling and replaces

+ it in a finally.

+ ---

+  eventlet/greenio/py3.py | 30 +++++++++++++++++++++++-------

+  1 file changed, 23 insertions(+), 7 deletions(-)

+ 

+ diff --git a/eventlet/greenio/py3.py b/eventlet/greenio/py3.py

+ index 7a75b52c0..c7f0aef50 100644

+ --- a/eventlet/greenio/py3.py

+ +++ b/eventlet/greenio/py3.py

+ @@ -2,6 +2,7 @@

+  import errno

+  import os as _original_os

+  import socket as _original_socket

+ +import sys

+  from io import (

+      BufferedRandom as _OriginalBufferedRandom,

+      BufferedReader as _OriginalBufferedReader,

+ @@ -19,6 +20,7 @@

+      SOCKET_BLOCKING,

+  )

+  from eventlet.hubs import notify_close, notify_opened, IOClosed, trampoline

+ +from eventlet.semaphore import Semaphore

+  from eventlet.support import get_errno

+  import six

+  

+ @@ -182,21 +184,35 @@ def __exit__(self, *args):

+          self.close()

+  

+  

+ -_open_environment = dict(globals())

+ -_open_environment.update(dict(

+ +_open_patching = dict(

+      BufferedRandom=_OriginalBufferedRandom,

+      BufferedWriter=_OriginalBufferedWriter,

+      BufferedReader=_OriginalBufferedReader,

+      TextIOWrapper=_OriginalTextIOWrapper,

+      FileIO=GreenFileIO,

+      os=_original_os,

+ -))

+ -

+ -_open = FunctionType(

+ -    six.get_function_code(_original_pyio.open),

+ -    _open_environment,

+  )

+  

+ +if sys.version_info < (3, 10):

+ +    _open_environment = dict(globals())

+ +    _open_environment.update(_open_patching)

+ +    _open = FunctionType(

+ +        six.get_function_code(_original_pyio.open),

+ +        _open_environment,

+ +    )

+ +else:

+ +    _open_lock = Semaphore()

+ +    _open_originals = {k: _original_pyio.open.__func__.__globals__[k]

+ +                       for k in _open_patching}

+ +

+ +    def _open(*a, **kw):

+ +        with _open_lock:

+ +            try:

+ +                _original_pyio.open.__func__.__globals__.update(_open_patching)

+ +                return _original_pyio.open(*a, **kw)

+ +            finally:

+ +                _original_pyio.open.__func__.__globals__.update(_open_originals)

+ +

+  

+  def GreenPipe(name, mode="r", buffering=-1, encoding=None, errors=None,

+                newline=None, closefd=True, opener=None):

+ 

+ From ab4f8aaa704eb56b1e15730268fffbc8724c53ea Mon Sep 17 00:00:00 2001

+ From: Tim Burke <tim.burke@gmail.com>

+ Date: Fri, 11 Jun 2021 13:02:52 -0700

+ Subject: [PATCH 3/6] Test using eventlet.is_timeout

+ 

+ ...rather than requiring an is_timeout attribute on errors.

+ 

+ TimeoutErrors (which are covered by is_timeout) can't necessarily have

+ attributes added to them.

+ ---

+  tests/__init__.py | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/tests/__init__.py b/tests/__init__.py

+ index c0b64fd9e..188366774 100644

+ --- a/tests/__init__.py

+ +++ b/tests/__init__.py

+ @@ -383,7 +383,7 @@ def run_isolated(path, prefix='tests/isolated/', **kwargs):

+  

+  def check_is_timeout(obj):

+      value_text = getattr(obj, 'is_timeout', '(missing)')

+ -    assert obj.is_timeout, 'type={0} str={1} .is_timeout={2}'.format(type(obj), str(obj), value_text)

+ +    assert eventlet.is_timeout(obj), 'type={0} str={1} .is_timeout={2}'.format(type(obj), str(obj), value_text)

+  

+  

+  @contextlib.contextmanager

+ 

+ From ceef941b6b730add07eff4a3d4da5d203e255a71 Mon Sep 17 00:00:00 2001

+ From: Tim Burke <tim.burke@gmail.com>

+ Date: Fri, 11 Jun 2021 13:07:09 -0700

+ Subject: [PATCH 4/6] Fix backdoor tests on py310

+ 

+ Python 3.10 started including build info on the version line, so the

+ expectation in tests had to change. Also, start printing the banner as

+ we read it to aid in future debugging.

+ ---

+  tests/backdoor_test.py | 17 +++++++++++++----

+  1 file changed, 13 insertions(+), 4 deletions(-)

+ 

+ diff --git a/tests/backdoor_test.py b/tests/backdoor_test.py

+ index 03a569259..67a817947 100644

+ --- a/tests/backdoor_test.py

+ +++ b/tests/backdoor_test.py

+ @@ -1,5 +1,6 @@

+  import os

+  import os.path

+ +import sys

+  

+  import eventlet

+  

+ @@ -21,10 +22,18 @@ def test_server(self):

+  

+      def _run_test_on_client_and_server(self, client, server_thread):

+          f = client.makefile('rw')

+ -        assert 'Python' in f.readline()

+ -        f.readline()  # build info

+ -        f.readline()  # help info

+ -        assert 'InteractiveConsole' in f.readline()

+ +        line = f.readline()

+ +        print(line.strip('\r\n'))

+ +        assert 'Python' in line

+ +        if sys.version_info < (3, 10):

+ +            # Starting in py310, build info is included in version line

+ +            line = f.readline()  # build info

+ +            print(line.strip('\r\n'))

+ +        line = f.readline()  # help info

+ +        print(line.strip('\r\n'))

+ +        line = f.readline()

+ +        print(line.strip('\r\n'))

+ +        assert 'InteractiveConsole' in line

+          self.assertEqual('>>> ', f.read(4))

+          f.write('print("hi")\n')

+          f.flush()

+ 

+ From aa6720a44cda816d1ac0a183ff94ebd51b6b1e53 Mon Sep 17 00:00:00 2001

+ From: Tim Burke <tim.burke@gmail.com>

+ Date: Fri, 11 Jun 2021 13:12:36 -0700

+ Subject: [PATCH 5/6] Tolerate __builtins__ being a dict (rather than module)

+  in is_timeout

+ 

+ I'm still not sure how this happens, but somehow it does in

+ socket_test.test_error_is_timeout. As a result, is_timeout wouldn't get

+ a reference to TimeoutError, so the socket error would not be correctly

+ identified as a timeout.

+ ---

+  eventlet/timeout.py | 5 ++++-

+  1 file changed, 4 insertions(+), 1 deletion(-)

+ 

+ diff --git a/eventlet/timeout.py b/eventlet/timeout.py

+ index 6e1e08f63..969fdbcbd 100644

+ --- a/eventlet/timeout.py

+ +++ b/eventlet/timeout.py

+ @@ -175,5 +175,8 @@ def fun(*args, **kwargs):

+  

+  

+  def is_timeout(obj):

+ -    py3err = getattr(__builtins__, 'TimeoutError', Timeout)

+ +    if isinstance(__builtins__, dict):  # seen when running tests on py310, but HOW??

+ +        py3err = __builtins__.get('TimeoutError', Timeout)

+ +    else:

+ +        py3err = getattr(__builtins__, 'TimeoutError', Timeout)

+      return bool(getattr(obj, 'is_timeout', False)) or isinstance(obj, py3err)

+ 

+ From 900c8e195154efdae526ee7901469152141ab9d2 Mon Sep 17 00:00:00 2001

+ From: Tim Burke <tim.burke@gmail.com>

+ Date: Fri, 11 Jun 2021 13:33:00 -0700

+ Subject: [PATCH 6/6] wsgi_test: Cap TLS version at 1.2

+ 

+ On py310, tests may attempt to use TLS 1.3 which apparently doesn't like

+ the abrupt disconnect. Instead, it would complain:

+ 

+     ssl.SSLEOFError: EOF occurred in violation of protocol

+ ---

+  tests/wsgi_test.py | 3 ++-

+  1 file changed, 2 insertions(+), 1 deletion(-)

+ 

+ diff --git a/tests/wsgi_test.py b/tests/wsgi_test.py

+ index 1dd754bba..4173bcefa 100644

+ --- a/tests/wsgi_test.py

+ +++ b/tests/wsgi_test.py

+ @@ -579,7 +579,8 @@ def wsgi_app(environ, start_response):

+          sock = eventlet.wrap_ssl(

+              eventlet.listen(('localhost', 0)),

+              certfile=certificate_file, keyfile=private_key_file,

+ -            server_side=True)

+ +            server_side=True,

+ +            ssl_version=ssl.PROTOCOL_TLSv1_2)

+          server_coro = eventlet.spawn(server, sock, wsgi_app, self.logfile)

+  

+          client = eventlet.connect(('localhost', sock.getsockname()[1]))

file modified
+14 -1
@@ -4,7 +4,7 @@ 

  

  Name:           python-%{modname}

  Version:        0.31.0

- Release:        2%{?dist}

+ Release:        3%{?dist}

  Summary:        Highly concurrent networking library

  %if %bundle_dns

  License:        MIT and ISC
@@ -17,6 +17,13 @@ 

  Source1:        %{pypi_source dnspython 1.16.0 zip}

  Patch0:         switch_to_python_cryptography.patch

  

+ # Since Python 3.10 MutableMapping is available in collections.abc instead of collections.

+ # This is already fixed in dnspython 2.0.0+, but eventlet still uses old 1.16.0.

+ Patch1:         0001-import-MutableMapping-from-collections.abc.patch

+ # Backport of upstream PR to introduce compatibility with Python 3.10

+ # https://github.com/eventlet/eventlet/pull/715

+ Patch715:       https://github.com/eventlet/eventlet/pull/715.patch

+ 

  BuildArch:      noarch

  

  %description
@@ -68,6 +75,7 @@ 

  %else

  %setup -n %{modname}-%{version} -q

  %endif

+ %patch -P 715 -p1

  # Remove dependency on enum-compat from setup.py

  # enum-compat is not needed for Python 3

  sed -i "/'enum-compat',/d" setup.py
@@ -75,6 +83,7 @@ 

  # We bundle last version of dns1 as eventlet does not support yet dns2

  pushd dnspython-1.16.0

  %patch -P 0 -p1

+ %patch -P 1 -p1

  grep -lRZ "dns\." dns | xargs -0 -l sed -i -e 's/\([^[a-zA-Z]\)dns\./\1eventlet\.dns\./g'

  grep -lRZ "^import dns$" dns | xargs -0 -l sed -i -e 's/^import\ dns$/import\ eventlet\.dns/'

  popd
@@ -121,6 +130,10 @@ 

  %doc html-3

  

  %changelog

+ * Wed Jun 16 2021 Tomas Hrnciar <thrnciar@redhat.com> - 0.31.0-3

+ - Backport upstream patch to add compatibility of Eventlet with Python 3.10

+ - Fixes: rhbz#1913291

+ 

  * Fri Jun 04 2021 Python Maint <python-maint@redhat.com> - 0.31.0-2

  - Rebuilt for Python 3.10

  

no initial comment

I've suggested to @thrnciar to move this near the other dnspython patch that is applied earlier.

rebased onto efed009

2 years ago

I've suggested to @thrnciar to move this near the other dnspython patch that is applied earlier.

Done, PR was updated.

Thanks. Looking good. If there is no pushback, I'll merge and build later today as a provenpackager.

Pull-Request has been merged by churchyard

2 years ago