from abc import ABC, abstractmethod from httpx import AsyncClient from requests import Request, Response, Session class Sender(ABC): """Sender interface for requests.""" @abstractmethod def send(self, request: Request) -> Response: """ Prepare and send a request. Parameters ---------- request :class:`Request` to send """ @property @abstractmethod def is_async(self) -> bool: """Sender asynchronicity mode.""" class SyncSender(Sender, ABC): """Synchronous request sender base class.""" @property def is_async(self) -> bool: """Sender asynchronicity, always :class:`False`.""" return False class AsyncSender(Sender, ABC): """Asynchronous request sender base class.""" @property def is_async(self) -> bool: """Sender asynchronicity, always :class:`True`.""" return True class TransientSender(SyncSender): """ Create a new session for each request. Parameters ---------- requests_kwargs keyword arguments for :meth:`requests.Session.send` """ def __init__(self, **requests_kwargs): from tekore import default_requests_kwargs self.requests_kwargs = requests_kwargs or default_requests_kwargs def send(self, request: Request) -> Response: """Send request with new session.""" with Session() as sess: prepared = sess.prepare_request(request) return sess.send(prepared, **self.requests_kwargs) class AsyncTransientSender(AsyncSender): """ Create a new asynchronous client for each request. Parameters ---------- httpx_kwargs keyword arguments for :meth:`httpx.AsyncClient.request` """ def __init__(self, **httpx_kwargs): from tekore import default_httpx_kwargs self.httpx_kwargs = httpx_kwargs or default_httpx_kwargs async def send(self, request: Request) -> Response: """Send request with new client.""" async with AsyncClient() as client: return await client.request( request.method, request.url, data=request.data or None, params=request.params or None, headers=request.headers, **self.httpx_kwargs, ) class SingletonSender(SyncSender): """ Use one session for all instances and requests. Parameters ---------- requests_kwargs keyword arguments for :meth:`requests.Session.send` """ session = Session() def __init__(self, **requests_kwargs): from tekore import default_requests_kwargs self.requests_kwargs = requests_kwargs or default_requests_kwargs def send(self, request: Request) -> Response: """Send request with global session.""" prepared = SingletonSender.session.prepare_request(request) return SingletonSender.session.send(prepared, **self.requests_kwargs) class AsyncSingletonSender(AsyncSender): """ Use one client for all instances and requests. Parameters ---------- httpx_kwargs keyword arguments for :meth:`httpx.AsyncClient.request` """ client = AsyncClient() def __init__(self, **httpx_kwargs): from tekore import default_httpx_kwargs self.httpx_kwargs = httpx_kwargs or default_httpx_kwargs async def send(self, request: Request) -> Response: """Send request with global client.""" return await AsyncSingletonSender.client.request( request.method, request.url, data=request.data or None, params=request.params or None, headers=request.headers, **self.httpx_kwargs, ) class PersistentSender(SyncSender): """ Use a per-instance session to send requests. Parameters ---------- session :class:`requests.Session` to use when sending requests requests_kwargs keyword arguments for :meth:`requests.Session.send` """ def __init__(self, session: Session = None, **requests_kwargs): from tekore import default_requests_kwargs self.requests_kwargs = requests_kwargs or default_requests_kwargs self.session = session or Session() def send(self, request: Request) -> Response: """Send request with instance session.""" prepared = self.session.prepare_request(request) return self.session.send(prepared, **self.requests_kwargs) def __del__(self): self.session.close() class AsyncPersistentSender(AsyncSender): """ Use a per-instance client to send requests asynchronously. Parameters ---------- session :class:`httpx.AsyncClient` to use when sending requests httpx_kwargs keyword arguments for :meth:`httpx.AsyncClient.request` """ def __init__(self, client: AsyncClient = None, **httpx_kwargs): from tekore import default_httpx_kwargs self.httpx_kwargs = httpx_kwargs or default_httpx_kwargs self.client = client or AsyncClient() async def send(self, request: Request) -> Response: """Send request with instance client.""" return await self.client.request( request.method, request.url, data=request.data or None, params=request.params or None, headers=request.headers, **self.httpx_kwargs, )