From 0a18325cb5ea2cee934c7376efad4ef672e92b18 Mon Sep 17 00:00:00 2001 From: Miro HronĨok Date: Jun 28 2023 18:22:13 +0000 Subject: Python 3.12 support --- diff --git a/python-eventlet.spec b/python-eventlet.spec index 8d44303..552e95c 100644 --- a/python-eventlet.spec +++ b/python-eventlet.spec @@ -21,6 +21,10 @@ License: MIT URL: https://eventlet.net Source: %pypi_source %{srcname} +# Python 3.12 support +# Upstream draft PR: https://github.com/eventlet/eventlet/pull/797 +Patch: python3.12.patch + BuildArch: noarch %description %{_description} @@ -45,7 +49,7 @@ BuildRequires: python3-zmq %{summary}. %prep -%setup -n %{srcname}-%{version} -q +%autosetup -p1 -n %{srcname}-%{version} %generate_buildrequires %pyproject_buildrequires diff --git a/python3.12.patch b/python3.12.patch new file mode 100644 index 0000000..21f2468 --- /dev/null +++ b/python3.12.patch @@ -0,0 +1,407 @@ +diff --git a/eventlet/green/http/client.py b/eventlet/green/http/client.py +index e4bd2ad..125c0bf 100644 +--- a/eventlet/green/http/client.py ++++ b/eventlet/green/http/client.py +@@ -1447,6 +1447,18 @@ try: + except ImportError: + pass + else: ++ def _create_https_context(http_version): ++ # Function also used by urllib.request to be able to set the check_hostname ++ # attribute on a context object. ++ context = ssl._create_default_https_context() ++ # send ALPN extension to indicate HTTP/1.1 protocol ++ if http_version == 11: ++ context.set_alpn_protocols(['http/1.1']) ++ # enable PHA for TLS 1.3 connections if available ++ if context.post_handshake_auth is not None: ++ context.post_handshake_auth = True ++ return context ++ + class HTTPSConnection(HTTPConnection): + "This class allows communication via SSL." + +@@ -1463,13 +1475,9 @@ else: + self.key_file = key_file + self.cert_file = cert_file + if context is None: +- context = ssl._create_default_https_context() +- will_verify = context.verify_mode != ssl.CERT_NONE +- if check_hostname is None: +- check_hostname = context.check_hostname +- if check_hostname and not will_verify: +- raise ValueError("check_hostname needs a SSL context with " +- "either CERT_OPTIONAL or CERT_REQUIRED") ++ context = _create_https_context(self._http_vsn) ++ if check_hostname is not None: ++ context.check_hostname = check_hostname + if key_file or cert_file: + context.load_cert_chain(cert_file, key_file) + self._context = context +diff --git a/eventlet/green/ssl.py b/eventlet/green/ssl.py +index b42ddaa..74b6c46 100644 +--- a/eventlet/green/ssl.py ++++ b/eventlet/green/ssl.py +@@ -22,21 +22,17 @@ __patched__ = [ + 'create_default_context', '_create_default_https_context'] + + _original_sslsocket = __ssl.SSLSocket +-_original_wrap_socket = __ssl.wrap_socket + _original_sslcontext = getattr(__ssl, 'SSLContext', None) + _is_under_py_3_7 = sys.version_info < (3, 7) + + + @contextmanager + def _original_ssl_context(*args, **kwargs): +- tmp_sslcontext = _original_wrap_socket.__globals__.get('SSLContext', None) + tmp_sslsocket = _original_sslsocket._create.__globals__.get('SSLSocket', None) + _original_sslsocket._create.__globals__['SSLSocket'] = _original_sslsocket +- _original_wrap_socket.__globals__['SSLContext'] = _original_sslcontext + try: + yield + finally: +- _original_wrap_socket.__globals__['SSLContext'] = tmp_sslcontext + _original_sslsocket._create.__globals__['SSLSocket'] = tmp_sslsocket + + +@@ -76,16 +72,21 @@ class GreenSSLSocket(_original_sslsocket): + session=kw.get('session'), + ) + else: +- ret = _original_wrap_socket( ++ context = _original_sslcontext(protocol=ssl_version) ++ context.options |= cert_reqs ++ if certfile or keyfile: ++ context.load_cert_chain( ++ certfile=certfile, ++ keyfile=keyfile, ++ ) ++ if ca_certs: ++ context.load_verify_locations(ca_certs) ++ if ciphers := kw.get('ciphers'): ++ context.set_ciphers(ciphers) ++ ret = context.wrap_socket( + sock=sock.fd, +- keyfile=keyfile, +- certfile=certfile, + server_side=server_side, +- cert_reqs=cert_reqs, +- ssl_version=ssl_version, +- ca_certs=ca_certs, + do_handshake_on_connect=False, +- ciphers=kw.get('ciphers'), + ) + ret.keyfile = keyfile + ret.certfile = certfile +diff --git a/eventlet/green/thread.py b/eventlet/green/thread.py +index e26f6b3..7bcb563 100644 +--- a/eventlet/green/thread.py ++++ b/eventlet/green/thread.py +@@ -113,3 +113,6 @@ if hasattr(__thread, 'stack_size'): + # this thread will suffer + + from eventlet.corolocal import local as _local ++ ++if hasattr(__thread, 'daemon_threads_allowed'): ++ daemon_threads_allowed = __thread.daemon_threads_allowed +diff --git a/tests/dagpool_test.py b/tests/dagpool_test.py +index fdc23e7..dcd7dd8 100644 +--- a/tests/dagpool_test.py ++++ b/tests/dagpool_test.py +@@ -191,14 +191,14 @@ def test_init(): + with check_no_suspend(): + results = pool.waitall() + # with no spawn() or post(), waitall() returns preload data +- assert_equals(results, dict(a=1, b=2, c=3)) ++ assert_equal(results, dict(a=1, b=2, c=3)) + + # preload sequence of pairs + pool = DAGPool([("d", 4), ("e", 5), ("f", 6)]) + # this must not hang + with check_no_suspend(): + results = pool.waitall() +- assert_equals(results, dict(d=4, e=5, f=6)) ++ assert_equal(results, dict(d=4, e=5, f=6)) + + + def test_wait_each_empty(): +@@ -216,10 +216,10 @@ def test_wait_each_preload(): + with check_no_suspend(): + # wait_each() may deliver in arbitrary order; collect into a dict + # for comparison +- assert_equals(dict(pool.wait_each("abc")), dict(a=1, b=2, c=3)) ++ assert_equal(dict(pool.wait_each("abc")), dict(a=1, b=2, c=3)) + + # while we're at it, test wait() for preloaded keys +- assert_equals(pool.wait("bc"), dict(b=2, c=3)) ++ assert_equal(pool.wait("bc"), dict(b=2, c=3)) + + + def post_each(pool, capture): +@@ -257,7 +257,7 @@ def test_wait_posted(): + eventlet.spawn(post_each, pool, capture) + gotten = pool.wait("bcdefg") + capture.add("got all") +- assert_equals(gotten, ++ assert_equal(gotten, + dict(b=2, c=3, + d="dval", e="eval", + f="fval", g="gval")) +@@ -285,7 +285,7 @@ def test_spawn_collision_spawn(): + pool = DAGPool() + pool.spawn("a", (), lambda key, results: "aval") + # hasn't yet even started +- assert_equals(pool.get("a"), None) ++ assert_equal(pool.get("a"), None) + with assert_raises(Collision): + # Attempting to spawn again with same key should collide even if the + # first spawned greenthread hasn't yet had a chance to run. +@@ -293,7 +293,7 @@ def test_spawn_collision_spawn(): + # now let the spawned eventlet run + eventlet.sleep(0) + # should have finished +- assert_equals(pool.get("a"), "aval") ++ assert_equal(pool.get("a"), "aval") + with assert_raises(Collision): + # Attempting to spawn with same key collides even when the greenthread + # has completed. +@@ -324,60 +324,60 @@ def test_spawn_multiple(): + capture.step() + # but none of them has yet produced a result + for k in "defgh": +- assert_equals(pool.get(k), None) +- assert_equals(set(pool.keys()), set("abc")) +- assert_equals(dict(pool.items()), dict(a=1, b=2, c=3)) +- assert_equals(pool.running(), 5) +- assert_equals(set(pool.running_keys()), set("defgh")) +- assert_equals(pool.waiting(), 1) +- assert_equals(pool.waiting_for(), dict(h=set("defg"))) +- assert_equals(pool.waiting_for("d"), set()) +- assert_equals(pool.waiting_for("c"), set()) ++ assert_equal(pool.get(k), None) ++ assert_equal(set(pool.keys()), set("abc")) ++ assert_equal(dict(pool.items()), dict(a=1, b=2, c=3)) ++ assert_equal(pool.running(), 5) ++ assert_equal(set(pool.running_keys()), set("defgh")) ++ assert_equal(pool.waiting(), 1) ++ assert_equal(pool.waiting_for(), dict(h=set("defg"))) ++ assert_equal(pool.waiting_for("d"), set()) ++ assert_equal(pool.waiting_for("c"), set()) + with assert_raises(KeyError): + pool.waiting_for("j") +- assert_equals(pool.waiting_for("h"), set("defg")) ++ assert_equal(pool.waiting_for("h"), set("defg")) + + # let one of the upstream greenthreads complete + events["f"].send("fval") + spin() + capture.step() +- assert_equals(pool.get("f"), "fval") +- assert_equals(set(pool.keys()), set("abcf")) +- assert_equals(dict(pool.items()), dict(a=1, b=2, c=3, f="fval")) +- assert_equals(pool.running(), 4) +- assert_equals(set(pool.running_keys()), set("degh")) +- assert_equals(pool.waiting(), 1) +- assert_equals(pool.waiting_for("h"), set("deg")) ++ assert_equal(pool.get("f"), "fval") ++ assert_equal(set(pool.keys()), set("abcf")) ++ assert_equal(dict(pool.items()), dict(a=1, b=2, c=3, f="fval")) ++ assert_equal(pool.running(), 4) ++ assert_equal(set(pool.running_keys()), set("degh")) ++ assert_equal(pool.waiting(), 1) ++ assert_equal(pool.waiting_for("h"), set("deg")) + + # now two others + events["e"].send("eval") + events["g"].send("gval") + spin() + capture.step() +- assert_equals(pool.get("e"), "eval") +- assert_equals(pool.get("g"), "gval") +- assert_equals(set(pool.keys()), set("abcefg")) +- assert_equals(dict(pool.items()), ++ assert_equal(pool.get("e"), "eval") ++ assert_equal(pool.get("g"), "gval") ++ assert_equal(set(pool.keys()), set("abcefg")) ++ assert_equal(dict(pool.items()), + dict(a=1, b=2, c=3, e="eval", f="fval", g="gval")) +- assert_equals(pool.running(), 2) +- assert_equals(set(pool.running_keys()), set("dh")) +- assert_equals(pool.waiting(), 1) +- assert_equals(pool.waiting_for("h"), set("d")) ++ assert_equal(pool.running(), 2) ++ assert_equal(set(pool.running_keys()), set("dh")) ++ assert_equal(pool.waiting(), 1) ++ assert_equal(pool.waiting_for("h"), set("d")) + + # last one + events["d"].send("dval") + # make sure both pool greenthreads get a chance to run + spin() + capture.step() +- assert_equals(pool.get("d"), "dval") +- assert_equals(set(pool.keys()), set("abcdefgh")) +- assert_equals(dict(pool.items()), ++ assert_equal(pool.get("d"), "dval") ++ assert_equal(set(pool.keys()), set("abcdefgh")) ++ assert_equal(dict(pool.items()), + dict(a=1, b=2, c=3, + d="dval", e="eval", f="fval", g="gval", h="hval")) +- assert_equals(pool.running(), 0) ++ assert_equal(pool.running(), 0) + assert_false(pool.running_keys()) +- assert_equals(pool.waiting(), 0) +- assert_equals(pool.waiting_for("h"), set()) ++ assert_equal(pool.waiting(), 0) ++ assert_equal(pool.waiting_for("h"), set()) + + capture.validate([ + ["h got b", "h got c"], +@@ -432,13 +432,13 @@ def test_spawn_many(): + spin() + # verify that e completed (also that post(key) within greenthread + # overrides implicit post of return value, which would be None) +- assert_equals(pool.get("e"), "e") ++ assert_equal(pool.get("e"), "e") + + # With the dependency graph shown above, it is not guaranteed whether b or + # c will complete first. Handle either case. + sequence = capture.sequence[:] + sequence[1:3] = [set([sequence[1].pop(), sequence[2].pop()])] +- assert_equals(sequence, ++ assert_equal(sequence, + [set(["a done"]), + set(["b done", "c done"]), + set(["d done"]), +@@ -466,7 +466,7 @@ def test_wait_each_all(): + for pos in range(len(keys)): + # next value from wait_each() + k, v = next(each) +- assert_equals(k, keys[pos]) ++ assert_equal(k, keys[pos]) + # advance every pool greenlet as far as it can go + spin() + # everything from keys[:pos+1] should have a value by now +@@ -494,7 +494,7 @@ def test_kill(): + pool.kill("a") + # didn't run + spin() +- assert_equals(pool.get("a"), None) ++ assert_equal(pool.get("a"), None) + # killing it forgets about it + with assert_raises(KeyError): + pool.kill("a") +@@ -505,7 +505,7 @@ def test_kill(): + with assert_raises(KeyError): + pool.kill("a") + # verify it ran to completion +- assert_equals(pool.get("a"), 2) ++ assert_equal(pool.get("a"), 2) + + + def test_post_collision_preload(): +@@ -533,7 +533,7 @@ def test_post_collision_spawn(): + pool.kill("a") + # now we can post + pool.post("a", 3) +- assert_equals(pool.get("a"), 3) ++ assert_equal(pool.get("a"), 3) + + pool = DAGPool() + pool.spawn("a", (), lambda key, result: 4) +@@ -553,10 +553,10 @@ def test_post_replace(): + pool = DAGPool() + pool.post("a", 1) + pool.post("a", 2, replace=True) +- assert_equals(pool.get("a"), 2) +- assert_equals(dict(pool.wait_each("a")), dict(a=2)) +- assert_equals(pool.wait("a"), dict(a=2)) +- assert_equals(pool["a"], 2) ++ assert_equal(pool.get("a"), 2) ++ assert_equal(dict(pool.wait_each("a")), dict(a=2)) ++ assert_equal(pool.wait("a"), dict(a=2)) ++ assert_equal(pool["a"], 2) + + + def waitfor(capture, pool, key): +@@ -598,10 +598,10 @@ def test_waitall_exc(): + try: + pool.waitall() + except PropagateError as err: +- assert_equals(err.key, "a") ++ assert_equal(err.key, "a") + assert isinstance(err.exc, BogusError), \ + "exc attribute is {0}, not BogusError".format(err.exc) +- assert_equals(str(err.exc), "bogus") ++ assert_equal(str(err.exc), "bogus") + msg = str(err) + assert_in("PropagateError(a)", msg) + assert_in("BogusError", msg) +@@ -616,14 +616,14 @@ def test_propagate_exc(): + try: + pool["c"] + except PropagateError as errc: +- assert_equals(errc.key, "c") ++ assert_equal(errc.key, "c") + errb = errc.exc +- assert_equals(errb.key, "b") ++ assert_equal(errb.key, "b") + erra = errb.exc +- assert_equals(erra.key, "a") ++ assert_equal(erra.key, "a") + assert isinstance(erra.exc, BogusError), \ + "exc attribute is {0}, not BogusError".format(erra.exc) +- assert_equals(str(erra.exc), "bogus") ++ assert_equal(str(erra.exc), "bogus") + msg = str(errc) + assert_in("PropagateError(a)", msg) + assert_in("PropagateError(b)", msg) +@@ -681,13 +681,13 @@ def test_post_get_exc(): + pass + + # wait_each_success() filters +- assert_equals(dict(pool.wait_each_success()), dict(a=bogua)) +- assert_equals(dict(pool.wait_each_success("ab")), dict(a=bogua)) +- assert_equals(dict(pool.wait_each_success("a")), dict(a=bogua)) +- assert_equals(dict(pool.wait_each_success("b")), {}) ++ assert_equal(dict(pool.wait_each_success()), dict(a=bogua)) ++ assert_equal(dict(pool.wait_each_success("ab")), dict(a=bogua)) ++ assert_equal(dict(pool.wait_each_success("a")), dict(a=bogua)) ++ assert_equal(dict(pool.wait_each_success("b")), {}) + + # wait_each_exception() filters the other way +- assert_equals(dict(pool.wait_each_exception()), dict(b=bogub)) +- assert_equals(dict(pool.wait_each_exception("ab")), dict(b=bogub)) +- assert_equals(dict(pool.wait_each_exception("a")), {}) +- assert_equals(dict(pool.wait_each_exception("b")), dict(b=bogub)) ++ assert_equal(dict(pool.wait_each_exception()), dict(b=bogub)) ++ assert_equal(dict(pool.wait_each_exception("ab")), dict(b=bogub)) ++ assert_equal(dict(pool.wait_each_exception("a")), {}) ++ assert_equal(dict(pool.wait_each_exception("b")), dict(b=bogub)) +diff --git a/tests/tpool_test.py b/tests/tpool_test.py +index 1a730dc..ffd947b 100644 +--- a/tests/tpool_test.py ++++ b/tests/tpool_test.py +@@ -315,11 +315,11 @@ class TpoolLongTests(tests.LimitedTestCase): + + @tests.skip_with_pyevent + def test_a_buncha_stuff(self): +- assert_ = self.assert_ ++ assertTrue = self.assertTrue + + class Dummy(object): + def foo(self, when, token=None): +- assert_(token is not None) ++ assertTrue(token is not None) + time.sleep(random.random() / 200.0) + return token + +@@ -359,7 +359,7 @@ class TpoolLongTests(tests.LimitedTestCase): + first_created = middle_objs - initial_objs + gc.collect() + second_created = len(gc.get_objects()) - middle_objs +- self.assert_(second_created - first_created < 10, ++ self.assertTrue(second_created - first_created < 10, + "first loop: %s, second loop: %s" % (first_created, + second_created)) + tpool.killall()