class RequestsClient(interfaces.HttpClientAdapter): """ A :py:mod:`requests` client that returns :py:class:`requests.Response` responses. Args: session (:py:class:`requests.Session`, optional): The session that should handle sending requests. If this argument is omitted or set to :py:obj:`None`, a new session will be created. """ exceptions = exceptions.Exceptions() def __init__(self, session=None, **kwargs): if session is None: session = self._create_session(**kwargs) self.__session = session def create_request(self): return Request(self.__session) @staticmethod @register.handler def with_session(session, *args, **kwargs): if isinstance(session, requests.Session): return RequestsClient(session, *args, **kwargs) @staticmethod def _create_session(**kwargs): session = requests.Session() atexit.register(session.close) for key in kwargs: setattr(session, key, kwargs[key]) return session
class HttpClientAdapter(object): """An adapter of an HTTP client library.""" __exceptions = exceptions.Exceptions() def create_request(self): raise NotImplementedError def io(self): """Returns the execution strategy for this client.""" raise NotImplementedError @property def exceptions(self): """ uplink.clients.exceptions.Exceptions: An enum of standard HTTP client errors that have been mapped to client specific exceptions. """ return self.__exceptions def send(self, request, template, data): class Client(io.Client): def send(self, r): return request.send(*r) return io.execute(Client(), self.io(), template, data)
class RequestsClient(interfaces.HttpClientAdapter): """ A :py:mod:`requests` client that returns :py:class:`requests.Response` responses. Args: session (:py:class:`requests.Session`, optional): The session that should handle sending requests. If this argument is omitted or set to :py:obj:`None`, a new session will be created. """ exceptions = exceptions.Exceptions() def __init__(self, session=None, **kwargs): self.__auto_created_session = False if session is None: session = self._create_session(**kwargs) self.__auto_created_session = True self.__session = session def __del__(self): if self.__auto_created_session: self.__session.close() @staticmethod @register.handler def with_session(session, *args, **kwargs): if isinstance(session, requests.Session): return RequestsClient(session, *args, **kwargs) @staticmethod def _create_session(**kwargs): session = requests.Session() for key in kwargs: setattr(session, key, kwargs[key]) return session def send(self, request): method, url, extras = request return self.__session.request(method=method, url=url, **extras) def apply_callback(self, callback, response): return callback(response) @staticmethod def io(): return io.BlockingStrategy()
class HttpClientAdapter(object): """An adapter of an HTTP client library.""" __exceptions = exceptions.Exceptions() def create_request(self): raise NotImplementedError @property def exceptions(self): """ uplink.clients.exceptions.Exceptions: An enum of standard HTTP client errors that have been mapped to client specific exceptions. """ return self.__exceptions
class HttpxClient(interfaces.HttpClientAdapter): exceptions = exceptions.Exceptions() def __init__(self, session=None, **kwargs): if httpx is None: raise NotImplementedError("httpx is not installed.") self._auto_created_session = False if session is None: session = httpx.AsyncClient(**kwargs) self._auto_created_session = True self._session = session self._sync_callback_adapter = threaded_callback def __del__(self): if self._auto_created_session: try: asyncio.get_event_loop().create_task(self._session.aclose()) except RuntimeError: asyncio.get_event_loop().run_until_complete( self._session.aclose()) @staticmethod @register.handler def with_session(session, *args, **kwargs): if isinstance(session, httpx.AsyncClient): return HttpxClient(session, *args, **kwargs) async def send(self, request): method, url, extras = request response = await self._session.request(method=method, url=url, **extras) return response def wrap_callback(self, callback): if not asyncio.iscoroutinefunction(callback): callback = self._sync_callback_adapter(callback) return callback def apply_callback(self, callback, response): return self.wrap_callback(callback)(response) @staticmethod def io(): return io.AsyncioStrategy()
class HttpClientAdapter(io.Client): """An adapter of an HTTP client library.""" __exceptions = exceptions.Exceptions() def io(self): """Returns the execution strategy for this client.""" raise NotImplementedError @property def exceptions(self): """ uplink.clients.exceptions.Exceptions: An enum of standard HTTP client errors that have been mapped to client specific exceptions. """ return self.__exceptions def send(self, request): raise NotImplementedError def apply_callback(self, callback, response): raise NotImplementedError
class AiohttpClient(interfaces.HttpClientAdapter): """ An :py:mod:`aiohttp` client that creates awaitable responses. Note: This client is an optional feature and requires the :py:mod:`aiohttp` package. For example, here's how to install this extra using pip:: $ pip install uplink[aiohttp] Args: session (:py:class:`aiohttp.ClientSession`, optional): The session that should handle sending requests. If this argument is omitted or set to :py:obj:`None`, a new session will be created. """ exceptions = exceptions.Exceptions() # TODO: Update docstrings to include aiohttp constructor parameters. __ARG_SPEC = collections.namedtuple("__ARG_SPEC", "args kwargs") def __init__(self, session=None, **kwargs): if aiohttp is None: raise NotImplementedError("aiohttp is not installed.") if session is None: session = self._create_session(**kwargs) self._session = session self._sync_callback_adapter = threaded_callback def create_request(self): return Request(self) @asyncio.coroutine def session(self): """Returns the underlying `aiohttp.ClientSession`.""" if isinstance(self._session, self.__ARG_SPEC): args, kwargs = self._session self._session = aiohttp.ClientSession(*args, **kwargs) # aiohttp v3.0 has made ClientSession.close a coroutine, # so we check whether it is one here and register it # to run appropriately at exit if asyncio.iscoroutinefunction(self._session.close): atexit.register( partial( asyncio.get_event_loop().run_until_complete, self._session.close(), )) else: atexit.register(self._session.close) return self._session def wrap_callback(self, callback): if not asyncio.iscoroutinefunction(callback): callback = self._sync_callback_adapter(callback) return callback @staticmethod @register.handler def with_session(session, *args, **kwargs): """ Builds a client instance if the first argument is a :py:class:`aiohttp.ClientSession`. Otherwise, return :py:obj:`None`. """ if isinstance(session, aiohttp.ClientSession): return AiohttpClient(session, *args, **kwargs) @classmethod def _create_session(cls, *args, **kwargs): return cls.__ARG_SPEC(args, kwargs) @classmethod def create(cls, *args, **kwargs): """ Builds a client instance with :py:class:`aiohttp.ClientSession` arguments. Instead of directly initializing this class with a :py:class:`aiohttp.ClientSession`, use this method to have the client lazily construct a session when sending the first request. Hence, this method guarantees that the creation of the underlying session happens inside of a coroutine. Args: *args: positional arguments that :py:class:`aiohttp.ClientSession` takes. **kwargs: keyword arguments that :py:class:`aiohttp.ClientSession` takes. """ session_build_args = cls._create_session(*args, **kwargs) return AiohttpClient(session=session_build_args)
def __init__(self, mock_client): self._mock_client = mock_client self._exceptions = client_exceptions.Exceptions() self._history = [] self._io = io.BlockingStrategy()
def __init__(self, request): self._mocked_request = request self._request = _HistoryMaintainingRequest(_MockRequest(request)) self._exceptions = client_exceptions.Exceptions() self._io = io.BlockingStrategy()