|
|
|
From 2b83e7ccc12af9fec136e9f4897e1585b3b931aa Mon Sep 17 00:00:00 2001
|
|
|
|
From: Aymeric Augustin <aymeric.augustin@m4x.org>
|
|
|
|
Date: Thu, 24 May 2018 22:29:12 +0200
|
|
|
|
Subject: [PATCH 1/3] Add support for Python 3.7.
|
|
|
|
|
|
|
|
Hopefully for real this time.
|
|
|
|
|
|
|
|
This is annoyingly complicated.
|
|
|
|
|
|
|
|
Fix #405.
|
|
|
|
|
|
|
|
(cherry picked from commit 6f8f1c877744623f0a5df5917a85b97807bfb7e5)
|
|
|
|
---
|
|
|
|
websockets/client.py | 24 +++++++----------
|
|
|
|
websockets/py35/_test_client_server.py | 37 ++++++++++++++++++++++++++
|
|
|
|
websockets/py35/client.py | 33 +++++++++++++++++++++++
|
|
|
|
websockets/py35/server.py | 22 +++++++++++++++
|
|
|
|
websockets/server.py | 25 +++++++----------
|
|
|
|
websockets/test_client_server.py | 1 +
|
|
|
|
6 files changed, 111 insertions(+), 31 deletions(-)
|
|
|
|
create mode 100644 websockets/py35/client.py
|
|
|
|
create mode 100644 websockets/py35/server.py
|
|
|
|
|
|
|
|
diff --git a/websockets/client.py b/websockets/client.py
|
|
|
|
index 92f29e9..a86b90f 100644
|
|
|
|
--- a/websockets/client.py
|
|
|
|
+++ b/websockets/client.py
|
|
|
|
@@ -385,15 +385,7 @@ class Connect:
|
|
|
|
self._creating_connection = loop.create_connection(
|
|
|
|
factory, host, port, **kwds)
|
|
|
|
|
|
|
|
- @asyncio.coroutine
|
|
|
|
- def __aenter__(self):
|
|
|
|
- return (yield from self)
|
|
|
|
-
|
|
|
|
- @asyncio.coroutine
|
|
|
|
- def __aexit__(self, exc_type, exc_value, traceback):
|
|
|
|
- yield from self.ws_client.close()
|
|
|
|
-
|
|
|
|
- def __await__(self):
|
|
|
|
+ def __iter__(self): # pragma: no cover
|
|
|
|
transport, protocol = yield from self._creating_connection
|
|
|
|
|
|
|
|
try:
|
|
|
|
@@ -410,17 +402,19 @@ class Connect:
|
|
|
|
self.ws_client = protocol
|
|
|
|
return protocol
|
|
|
|
|
|
|
|
- __iter__ = __await__
|
|
|
|
-
|
|
|
|
|
|
|
|
-# Disable asynchronous context manager functionality only on Python < 3.5.1
|
|
|
|
-# because it doesn't exist on Python < 3.5 and asyncio.ensure_future didn't
|
|
|
|
-# accept arbitrary awaitables in Python 3.5; that was fixed in Python 3.5.1.
|
|
|
|
+# We can't define __await__ on Python < 3.5.1 because asyncio.ensure_future
|
|
|
|
+# didn't accept arbitrary awaitables until Python 3.5.1. We don't define
|
|
|
|
+# __aenter__ and __aexit__ either on Python < 3.5.1 to keep things simple.
|
|
|
|
if sys.version_info[:3] <= (3, 5, 0): # pragma: no cover
|
|
|
|
@asyncio.coroutine
|
|
|
|
def connect(*args, **kwds):
|
|
|
|
- return Connect(*args, **kwds).__await__()
|
|
|
|
+ return Connect(*args, **kwds).__iter__()
|
|
|
|
connect.__doc__ = Connect.__doc__
|
|
|
|
|
|
|
|
else:
|
|
|
|
+ from .py35.client import __aenter__, __aexit__, __await__
|
|
|
|
+ Connect.__aenter__ = __aenter__
|
|
|
|
+ Connect.__aexit__ = __aexit__
|
|
|
|
+ Connect.__await__ = __await__
|
|
|
|
connect = Connect
|
|
|
|
diff --git a/websockets/py35/_test_client_server.py b/websockets/py35/_test_client_server.py
|
|
|
|
index 4375248..5360d8d 100644
|
|
|
|
--- a/websockets/py35/_test_client_server.py
|
|
|
|
+++ b/websockets/py35/_test_client_server.py
|
|
|
|
@@ -13,6 +13,43 @@ from ..server import *
|
|
|
|
from ..test_client_server import get_server_uri, handler
|
|
|
|
|
|
|
|
|
|
|
|
+class AsyncAwaitTests(unittest.TestCase):
|
|
|
|
+
|
|
|
|
+ def setUp(self):
|
|
|
|
+ self.loop = asyncio.new_event_loop()
|
|
|
|
+ asyncio.set_event_loop(self.loop)
|
|
|
|
+
|
|
|
|
+ def tearDown(self):
|
|
|
|
+ self.loop.close()
|
|
|
|
+
|
|
|
|
+ def test_client(self):
|
|
|
|
+ start_server = serve(handler, 'localhost', 0)
|
|
|
|
+ server = self.loop.run_until_complete(start_server)
|
|
|
|
+
|
|
|
|
+ async def run_client():
|
|
|
|
+ # Await connect.
|
|
|
|
+ client = await connect(get_server_uri(server))
|
|
|
|
+ self.assertEqual(client.state, State.OPEN)
|
|
|
|
+ await client.close()
|
|
|
|
+ self.assertEqual(client.state, State.CLOSED)
|
|
|
|
+
|
|
|
|
+ self.loop.run_until_complete(run_client())
|
|
|
|
+
|
|
|
|
+ server.close()
|
|
|
|
+ self.loop.run_until_complete(server.wait_closed())
|
|
|
|
+
|
|
|
|
+ def test_server(self):
|
|
|
|
+ async def run_server():
|
|
|
|
+ # Await serve.
|
|
|
|
+ server = await serve(handler, 'localhost', 0)
|
|
|
|
+ self.assertTrue(server.sockets)
|
|
|
|
+ server.close()
|
|
|
|
+ await server.wait_closed()
|
|
|
|
+ self.assertFalse(server.sockets)
|
|
|
|
+
|
|
|
|
+ self.loop.run_until_complete(run_server())
|
|
|
|
+
|
|
|
|
+
|
|
|
|
class ContextManagerTests(unittest.TestCase):
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
diff --git a/websockets/py35/client.py b/websockets/py35/client.py
|
|
|
|
new file mode 100644
|
|
|
|
index 0000000..7673ea3
|
|
|
|
--- /dev/null
|
|
|
|
+++ b/websockets/py35/client.py
|
|
|
|
@@ -0,0 +1,33 @@
|
|
|
|
+async def __aenter__(self):
|
|
|
|
+ return await self
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+async def __aexit__(self, exc_type, exc_value, traceback):
|
|
|
|
+ await self.ws_client.close()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+async def __await_impl__(self):
|
|
|
|
+ # Duplicated with __iter__ because Python 3.7 requires an async function
|
|
|
|
+ # (as explained in __await__ below) which Python 3.4 doesn't support.
|
|
|
|
+ transport, protocol = await self._creating_connection
|
|
|
|
+
|
|
|
|
+ try:
|
|
|
|
+ await protocol.handshake(
|
|
|
|
+ self._wsuri, origin=self._origin,
|
|
|
|
+ available_extensions=protocol.available_extensions,
|
|
|
|
+ available_subprotocols=protocol.available_subprotocols,
|
|
|
|
+ extra_headers=protocol.extra_headers,
|
|
|
|
+ )
|
|
|
|
+ except Exception:
|
|
|
|
+ await protocol.fail_connection()
|
|
|
|
+ raise
|
|
|
|
+
|
|
|
|
+ self.ws_client = protocol
|
|
|
|
+ return protocol
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def __await__(self):
|
|
|
|
+ # __await__() must return a type that I don't know how to obtain except
|
|
|
|
+ # by calling __await__() on the return value of an async function.
|
|
|
|
+ # I'm not finding a better way to take advantage of PEP 492.
|
|
|
|
+ return __await_impl__(self).__await__()
|
|
|
|
diff --git a/websockets/py35/server.py b/websockets/py35/server.py
|
|
|
|
new file mode 100644
|
|
|
|
index 0000000..41a3675
|
|
|
|
--- /dev/null
|
|
|
|
+++ b/websockets/py35/server.py
|
|
|
|
@@ -0,0 +1,22 @@
|
|
|
|
+async def __aenter__(self):
|
|
|
|
+ return await self
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+async def __aexit__(self, exc_type, exc_value, traceback):
|
|
|
|
+ self.ws_server.close()
|
|
|
|
+ await self.ws_server.wait_closed()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+async def __await_impl__(self):
|
|
|
|
+ # Duplicated with __iter__ because Python 3.7 requires an async function
|
|
|
|
+ # (as explained in __await__ below) which Python 3.4 doesn't support.
|
|
|
|
+ server = await self._creating_server
|
|
|
|
+ self.ws_server.wrap(server)
|
|
|
|
+ return self.ws_server
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def __await__(self):
|
|
|
|
+ # __await__() must return a type that I don't know how to obtain except
|
|
|
|
+ # by calling __await__() on the return value of an async function.
|
|
|
|
+ # I'm not finding a better way to take advantage of PEP 492.
|
|
|
|
+ return __await_impl__(self).__await__()
|
|
|
|
diff --git a/websockets/server.py b/websockets/server.py
|
|
|
|
index 8db0482..46c80dc 100644
|
|
|
|
--- a/websockets/server.py
|
|
|
|
+++ b/websockets/server.py
|
|
|
|
@@ -729,22 +729,11 @@ class Serve:
|
|
|
|
self._creating_server = creating_server
|
|
|
|
self.ws_server = ws_server
|
|
|
|
|
|
|
|
- @asyncio.coroutine
|
|
|
|
- def __aenter__(self):
|
|
|
|
- return (yield from self)
|
|
|
|
-
|
|
|
|
- @asyncio.coroutine
|
|
|
|
- def __aexit__(self, exc_type, exc_value, traceback):
|
|
|
|
- self.ws_server.close()
|
|
|
|
- yield from self.ws_server.wait_closed()
|
|
|
|
-
|
|
|
|
- def __await__(self):
|
|
|
|
+ def __iter__(self): # pragma: no cover
|
|
|
|
server = yield from self._creating_server
|
|
|
|
self.ws_server.wrap(server)
|
|
|
|
return self.ws_server
|
|
|
|
|
|
|
|
- __iter__ = __await__
|
|
|
|
-
|
|
|
|
|
|
|
|
def unix_serve(ws_handler, path, **kwargs):
|
|
|
|
"""
|
|
|
|
@@ -761,14 +750,18 @@ def unix_serve(ws_handler, path, **kwargs):
|
|
|
|
return serve(ws_handler, path=path, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
-# Disable asynchronous context manager functionality only on Python < 3.5.1
|
|
|
|
-# because it doesn't exist on Python < 3.5 and asyncio.ensure_future didn't
|
|
|
|
-# accept arbitrary awaitables in Python 3.5; that was fixed in Python 3.5.1.
|
|
|
|
+# We can't define __await__ on Python < 3.5.1 because asyncio.ensure_future
|
|
|
|
+# didn't accept arbitrary awaitables until Python 3.5.1. We don't define
|
|
|
|
+# __aenter__ and __aexit__ either on Python < 3.5.1 to keep things simple.
|
|
|
|
if sys.version_info[:3] <= (3, 5, 0): # pragma: no cover
|
|
|
|
@asyncio.coroutine
|
|
|
|
def serve(*args, **kwds):
|
|
|
|
- return Serve(*args, **kwds).__await__()
|
|
|
|
+ return Serve(*args, **kwds).__iter__()
|
|
|
|
serve.__doc__ = Serve.__doc__
|
|
|
|
|
|
|
|
else:
|
|
|
|
+ from .py35.server import __aenter__, __aexit__, __await__
|
|
|
|
+ Serve.__aenter__ = __aenter__
|
|
|
|
+ Serve.__aexit__ = __aexit__
|
|
|
|
+ Serve.__await__ = __await__
|
|
|
|
serve = Serve
|
|
|
|
diff --git a/websockets/test_client_server.py b/websockets/test_client_server.py
|
|
|
|
index 8476913..27a2a71 100644
|
|
|
|
--- a/websockets/test_client_server.py
|
|
|
|
+++ b/websockets/test_client_server.py
|
|
|
|
@@ -1057,6 +1057,7 @@ class ClientServerOriginTests(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
+ from .py35._test_client_server import AsyncAwaitTests # noqa
|
|
|
|
from .py35._test_client_server import ContextManagerTests # noqa
|
|
|
|
except (SyntaxError, ImportError): # pragma: no cover
|
|
|
|
pass
|
|
|
|
--
|
|
|
|
2.18.0
|
|
|
|
|