diff --git a/httpcore/__init__.py b/httpcore/__init__.py index 330745a5d..014213bae 100644 --- a/httpcore/__init__.py +++ b/httpcore/__init__.py @@ -130,7 +130,7 @@ def __init__(self, *args, **kwargs): # type: ignore "WriteError", ] -__version__ = "1.0.6" +__version__ = "1.0.5" __locals = locals() diff --git a/httpcore/_synchronization.py b/httpcore/_synchronization.py index 2d86f8b8e..8d8c5b689 100644 --- a/httpcore/_synchronization.py +++ b/httpcore/_synchronization.py @@ -1,4 +1,5 @@ import asyncio +import sys import threading from types import TracebackType from typing import ( @@ -29,6 +30,18 @@ anyio = None # type: ignore +if sys.version_info >= (3, 11): # pragma: nocover + import asyncio as asyncio_timeout + + anyio_shield = None +else: # pragma: nocover + import async_timeout as asyncio_timeout + + if anyio is None: # pragma: nocover + raise RuntimeError("Running in Python<3.11 requires anyio") + anyio_shield = anyio.CancelScope + + AsyncBackend = Literal["asyncio", "trio"] @@ -163,9 +176,11 @@ async def wait(self, timeout: Optional[float] = None) -> None: with trio.fail_after(timeout_or_inf): await event.wait() else: - asyncio_exc_map: ExceptionMapping = {TimeoutError: PoolTimeout} + asyncio_exc_map: ExceptionMapping = { + asyncio.exceptions.TimeoutError: PoolTimeout + } with map_exceptions(asyncio_exc_map): - async with asyncio.timeout(timeout): + async with asyncio_timeout.timeout(timeout): await event.wait() @@ -217,8 +232,11 @@ async def shield(shielded: Callable[[], Coroutine[Any, Any, None]]) -> None: if current_async_backend() == "trio": with trio.CancelScope(shield=True): await shielded() + elif sys.version_info < (3, 11): # pragma: nocover + with anyio_shield(shield=True): + await shielded() else: - await AsyncShieldCancellation._asyncio_shield(shielded) + await AsyncShieldCancellation._asyncio_shield(shielded) # pragma: nocover @staticmethod async def _asyncio_shield( @@ -227,7 +245,7 @@ async def _asyncio_shield( inner_task = asyncio.create_task(shielded()) try: await asyncio.shield(inner_task) - except asyncio.CancelledError: + except (asyncio.exceptions.CancelledError, asyncio.CancelledError): # Let the inner_task to complete as it was shielded from the cancellation await inner_task diff --git a/pyproject.toml b/pyproject.toml index 85c787402..7a9fea162 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,7 @@ classifiers = [ dependencies = [ "certifi", "h11>=0.13,<0.15", + "async-timeout==4.*; python_version < '3.11'", ] [project.optional-dependencies] diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 463a189c0..000000000 --- a/tests/conftest.py +++ /dev/null @@ -1,16 +0,0 @@ -import pytest - - -@pytest.fixture( - params=[ - pytest.param(("asyncio", {"httpcore_use_anyio": False}), id="asyncio"), - pytest.param(("asyncio", {"httpcore_use_anyio": True}), id="asyncio+anyio"), - pytest.param(("trio", {}), id="trio"), - ] -) -def anyio_backend(request, monkeypatch): - backend_name, options = request.param - options = {**options} - use_anyio = options.pop("httpcore_use_anyio", False) - monkeypatch.setenv("HTTPCORE_PREFER_ANYIO", "1" if use_anyio else "0") - return backend_name, options