From: Tom Christie Date: Wed, 21 Aug 2019 06:35:01 +0000 (+0100) Subject: Refactor interfaces (#252) X-Git-Tag: 0.7.2~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c0554e96d912944c51eb5d717944d37d884f4763;p=thirdparty%2Fhttpx.git Refactor interfaces (#252) * Move Dispatcher, AsyncDispatcher into dispatch/base.py * Move concurrency interfaces into concurrency/base.py --- diff --git a/httpx/__init__.py b/httpx/__init__.py index 69759f4d..ebacaad8 100644 --- a/httpx/__init__.py +++ b/httpx/__init__.py @@ -2,6 +2,13 @@ from .__version__ import __description__, __title__, __version__ from .api import delete, get, head, options, patch, post, put, request from .client import AsyncClient, Client from .concurrency.asyncio import AsyncioBackend +from .concurrency.base import ( + BaseBackgroundManager, + BasePoolSemaphore, + BaseReader, + BaseWriter, + ConcurrencyBackend, +) from .config import ( USER_AGENT, CertTypes, @@ -13,6 +20,7 @@ from .config import ( TimeoutTypes, VerifyTypes, ) +from .dispatch.base import AsyncDispatcher, Dispatcher from .dispatch.connection import HTTPConnection from .dispatch.connection_pool import ConnectionPool from .exceptions import ( @@ -32,15 +40,6 @@ from .exceptions import ( TooManyRedirects, WriteTimeout, ) -from .interfaces import ( - AsyncDispatcher, - BaseBackgroundManager, - BasePoolSemaphore, - BaseReader, - BaseWriter, - ConcurrencyBackend, - Dispatcher, -) from .models import ( URL, AsyncRequest, diff --git a/httpx/client.py b/httpx/client.py index 04dbfea5..f7a3c5db 100644 --- a/httpx/client.py +++ b/httpx/client.py @@ -6,6 +6,7 @@ import hstspreload from .auth import HTTPBasicAuth from .concurrency.asyncio import AsyncioBackend +from .concurrency.base import ConcurrencyBackend from .config import ( DEFAULT_MAX_REDIRECTS, DEFAULT_POOL_LIMITS, @@ -17,6 +18,7 @@ from .config import ( VerifyTypes, ) from .dispatch.asgi import ASGIDispatch +from .dispatch.base import AsyncDispatcher, Dispatcher from .dispatch.connection_pool import ConnectionPool from .dispatch.threaded import ThreadedDispatcher from .dispatch.wsgi import WSGIDispatch @@ -27,7 +29,6 @@ from .exceptions import ( RedirectLoop, TooManyRedirects, ) -from .interfaces import AsyncDispatcher, ConcurrencyBackend, Dispatcher from .models import ( URL, AsyncRequest, diff --git a/httpx/concurrency/asyncio.py b/httpx/concurrency/asyncio.py index 08e39839..f378e4d9 100644 --- a/httpx/concurrency/asyncio.py +++ b/httpx/concurrency/asyncio.py @@ -14,16 +14,17 @@ import ssl import typing from types import TracebackType -from ..config import PoolLimits, TimeoutConfig -from ..exceptions import ConnectTimeout, PoolTimeout, ReadTimeout, WriteTimeout -from ..interfaces import ( +from .base import ( BaseBackgroundManager, BasePoolSemaphore, BaseQueue, BaseReader, BaseWriter, ConcurrencyBackend, + TimeoutFlag, ) +from ..config import PoolLimits, TimeoutConfig +from ..exceptions import ConnectTimeout, PoolTimeout, ReadTimeout, WriteTimeout SSL_MONKEY_PATCH_APPLIED = False @@ -49,38 +50,6 @@ def ssl_monkey_patch() -> None: MonkeyPatch.write = _fixed_write -class TimeoutFlag: - """ - A timeout flag holds a state of either read-timeout or write-timeout mode. - - We use this so that we can attempt both reads and writes concurrently, while - only enforcing timeouts in one direction. - - During a request/response cycle we start in write-timeout mode. - - Once we've sent a request fully, or once we start seeing a response, - then we switch to read-timeout mode instead. - """ - - def __init__(self) -> None: - self.raise_on_read_timeout = False - self.raise_on_write_timeout = True - - def set_read_timeouts(self) -> None: - """ - Set the flag to read-timeout mode. - """ - self.raise_on_read_timeout = True - self.raise_on_write_timeout = False - - def set_write_timeouts(self) -> None: - """ - Set the flag to write-timeout mode. - """ - self.raise_on_read_timeout = False - self.raise_on_write_timeout = True - - class Reader(BaseReader): def __init__( self, stream_reader: asyncio.StreamReader, timeout: TimeoutConfig diff --git a/httpx/interfaces.py b/httpx/concurrency/base.py similarity index 56% rename from httpx/interfaces.py rename to httpx/concurrency/base.py index cdfc0726..1a6842b8 100644 --- a/httpx/interfaces.py +++ b/httpx/concurrency/base.py @@ -2,114 +2,39 @@ import ssl import typing from types import TracebackType -from .config import CertTypes, PoolLimits, TimeoutConfig, TimeoutTypes, VerifyTypes -from .models import ( - AsyncRequest, - AsyncRequestData, - AsyncResponse, - HeaderTypes, - QueryParamTypes, - Request, - RequestData, - Response, - URLTypes, -) - - -class AsyncDispatcher: - """ - Base class for async dispatcher classes, that handle sending the request. - - Stubs out the interface, as well as providing a `.request()` convenience - implementation, to make it easy to use or test stand-alone dispatchers, - without requiring a complete `Client` instance. - """ - - async def request( - self, - method: str, - url: URLTypes, - *, - data: AsyncRequestData = b"", - params: QueryParamTypes = None, - headers: HeaderTypes = None, - verify: VerifyTypes = None, - cert: CertTypes = None, - timeout: TimeoutTypes = None, - ) -> AsyncResponse: - request = AsyncRequest(method, url, data=data, params=params, headers=headers) - return await self.send(request, verify=verify, cert=cert, timeout=timeout) - - async def send( - self, - request: AsyncRequest, - verify: VerifyTypes = None, - cert: CertTypes = None, - timeout: TimeoutTypes = None, - ) -> AsyncResponse: - raise NotImplementedError() # pragma: nocover - - async def close(self) -> None: - pass # pragma: nocover - - async def __aenter__(self) -> "AsyncDispatcher": - return self - - async def __aexit__( - self, - exc_type: typing.Type[BaseException] = None, - exc_value: BaseException = None, - traceback: TracebackType = None, - ) -> None: - await self.close() +from ..config import PoolLimits, TimeoutConfig -class Dispatcher: +class TimeoutFlag: """ - Base class for synchronous dispatcher classes, that handle sending the request. + A timeout flag holds a state of either read-timeout or write-timeout mode. - Stubs out the interface, as well as providing a `.request()` convenience - implementation, to make it easy to use or test stand-alone dispatchers, - without requiring a complete `Client` instance. - """ - - def request( - self, - method: str, - url: URLTypes, - *, - data: RequestData = b"", - params: QueryParamTypes = None, - headers: HeaderTypes = None, - verify: VerifyTypes = None, - cert: CertTypes = None, - timeout: TimeoutTypes = None, - ) -> Response: - request = Request(method, url, data=data, params=params, headers=headers) - return self.send(request, verify=verify, cert=cert, timeout=timeout) - - def send( - self, - request: Request, - verify: VerifyTypes = None, - cert: CertTypes = None, - timeout: TimeoutTypes = None, - ) -> Response: - raise NotImplementedError() # pragma: nocover + We use this so that we can attempt both reads and writes concurrently, while + only enforcing timeouts in one direction. - def close(self) -> None: - pass # pragma: nocover + During a request/response cycle we start in write-timeout mode. - def __enter__(self) -> "Dispatcher": - return self + Once we've sent a request fully, or once we start seeing a response, + then we switch to read-timeout mode instead. + """ - def __exit__( - self, - exc_type: typing.Type[BaseException] = None, - exc_value: BaseException = None, - traceback: TracebackType = None, - ) -> None: - self.close() + def __init__(self) -> None: + self.raise_on_read_timeout = False + self.raise_on_write_timeout = True + + def set_read_timeouts(self) -> None: + """ + Set the flag to read-timeout mode. + """ + self.raise_on_read_timeout = True + self.raise_on_write_timeout = False + + def set_write_timeouts(self) -> None: + """ + Set the flag to write-timeout mode. + """ + self.raise_on_read_timeout = False + self.raise_on_write_timeout = True class BaseReader: diff --git a/httpx/dispatch/asgi.py b/httpx/dispatch/asgi.py index 5b6bcad6..bf926f48 100644 --- a/httpx/dispatch/asgi.py +++ b/httpx/dispatch/asgi.py @@ -1,9 +1,10 @@ import asyncio import typing +from .base import AsyncDispatcher +from ..concurrency.base import ConcurrencyBackend from ..concurrency.asyncio import AsyncioBackend from ..config import CertTypes, TimeoutTypes, VerifyTypes -from ..interfaces import AsyncDispatcher, ConcurrencyBackend from ..models import AsyncRequest, AsyncResponse diff --git a/httpx/dispatch/base.py b/httpx/dispatch/base.py new file mode 100644 index 00000000..d0baa514 --- /dev/null +++ b/httpx/dispatch/base.py @@ -0,0 +1,111 @@ +import typing +from types import TracebackType + +from ..config import CertTypes, TimeoutTypes, VerifyTypes +from ..models import ( + AsyncRequest, + AsyncRequestData, + AsyncResponse, + HeaderTypes, + QueryParamTypes, + Request, + RequestData, + Response, + URLTypes, +) + + +class AsyncDispatcher: + """ + Base class for async dispatcher classes, that handle sending the request. + + Stubs out the interface, as well as providing a `.request()` convenience + implementation, to make it easy to use or test stand-alone dispatchers, + without requiring a complete `Client` instance. + """ + + async def request( + self, + method: str, + url: URLTypes, + *, + data: AsyncRequestData = b"", + params: QueryParamTypes = None, + headers: HeaderTypes = None, + verify: VerifyTypes = None, + cert: CertTypes = None, + timeout: TimeoutTypes = None, + ) -> AsyncResponse: + request = AsyncRequest(method, url, data=data, params=params, headers=headers) + return await self.send(request, verify=verify, cert=cert, timeout=timeout) + + async def send( + self, + request: AsyncRequest, + verify: VerifyTypes = None, + cert: CertTypes = None, + timeout: TimeoutTypes = None, + ) -> AsyncResponse: + raise NotImplementedError() # pragma: nocover + + async def close(self) -> None: + pass # pragma: nocover + + async def __aenter__(self) -> "AsyncDispatcher": + return self + + async def __aexit__( + self, + exc_type: typing.Type[BaseException] = None, + exc_value: BaseException = None, + traceback: TracebackType = None, + ) -> None: + await self.close() + + +class Dispatcher: + """ + Base class for synchronous dispatcher classes, that handle sending the request. + + Stubs out the interface, as well as providing a `.request()` convenience + implementation, to make it easy to use or test stand-alone dispatchers, + without requiring a complete `Client` instance. + """ + + def request( + self, + method: str, + url: URLTypes, + *, + data: RequestData = b"", + params: QueryParamTypes = None, + headers: HeaderTypes = None, + verify: VerifyTypes = None, + cert: CertTypes = None, + timeout: TimeoutTypes = None, + ) -> Response: + request = Request(method, url, data=data, params=params, headers=headers) + return self.send(request, verify=verify, cert=cert, timeout=timeout) + + def send( + self, + request: Request, + verify: VerifyTypes = None, + cert: CertTypes = None, + timeout: TimeoutTypes = None, + ) -> Response: + raise NotImplementedError() # pragma: nocover + + def close(self) -> None: + pass # pragma: nocover + + def __enter__(self) -> "Dispatcher": + return self + + def __exit__( + self, + exc_type: typing.Type[BaseException] = None, + exc_value: BaseException = None, + traceback: TracebackType = None, + ) -> None: + self.close() diff --git a/httpx/dispatch/connection.py b/httpx/dispatch/connection.py index d82ea5db..36f96f80 100644 --- a/httpx/dispatch/connection.py +++ b/httpx/dispatch/connection.py @@ -2,7 +2,9 @@ import functools import ssl import typing +from .base import AsyncDispatcher from ..concurrency.asyncio import AsyncioBackend +from ..concurrency.base import ConcurrencyBackend from ..config import ( DEFAULT_TIMEOUT_CONFIG, CertTypes, @@ -13,7 +15,6 @@ from ..config import ( TimeoutTypes, VerifyTypes, ) -from ..interfaces import AsyncDispatcher, ConcurrencyBackend from ..models import AsyncRequest, AsyncResponse, Origin from .http2 import HTTP2Connection from .http11 import HTTP11Connection diff --git a/httpx/dispatch/connection_pool.py b/httpx/dispatch/connection_pool.py index b88d142c..0e14bf83 100644 --- a/httpx/dispatch/connection_pool.py +++ b/httpx/dispatch/connection_pool.py @@ -1,6 +1,8 @@ import typing +from .base import AsyncDispatcher from ..concurrency.asyncio import AsyncioBackend +from ..concurrency.base import ConcurrencyBackend from ..config import ( DEFAULT_POOL_LIMITS, DEFAULT_TIMEOUT_CONFIG, @@ -10,7 +12,6 @@ from ..config import ( TimeoutTypes, VerifyTypes, ) -from ..interfaces import AsyncDispatcher, ConcurrencyBackend from ..models import AsyncRequest, AsyncResponse, Origin from .connection import HTTPConnection diff --git a/httpx/dispatch/http11.py b/httpx/dispatch/http11.py index 46d7309c..554591f8 100644 --- a/httpx/dispatch/http11.py +++ b/httpx/dispatch/http11.py @@ -2,9 +2,8 @@ import typing import h11 -from ..concurrency.asyncio import TimeoutFlag +from ..concurrency.base import BaseReader, BaseWriter, ConcurrencyBackend, TimeoutFlag from ..config import TimeoutConfig, TimeoutTypes -from ..interfaces import BaseReader, BaseWriter, ConcurrencyBackend from ..models import AsyncRequest, AsyncResponse H11Event = typing.Union[ diff --git a/httpx/dispatch/http2.py b/httpx/dispatch/http2.py index 199ee8fa..bf258e3a 100644 --- a/httpx/dispatch/http2.py +++ b/httpx/dispatch/http2.py @@ -4,9 +4,8 @@ import typing import h2.connection import h2.events -from ..concurrency.asyncio import TimeoutFlag +from ..concurrency.base import BaseReader, BaseWriter, ConcurrencyBackend, TimeoutFlag from ..config import TimeoutConfig, TimeoutTypes -from ..interfaces import BaseReader, BaseWriter, ConcurrencyBackend from ..models import AsyncRequest, AsyncResponse diff --git a/httpx/dispatch/threaded.py b/httpx/dispatch/threaded.py index 60200109..81766087 100644 --- a/httpx/dispatch/threaded.py +++ b/httpx/dispatch/threaded.py @@ -1,5 +1,6 @@ +from .base import AsyncDispatcher, Dispatcher +from ..concurrency.base import ConcurrencyBackend from ..config import CertTypes, TimeoutTypes, VerifyTypes -from ..interfaces import AsyncDispatcher, ConcurrencyBackend, Dispatcher from ..models import ( AsyncRequest, AsyncRequestData, diff --git a/httpx/dispatch/wsgi.py b/httpx/dispatch/wsgi.py index e1109c05..0cbe1095 100644 --- a/httpx/dispatch/wsgi.py +++ b/httpx/dispatch/wsgi.py @@ -1,8 +1,8 @@ import io import typing +from .base import Dispatcher from ..config import CertTypes, TimeoutTypes, VerifyTypes -from ..interfaces import Dispatcher from ..models import Request, Response