From 51bbf697559d995501e0bce88b5c366b6e6bec54 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 1 Aug 2024 15:08:42 -0500 Subject: [PATCH] Restore the ability to create objects without a running event loop --- aiohttp/abc.py | 3 ++- aiohttp/client.py | 3 ++- aiohttp/connector.py | 4 ++-- aiohttp/helpers.py | 23 +++++++++++++++++++++-- aiohttp/resolver.py | 3 ++- aiohttp/web_server.py | 3 ++- 6 files changed, 31 insertions(+), 8 deletions(-) diff --git a/aiohttp/abc.py b/aiohttp/abc.py index 3fb02404..8e327f09 100644 --- a/aiohttp/abc.py +++ b/aiohttp/abc.py @@ -21,6 +21,7 @@ from typing import ( from multidict import CIMultiDict from yarl import URL +from .helpers import get_running_loop from .typedefs import LooseCookies if TYPE_CHECKING: @@ -169,7 +170,7 @@ class AbstractCookieJar(Sized, IterableBase): """Abstract Cookie Jar.""" def __init__(self, *, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: - self._loop = loop or asyncio.get_running_loop() + self._loop = loop or get_running_loop() @abstractmethod def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: diff --git a/aiohttp/client.py b/aiohttp/client.py index c70ad65c..346c1532 100644 --- a/aiohttp/client.py +++ b/aiohttp/client.py @@ -88,6 +88,7 @@ from .helpers import ( TimeoutHandle, ceil_timeout, get_env_proxy_for_url, + get_running_loop, method_must_be_empty_body, sentinel, strip_auth_from_url, @@ -293,7 +294,7 @@ class ClientSession: if connector is not None: loop = connector._loop - loop = loop or asyncio.get_running_loop() + loop = loop or get_running_loop() if base_url is None or isinstance(base_url, URL): self._base_url: Optional[URL] = base_url diff --git a/aiohttp/connector.py b/aiohttp/connector.py index cd89ea64..f33cee19 100644 --- a/aiohttp/connector.py +++ b/aiohttp/connector.py @@ -49,7 +49,7 @@ from .client_exceptions import ( ) from .client_proto import ResponseHandler from .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params -from .helpers import ceil_timeout, is_ip_address, noop, sentinel +from .helpers import ceil_timeout, get_running_loop, is_ip_address, noop, sentinel from .locks import EventResultOrError from .resolver import DefaultResolver @@ -105,7 +105,7 @@ class Connection: ) -> None: self._key = key self._connector = connector - self._loop = loop + self._loop = loop or get_running_loop() self._protocol: Optional[ResponseHandler] = protocol self._callbacks: List[Callable[[], None]] = [] diff --git a/aiohttp/helpers.py b/aiohttp/helpers.py index b3cc1b6b..aa4769ed 100644 --- a/aiohttp/helpers.py +++ b/aiohttp/helpers.py @@ -14,6 +14,7 @@ import platform import re import sys import time +import warnings import weakref from collections import namedtuple from contextlib import suppress @@ -51,7 +52,7 @@ from multidict import MultiDict, MultiDictProxy, MultiMapping from yarl import URL from . import hdrs -from .log import client_logger +from .log import client_logger, internal_logger if sys.version_info >= (3, 11): import asyncio as async_timeout @@ -286,6 +287,24 @@ def proxies_from_env() -> Dict[str, ProxyInfo]: return ret +def get_running_loop() -> asyncio.AbstractEventLoop: + """Get the running event loop.""" + try: + return asyncio.get_running_loop() + except RuntimeError: + warnings.warn( + "The object should be created within an async function", + DeprecationWarning, + stacklevel=3, + ) + loop = asyncio.get_event_loop() + if loop.get_debug(): + internal_logger.warning( + "The object should be created within an async function", stack_info=True + ) + return loop + + def get_env_proxy_for_url(url: URL) -> Tuple[URL, Optional[BasicAuth]]: """Get a permitted proxy for the given URL from the env.""" if url.host is not None and proxy_bypass(url.host): @@ -716,7 +735,7 @@ def ceil_timeout( if delay is None or delay <= 0: return async_timeout.timeout(None) - loop = asyncio.get_running_loop() + loop = get_running_loop() now = loop.time() when = now + delay if delay > ceil_threshold: diff --git a/aiohttp/resolver.py b/aiohttp/resolver.py index 10e36266..e9b43df9 100644 --- a/aiohttp/resolver.py +++ b/aiohttp/resolver.py @@ -4,6 +4,7 @@ import sys from typing import Any, Dict, List, Optional, Tuple, Type, Union from .abc import AbstractResolver, ResolveResult +from .helpers import get_running_loop __all__ = ("ThreadedResolver", "AsyncResolver", "DefaultResolver") @@ -29,7 +30,7 @@ class ThreadedResolver(AbstractResolver): """ def __init__(self, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: - self._loop = loop or asyncio.get_running_loop() + self._loop = loop or get_running_loop() async def resolve( self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET diff --git a/aiohttp/web_server.py b/aiohttp/web_server.py index ffc198d5..78f0b358 100644 --- a/aiohttp/web_server.py +++ b/aiohttp/web_server.py @@ -4,6 +4,7 @@ import asyncio from typing import Any, Awaitable, Callable, Dict, List, Optional # noqa from .abc import AbstractStreamWriter +from .helpers import get_running_loop from .http_parser import RawRequestMessage from .streams import StreamReader from .web_protocol import RequestHandler, _RequestFactory, _RequestHandler @@ -22,7 +23,7 @@ class Server: loop: Optional[asyncio.AbstractEventLoop] = None, **kwargs: Any ) -> None: - self._loop = loop or asyncio.get_running_loop() + self._loop = loop or get_running_loop() self._connections: Dict[RequestHandler, asyncio.Transport] = {} self._kwargs = kwargs self.requests_count = 0 -- 2.39.3 (Apple Git-145)