From d23334f69c7d29715e428f7d7c649450413d3a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= Date: Sat, 27 Feb 2021 12:44:20 +0200 Subject: [PATCH 1/5] Ensured AnyIO 3.x compatibility --- httpcore/_backends/anyio.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/httpcore/_backends/anyio.py b/httpcore/_backends/anyio.py index 971fbab43..ed81d8492 100644 --- a/httpcore/_backends/anyio.py +++ b/httpcore/_backends/anyio.py @@ -20,6 +20,16 @@ from .._utils import is_socket_readable from .base import AsyncBackend, AsyncLock, AsyncSemaphore, AsyncSocketStream +# For compatibility with both AnyIO 2.x and 3.x +try: + from anyio import maybe_async, maybe_async_cm +except ImportError: + + def maybe_async(x): + return x + + maybe_async_cm = maybe_async + class SocketStream(AsyncSocketStream): def __init__(self, stream: ByteStream) -> None: @@ -39,7 +49,7 @@ async def start_tls( ) -> "SocketStream": connect_timeout = timeout.get("connect") try: - async with anyio.fail_after(connect_timeout): + async with maybe_async_cm(anyio.fail_after(connect_timeout)): ssl_stream = await TLSStream.wrap( self.stream, ssl_context=ssl_context, @@ -56,7 +66,7 @@ async def read(self, n: int, timeout: TimeoutDict) -> bytes: read_timeout = timeout.get("read") async with self.read_lock: try: - async with anyio.fail_after(read_timeout): + async with maybe_async_cm(anyio.fail_after(read_timeout)): return await self.stream.receive(n) except TimeoutError: raise ReadTimeout from None @@ -72,7 +82,7 @@ async def write(self, data: bytes, timeout: TimeoutDict) -> None: write_timeout = timeout.get("write") async with self.write_lock: try: - async with anyio.fail_after(write_timeout): + async with maybe_async_cm(anyio.fail_after(write_timeout)): return await self.stream.send(data) except TimeoutError: raise WriteTimeout from None @@ -96,7 +106,7 @@ def __init__(self) -> None: self._lock = anyio.create_lock() async def release(self) -> None: - await self._lock.release() + await maybe_async(self._lock.release()) async def acquire(self) -> None: await self._lock.acquire() @@ -114,14 +124,14 @@ def semaphore(self) -> anyio.abc.Semaphore: return self._semaphore async def acquire(self, timeout: float = None) -> None: - async with anyio.move_on_after(timeout): + async with maybe_async_cm(anyio.move_on_after(timeout)): await self.semaphore.acquire() return raise self.exc_class() async def release(self) -> None: - await self.semaphore.release() + await maybe_async(self.semaphore.release()) class AnyIOBackend(AsyncBackend): @@ -143,7 +153,7 @@ async def open_tcp_stream( } with map_exceptions(exc_map): - async with anyio.fail_after(connect_timeout): + async with maybe_async_cm(anyio.fail_after(connect_timeout)): stream: anyio.abc.ByteStream stream = await anyio.connect_tcp( unicode_host, port, local_host=local_address @@ -174,7 +184,7 @@ async def open_uds_stream( } with map_exceptions(exc_map): - async with anyio.fail_after(connect_timeout): + async with maybe_async_cm(anyio.fail_after(connect_timeout)): stream: anyio.abc.ByteStream = await anyio.connect_unix(path) if ssl_context: stream = await TLSStream.wrap( @@ -193,7 +203,7 @@ def create_semaphore(self, max_value: int, exc_class: type) -> AsyncSemaphore: return Semaphore(max_value, exc_class=exc_class) async def time(self) -> float: - return await anyio.current_time() + return await maybe_async(anyio.current_time()) async def sleep(self, seconds: float) -> None: await anyio.sleep(seconds) From 1aaa0cfcfd97f79111ea2278e50a672146813620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= Date: Sat, 27 Feb 2021 12:56:15 +0200 Subject: [PATCH 2/5] Fixed linting errors --- httpcore/_backends/anyio.py | 5 +++-- requirements.txt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/httpcore/_backends/anyio.py b/httpcore/_backends/anyio.py index ed81d8492..bcc4a4804 100644 --- a/httpcore/_backends/anyio.py +++ b/httpcore/_backends/anyio.py @@ -25,10 +25,11 @@ from anyio import maybe_async, maybe_async_cm except ImportError: - def maybe_async(x): + def maybe_async(x): # type: ignore return x - maybe_async_cm = maybe_async + def maybe_async_cm(x): # type: ignore + return x class SocketStream(AsyncSocketStream): diff --git a/requirements.txt b/requirements.txt index ea3f8414c..561e7ee57 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ twine==3.2.0 wheel==0.35.1 # Tests & Linting -anyio==2.0.2 +anyio==2.2.0 autoflake==1.4 black==20.8b1 coverage==5.3 From 455fbe18aa7623ae04162d8d74966d48a2eb015b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= Date: Fri, 12 Mar 2021 14:53:51 +0200 Subject: [PATCH 3/5] Improved the comment --- httpcore/_backends/anyio.py | 1 + 1 file changed, 1 insertion(+) diff --git a/httpcore/_backends/anyio.py b/httpcore/_backends/anyio.py index bcc4a4804..2c927e243 100644 --- a/httpcore/_backends/anyio.py +++ b/httpcore/_backends/anyio.py @@ -21,6 +21,7 @@ from .base import AsyncBackend, AsyncLock, AsyncSemaphore, AsyncSocketStream # For compatibility with both AnyIO 2.x and 3.x +# (some functions and context managers were converted from async to sync in 3.0) try: from anyio import maybe_async, maybe_async_cm except ImportError: From b6ad47b65115a62b36f75ccd516ef4ddc4a264c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= Date: Fri, 23 Apr 2021 10:01:49 +0300 Subject: [PATCH 4/5] Fixed deprecation warnings --- httpcore/_backends/anyio.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/httpcore/_backends/anyio.py b/httpcore/_backends/anyio.py index 2c927e243..a071e6fc1 100644 --- a/httpcore/_backends/anyio.py +++ b/httpcore/_backends/anyio.py @@ -33,11 +33,17 @@ def maybe_async_cm(x): # type: ignore return x +try: + from anyio import Lock as create_lock, Semaphore as create_semaphore +except ImportError: + from anyio import create_lock, create_semaphore + + class SocketStream(AsyncSocketStream): def __init__(self, stream: ByteStream) -> None: self.stream = stream - self.read_lock = anyio.create_lock() - self.write_lock = anyio.create_lock() + self.read_lock = create_lock() + self.write_lock = create_lock() def get_http_version(self) -> str: alpn_protocol = self.stream.extra(TLSAttribute.alpn_protocol, None) @@ -105,7 +111,7 @@ def is_readable(self) -> bool: class Lock(AsyncLock): def __init__(self) -> None: - self._lock = anyio.create_lock() + self._lock = create_lock() async def release(self) -> None: await maybe_async(self._lock.release()) @@ -122,7 +128,7 @@ def __init__(self, max_value: int, exc_class: type): @property def semaphore(self) -> anyio.abc.Semaphore: if not hasattr(self, "_semaphore"): - self._semaphore = anyio.create_semaphore(self.max_value) + self._semaphore = create_semaphore(self.max_value) return self._semaphore async def acquire(self, timeout: float = None) -> None: From 8c02bd521a2899a5a28b137a225830d22df81481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= Date: Fri, 23 Apr 2021 10:05:32 +0300 Subject: [PATCH 5/5] Fixed mypy errors and upgraded AnyIO --- httpcore/_backends/anyio.py | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/httpcore/_backends/anyio.py b/httpcore/_backends/anyio.py index a071e6fc1..3d1ebb65d 100644 --- a/httpcore/_backends/anyio.py +++ b/httpcore/_backends/anyio.py @@ -36,7 +36,7 @@ def maybe_async_cm(x): # type: ignore try: from anyio import Lock as create_lock, Semaphore as create_semaphore except ImportError: - from anyio import create_lock, create_semaphore + from anyio import create_lock, create_semaphore # type: ignore class SocketStream(AsyncSocketStream): diff --git a/requirements.txt b/requirements.txt index ddb56746e..a81fd7a23 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,7 +20,7 @@ twine==3.4.1 wheel==0.36.2 # Tests & Linting -anyio==2.2.0 +anyio==3.0.0 autoflake==1.4 black==20.8b1 coverage==5.5