From: Tom Christie Date: Mon, 2 Dec 2019 17:07:04 +0000 (+0000) Subject: Better HTTP/2 defaults. (#584) X-Git-Tag: 0.9.0~27 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=30229f16527882305d75ff2877c5b8831f6dc638;p=thirdparty%2Fhttpx.git Better HTTP/2 defaults. (#584) * Simplify HTTP version config, and switch HTTP/2 off by default * HTTP/2 docs * HTTP/2 interlinking in docs --- diff --git a/docs/advanced.md b/docs/advanced.md index d087bd25..9b1502fa 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -141,20 +141,6 @@ make modifications before sending the request. ``` -## Specify the version of the HTTP protocol - -One can set the version of the HTTP protocol for the client in case you want to make the requests using a specific version. - -For example: - -```python -async with httpx.Client(http_versions=["HTTP/1.1"]) as h11_client: - h11_response = await h11_client.get("https://myserver.com") - -async with httpx.Client(http_versions=["HTTP/2"]) as h2_client: - h2_response = await h2_client.get("https://myserver.com") -``` - ## .netrc Support HTTPX supports .netrc file. In `trust_env=True` cases, if auth parameter is @@ -367,7 +353,7 @@ More specifically, if a tuple is used as a value, it must have between 2 and 3 e - The first element is an optional file name which can be set to `None`. - The second element may be a file-like object or a string which will be automatically encoded in UTF-8. -- An optional third element can be used to specify the +- An optional third element can be used to specify the [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_Types) of the file being uploaded. If not specified HTTPX will attempt to guess the MIME type based on the file name, with unknown file extensions defaulting to "application/octet-stream". diff --git a/docs/http2.md b/docs/http2.md new file mode 100644 index 00000000..66d835d3 --- /dev/null +++ b/docs/http2.md @@ -0,0 +1,60 @@ +# HTTP/2 + +HTTP/2 is a major new iteration of the HTTP protocol, that provides a far more +efficient transport, with potential performance benefits. HTTP/2 does not change +the core semantics of the request or response, but alters the way that data is +sent to and from the server. + +Rather that the text format that HTTP/1.1 uses, HTTP/2 is a binary format. +The binary format provides full request and response multiplexing, and efficient +compression of HTTP headers. The stream multiplexing means that where HTTP/1.1 +requires one TCP stream for each concurrent request, HTTP/2 allows a single TCP +stream to handle multiple concurrent requests. + +HTTP/2 also provides support for functionality such as response prioritization, +and server push. + +For a comprehensive guide to HTTP/2 you may want to check out "[HTTP2 Explained](https://http2-explained.haxx.se/content/en/)". + +## Enabling HTTP/2 + +The HTTPX client provides provisional HTTP/2 support. + +HTTP/2 support is not enabled by default, because HTTP/1.1 is a mature, +battle-hardened transport layer. With HTTP/2 being newer and significantly more +complex, our implementation should be considered a less robust option at this +point in time. + +However, if you're issuing highly concurrent requests you might want to consider +trying out our HTTP/2 support. You can do so by instantiating a client with +HTTP/2 support enabled: + +```python +client = httpx.Client(http_2=True) +... +``` + +You can also instantiate a client as a context manager, to ensure that all +HTTP connections are nicely scoped, and will be closed once the context block +is exited. + +```python +async with httpx.Client(http_2=True) as client: + ... +``` + +## Inspecting the HTTP version + +Enabling HTTP/2 support on the client does not *necessarily* mean that your +requests and responses will be transported over HTTP/2, since both the client +*and* the server need to support HTTP/2. If you connect to a server that only +supports HTTP/1.1 the client will use a standard HTTP/1.1 connection instead. + +You can determine which version of the HTTP protocol was used by examining +the `.http_version` property on the response. + +```python +client = httpx.Client(http_2=True) +response = await client.get(...) +print(response.http_version) # "HTTP/1.0", "HTTP/1.1", or "HTTP/2". +``` diff --git a/docs/index.md b/docs/index.md index 846d58a4..c233494c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -64,7 +64,7 @@ HTTPX is a high performance asynchronous HTTP client, that builds on the well-established usability of `requests`, and gives you: * A broadly requests-compatible API. -* HTTP/2 and HTTP/1.1 support. +* HTTP/1.1 and [HTTP/2 support](http2.md). * Ability to [make requests directly to ASGI applications](advanced.md#calling-into-python-web-apps). * Strict timeouts everywhere. * Fully type annotated. @@ -92,7 +92,8 @@ Plus all the standard features of `requests`... For a run-through of all the basics, head over to the [QuickStart](quickstart.md). -For more advanced topics, see the [Advanced Usage](advanced.md) section. +For more advanced topics, see the [Advanced Usage](advanced.md) section, +or the [HTTP/2](http2.md) section. The [Developer Interface](api.md) provides a comprehensive API reference. diff --git a/httpx/__init__.py b/httpx/__init__.py index bda76ae3..0910545b 100644 --- a/httpx/__init__.py +++ b/httpx/__init__.py @@ -12,8 +12,6 @@ from .concurrency.base import ( from .config import ( USER_AGENT, CertTypes, - HTTPVersionConfig, - HTTPVersionTypes, PoolLimits, SSLConfig, TimeoutConfig, @@ -118,8 +116,6 @@ __all__ = [ "StatusCode", "codes", "TimeoutTypes", - "HTTPVersionTypes", - "HTTPVersionConfig", "AuthTypes", "Cookies", "CookieTypes", diff --git a/httpx/api.py b/httpx/api.py index 2ea1be62..893c3e73 100644 --- a/httpx/api.py +++ b/httpx/api.py @@ -81,11 +81,7 @@ async def request( ``` """ async with Client( - http_versions=["HTTP/1.1"], - cert=cert, - verify=verify, - timeout=timeout, - trust_env=trust_env, + cert=cert, verify=verify, timeout=timeout, trust_env=trust_env, ) as client: return await client.request( method=method, diff --git a/httpx/client.py b/httpx/client.py index 1fe4f6c0..28aa1767 100644 --- a/httpx/client.py +++ b/httpx/client.py @@ -12,7 +12,6 @@ from .config import ( DEFAULT_POOL_LIMITS, DEFAULT_TIMEOUT_CONFIG, CertTypes, - HTTPVersionTypes, PoolLimits, TimeoutTypes, VerifyTypes, @@ -79,8 +78,8 @@ class Client: to authenticate the client. Either a path to an SSL certificate file, or two-tuple of (certificate file, key file), or a three-tuple of (certificate file, key file, password). - * **http_versions** - *(optional)* A list of strings of HTTP protocol - versions to use when sending requests. eg. `http_versions=["HTTP/1.1"]` + * **http_2** - *(optional)* A boolean indicating if HTTP/2 support should be + enabled. Defaults to `False`. * **proxies** - *(optional)* A dictionary mapping HTTP protocols to proxy URLs. * **timeout** - *(optional)* The timeout configuration to use when sending @@ -111,7 +110,7 @@ class Client: cookies: CookieTypes = None, verify: VerifyTypes = True, cert: CertTypes = None, - http_versions: HTTPVersionTypes = None, + http_2: bool = False, proxies: ProxiesTypes = None, timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, pool_limits: PoolLimits = DEFAULT_POOL_LIMITS, @@ -134,7 +133,7 @@ class Client: verify=verify, cert=cert, timeout=timeout, - http_versions=http_versions, + http_2=http_2, pool_limits=pool_limits, backend=backend, trust_env=trust_env, @@ -167,7 +166,7 @@ class Client: verify=verify, cert=cert, timeout=timeout, - http_versions=http_versions, + http_2=http_2, pool_limits=pool_limits, backend=backend, trust_env=trust_env, @@ -833,13 +832,13 @@ def _proxies_to_dispatchers( verify: VerifyTypes, cert: typing.Optional[CertTypes], timeout: TimeoutTypes, - http_versions: typing.Optional[HTTPVersionTypes], + http_2: bool, pool_limits: PoolLimits, backend: ConcurrencyBackend, trust_env: bool, ) -> typing.Dict[str, Dispatcher]: def _proxy_from_url(url: URLTypes) -> Dispatcher: - nonlocal verify, cert, timeout, http_versions, pool_limits, backend, trust_env + nonlocal verify, cert, timeout, http_2, pool_limits, backend, trust_env url = URL(url) if url.scheme in ("http", "https"): return HTTPProxy( @@ -850,7 +849,7 @@ def _proxies_to_dispatchers( pool_limits=pool_limits, backend=backend, trust_env=trust_env, - http_versions=http_versions, + http_2=http_2, ) raise ValueError(f"Unknown proxy for {url!r}") diff --git a/httpx/config.py b/httpx/config.py index a32ae84d..cace3c20 100644 --- a/httpx/config.py +++ b/httpx/config.py @@ -13,15 +13,10 @@ VerifyTypes = typing.Union[str, bool, ssl.SSLContext] TimeoutTypes = typing.Union[ float, typing.Tuple[float, float, float, float], "TimeoutConfig" ] -HTTPVersionTypes = typing.Union[ - str, typing.List[str], typing.Tuple[str], "HTTPVersionConfig" -] USER_AGENT = f"python-httpx/{__version__}" -HTTP_VERSIONS_TO_ALPN_IDENTIFIERS = {"HTTP/1.1": "http/1.1", "HTTP/2": "h2"} - DEFAULT_CIPHERS = ":".join( [ "ECDHE+AESGCM", @@ -91,43 +86,35 @@ class SSLConfig: return self return SSLConfig(cert=cert, verify=verify) - def load_ssl_context( - self, http_versions: "HTTPVersionConfig" = None - ) -> ssl.SSLContext: - http_versions = HTTPVersionConfig() if http_versions is None else http_versions - + def load_ssl_context(self, http_2: bool = False) -> ssl.SSLContext: logger.trace( f"load_ssl_context " f"verify={self.verify!r} " f"cert={self.cert!r} " f"trust_env={self.trust_env!r} " - f"http_versions={http_versions!r}" + f"http_2={http_2!r}" ) if self.ssl_context is None: self.ssl_context = ( - self.load_ssl_context_verify(http_versions=http_versions) + self.load_ssl_context_verify(http_2=http_2) if self.verify - else self.load_ssl_context_no_verify(http_versions=http_versions) + else self.load_ssl_context_no_verify(http_2=http_2) ) assert self.ssl_context is not None return self.ssl_context - def load_ssl_context_no_verify( - self, http_versions: "HTTPVersionConfig" - ) -> ssl.SSLContext: + def load_ssl_context_no_verify(self, http_2: bool = False) -> ssl.SSLContext: """ Return an SSL context for unverified connections. """ - context = self._create_default_ssl_context(http_versions=http_versions) + context = self._create_default_ssl_context(http_2=http_2) context.verify_mode = ssl.CERT_NONE context.check_hostname = False return context - def load_ssl_context_verify( - self, http_versions: "HTTPVersionConfig" - ) -> ssl.SSLContext: + def load_ssl_context_verify(self, http_2: bool = False) -> ssl.SSLContext: """ Return an SSL context for verified connections. """ @@ -146,7 +133,7 @@ class SSLConfig: "invalid path: {}".format(self.verify) ) - context = self._create_default_ssl_context(http_versions=http_versions) + context = self._create_default_ssl_context(http_2=http_2) context.verify_mode = ssl.CERT_REQUIRED context.check_hostname = True @@ -175,9 +162,7 @@ class SSLConfig: return context - def _create_default_ssl_context( - self, http_versions: "HTTPVersionConfig" - ) -> ssl.SSLContext: + def _create_default_ssl_context(self, http_2: bool) -> ssl.SSLContext: """ Creates the default SSLContext object that's used for both verified and unverified connections. @@ -191,7 +176,8 @@ class SSLConfig: context.set_ciphers(DEFAULT_CIPHERS) if ssl.HAS_ALPN: - context.set_alpn_protocols(http_versions.alpn_identifiers) + alpn_idents = ["http/1.1", "h2"] if http_2 else ["http/1.1"] + context.set_alpn_protocols(alpn_idents) if hasattr(context, "keylog_filename"): keylogfile = os.environ.get("SSLKEYLOGFILE") @@ -288,52 +274,6 @@ class TimeoutConfig: ) -class HTTPVersionConfig: - """ - Configure which HTTP protocol versions are supported. - """ - - def __init__(self, http_versions: HTTPVersionTypes = None): - if http_versions is None: - http_versions = ["HTTP/1.1", "HTTP/2"] - - if isinstance(http_versions, str): - self.http_versions = {http_versions.upper()} - elif isinstance(http_versions, HTTPVersionConfig): - self.http_versions = http_versions.http_versions - elif isinstance(http_versions, typing.Iterable): - self.http_versions = { - version.upper() if isinstance(version, str) else version - for version in http_versions - } - else: - raise TypeError( - "HTTP version should be a string or list of strings, " - f"but got {type(http_versions)}" - ) - - for version in self.http_versions: - if version not in ("HTTP/1.1", "HTTP/2"): - raise ValueError(f"Unsupported HTTP version {version!r}.") - - if not self.http_versions: - raise ValueError("HTTP versions cannot be an empty list.") - - @property - def alpn_identifiers(self) -> typing.List[str]: - """ - Returns a list of supported ALPN identifiers. (One or more of "http/1.1", "h2"). - """ - return [ - HTTP_VERSIONS_TO_ALPN_IDENTIFIERS[version] for version in self.http_versions - ] - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - value = sorted(list(self.http_versions)) - return f"{class_name}({value!r})" - - class PoolLimits: """ Limits on the number of connections in a connection pool. diff --git a/httpx/dispatch/connection.py b/httpx/dispatch/connection.py index 6694caa2..0f05b2e8 100644 --- a/httpx/dispatch/connection.py +++ b/httpx/dispatch/connection.py @@ -7,8 +7,6 @@ from ..concurrency.base import ConcurrencyBackend from ..config import ( DEFAULT_TIMEOUT_CONFIG, CertTypes, - HTTPVersionConfig, - HTTPVersionTypes, SSLConfig, TimeoutConfig, TimeoutTypes, @@ -35,7 +33,7 @@ class HTTPConnection(Dispatcher): cert: CertTypes = None, trust_env: bool = None, timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - http_versions: HTTPVersionTypes = None, + http_2: bool = False, backend: ConcurrencyBackend = None, release_func: typing.Optional[ReleaseCallback] = None, uds: typing.Optional[str] = None, @@ -43,7 +41,7 @@ class HTTPConnection(Dispatcher): self.origin = Origin(origin) if isinstance(origin, str) else origin self.ssl = SSLConfig(cert=cert, verify=verify, trust_env=trust_env) self.timeout = TimeoutConfig(timeout) - self.http_versions = HTTPVersionConfig(http_versions) + self.http_2 = http_2 self.backend = AsyncioBackend() if backend is None else backend self.release_func = release_func self.uds = uds @@ -119,9 +117,7 @@ class HTTPConnection(Dispatcher): return None # Run the SSL loading in a threadpool, since it may make disk accesses. - return await self.backend.run_in_threadpool( - ssl.load_ssl_context, self.http_versions - ) + return await self.backend.run_in_threadpool(ssl.load_ssl_context, self.http_2) async def close(self) -> None: logger.trace("close_connection") diff --git a/httpx/dispatch/connection_pool.py b/httpx/dispatch/connection_pool.py index 32173301..fc44c413 100644 --- a/httpx/dispatch/connection_pool.py +++ b/httpx/dispatch/connection_pool.py @@ -6,7 +6,6 @@ from ..config import ( DEFAULT_POOL_LIMITS, DEFAULT_TIMEOUT_CONFIG, CertTypes, - HTTPVersionTypes, PoolLimits, TimeoutConfig, TimeoutTypes, @@ -88,7 +87,7 @@ class ConnectionPool(Dispatcher): trust_env: bool = None, timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, pool_limits: PoolLimits = DEFAULT_POOL_LIMITS, - http_versions: HTTPVersionTypes = None, + http_2: bool = False, backend: ConcurrencyBackend = None, uds: typing.Optional[str] = None, ): @@ -96,7 +95,7 @@ class ConnectionPool(Dispatcher): self.cert = cert self.timeout = TimeoutConfig(timeout) self.pool_limits = pool_limits - self.http_versions = http_versions + self.http_2 = http_2 self.is_closed = False self.trust_env = trust_env self.uds = uds @@ -150,7 +149,7 @@ class ConnectionPool(Dispatcher): verify=self.verify, cert=self.cert, timeout=self.timeout, - http_versions=self.http_versions, + http_2=self.http_2, backend=self.backend, release_func=self.release_connection, trust_env=self.trust_env, diff --git a/httpx/dispatch/proxy_http.py b/httpx/dispatch/proxy_http.py index 13eb4233..c51c009e 100644 --- a/httpx/dispatch/proxy_http.py +++ b/httpx/dispatch/proxy_http.py @@ -8,7 +8,6 @@ from ..config import ( DEFAULT_POOL_LIMITS, DEFAULT_TIMEOUT_CONFIG, CertTypes, - HTTPVersionTypes, PoolLimits, SSLConfig, TimeoutTypes, @@ -47,7 +46,7 @@ class HTTPProxy(ConnectionPool): trust_env: bool = None, timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, pool_limits: PoolLimits = DEFAULT_POOL_LIMITS, - http_versions: HTTPVersionTypes = None, + http_2: bool = False, backend: ConcurrencyBackend = None, ): @@ -58,7 +57,7 @@ class HTTPProxy(ConnectionPool): pool_limits=pool_limits, backend=backend, trust_env=trust_env, - http_versions=http_versions, + http_2=http_2, ) self.proxy_url = URL(proxy_url) @@ -134,7 +133,7 @@ class HTTPProxy(ConnectionPool): cert=self.cert, timeout=self.timeout, backend=self.backend, - http_versions=["HTTP/1.1"], # Short-lived 'connection' + http_2=False, # Short-lived 'connection' trust_env=self.trust_env, release_func=self.release_connection, ) diff --git a/mkdocs.yml b/mkdocs.yml index 0ddd8c85..a2a733c9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,6 +12,7 @@ nav: - Introduction: 'index.md' - QuickStart: 'quickstart.md' - Advanced Usage: 'advanced.md' + - HTTP/2 Support: 'http2.md' - Environment Variables: 'environment_variables.md' - Requests Compatibility: 'compatibility.md' - Developer Interface: 'api.md' diff --git a/tests/client/test_proxies.py b/tests/client/test_proxies.py index fc1e57a5..ede15a8f 100644 --- a/tests/client/test_proxies.py +++ b/tests/client/test_proxies.py @@ -36,7 +36,6 @@ def test_proxies_has_same_properties_as_dispatch(): cert="/path/to/cert", trust_env=False, timeout=30, - http_versions=["HTTP/1.1"], ) pool = client.dispatch proxy = client.proxies["all"] @@ -49,7 +48,6 @@ def test_proxies_has_same_properties_as_dispatch(): "cert", "timeout", "pool_limits", - "http_versions", "backend", ]: assert getattr(pool, prop) == getattr(proxy, prop) diff --git a/tests/dispatch/test_http2.py b/tests/dispatch/test_http2.py index 0c8c9177..86dcc8ff 100644 --- a/tests/dispatch/test_http2.py +++ b/tests/dispatch/test_http2.py @@ -27,7 +27,7 @@ def app(request): async def test_http2_get_request(): backend = MockHTTP2Backend(app=app) - async with Client(backend=backend) as client: + async with Client(backend=backend, http_2=True) as client: response = await client.get("http://example.org") assert response.status_code == 200 @@ -38,7 +38,7 @@ async def test_http2_get_request(): async def test_http2_post_request(): backend = MockHTTP2Backend(app=app) - async with Client(backend=backend) as client: + async with Client(backend=backend, http_2=True) as client: response = await client.post("http://example.org", data=b"") assert response.status_code == 200 @@ -54,7 +54,7 @@ async def test_http2_large_post_request(): backend = MockHTTP2Backend(app=app) data = b"a" * 100000 - async with Client(backend=backend) as client: + async with Client(backend=backend, http_2=True) as client: response = await client.post("http://example.org", data=data) assert response.status_code == 200 assert json.loads(response.content) == { @@ -68,7 +68,7 @@ async def test_http2_large_post_request(): async def test_http2_multiple_requests(): backend = MockHTTP2Backend(app=app) - async with Client(backend=backend) as client: + async with Client(backend=backend, http_2=True) as client: response_1 = await client.get("http://example.org/1") response_2 = await client.get("http://example.org/2") response_3 = await client.get("http://example.org/3") @@ -91,7 +91,7 @@ async def test_http2_reconnect(): """ backend = MockHTTP2Backend(app=app) - async with Client(backend=backend) as client: + async with Client(backend=backend, http_2=True) as client: response_1 = await client.get("http://example.org/1") backend.server.close_connection = True response_2 = await client.get("http://example.org/2") @@ -106,7 +106,7 @@ async def test_http2_reconnect(): async def test_http2_settings_in_handshake(backend): backend = MockHTTP2Backend(app=app, backend=backend) - async with Client(backend=backend) as client: + async with Client(backend=backend, http_2=True) as client: await client.get("http://example.org") h2_conn = backend.server.conn @@ -139,7 +139,7 @@ async def test_http2_settings_in_handshake(backend): async def test_http2_live_request(backend): - async with Client(backend=backend) as client: + async with Client(backend=backend, http_2=True) as client: try: resp = await client.get("https://nghttp2.org/httpbin/anything") except Timeout: diff --git a/tests/test_concurrency.py b/tests/test_concurrency.py index da43987f..52828dac 100644 --- a/tests/test_concurrency.py +++ b/tests/test_concurrency.py @@ -1,7 +1,7 @@ import pytest import trio -from httpx import AsyncioBackend, HTTPVersionConfig, SSLConfig, TimeoutConfig +from httpx import AsyncioBackend, SSLConfig, TimeoutConfig from httpx.concurrency.trio import TrioBackend from tests.concurrency import run_concurrently @@ -40,7 +40,7 @@ async def read_response(stream, timeout: float, should_contain: bytes) -> bytes: ], ) async def test_start_tls_on_tcp_socket_stream(https_server, backend, get_cipher): - ctx = SSLConfig().load_ssl_context_no_verify(HTTPVersionConfig()) + ctx = SSLConfig().load_ssl_context_no_verify() timeout = TimeoutConfig(5) stream = await backend.open_tcp_stream( @@ -72,7 +72,7 @@ async def test_start_tls_on_tcp_socket_stream(https_server, backend, get_cipher) ], ) async def test_start_tls_on_uds_socket_stream(https_uds_server, backend, get_cipher): - ctx = SSLConfig().load_ssl_context_no_verify(HTTPVersionConfig()) + ctx = SSLConfig().load_ssl_context_no_verify() timeout = TimeoutConfig(5) stream = await backend.open_uds_stream( diff --git a/tests/test_config.py b/tests/test_config.py index 6f8d808b..1835ec74 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -118,46 +118,6 @@ def test_ssl_repr(): assert repr(ssl) == "SSLConfig(cert=None, verify=False)" -def test_http_versions_repr(): - http_versions = httpx.HTTPVersionConfig() - assert repr(http_versions) == "HTTPVersionConfig(['HTTP/1.1', 'HTTP/2'])" - - -def test_http_versions_from_string(): - http_versions = httpx.HTTPVersionConfig("HTTP/1.1") - assert repr(http_versions) == "HTTPVersionConfig(['HTTP/1.1'])" - - -def test_http_versions_from_list(): - http_versions = httpx.HTTPVersionConfig(["http/1.1"]) - assert repr(http_versions) == "HTTPVersionConfig(['HTTP/1.1'])" - - -def test_http_versions_from_config(): - http_versions = httpx.HTTPVersionConfig(httpx.HTTPVersionConfig("HTTP/1.1")) - assert repr(http_versions) == "HTTPVersionConfig(['HTTP/1.1'])" - - -def test_invalid_http_version(): - with pytest.raises(ValueError): - httpx.HTTPVersionConfig("HTTP/9") - - -def test_invalid_http_version_type(): - with pytest.raises(TypeError): - httpx.HTTPVersionConfig(123) - - -def test_invalid_http_version_list_type(): - with pytest.raises(ValueError): - httpx.HTTPVersionConfig([123]) - - -def test_empty_http_version(): - with pytest.raises(ValueError): - httpx.HTTPVersionConfig([]) - - def test_limits_repr(): limits = httpx.PoolLimits(hard_limit=100) assert repr(limits) == "PoolLimits(soft_limit=None, hard_limit=100)" diff --git a/tests/test_multipart.py b/tests/test_multipart.py index 3936a05d..b5e2290a 100644 --- a/tests/test_multipart.py +++ b/tests/test_multipart.py @@ -10,7 +10,6 @@ from httpx import ( CertTypes, Client, Dispatcher, - HTTPVersionTypes, Request, Response, TimeoutTypes, @@ -26,7 +25,6 @@ class MockDispatch(Dispatcher): verify: VerifyTypes = None, cert: CertTypes = None, timeout: TimeoutTypes = None, - http_versions: HTTPVersionTypes = None, ) -> Response: content = await request.read() return Response(200, content=content)