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