The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## 0.15.0
+
+### Added
+
+* Added support for event hooks. (Pull #1246)
+* Added support for authentication flows which require either sync or async I/O. (Pull #1217)
+* Added support for monitoring download progress with `response.num_bytes_downloaded`. (Pull #1268)
+* Added `Request(content=...)` for byte content, instead of overloading `Request(data=...)` (Pull #1266)
+* Added support for all URL components as parameter names when using `url.copy_with(...)`. (Pull #1285)
+* Neater split between automatically populated headers on `Request` instances, vs default `client.headers`. (Pull #1248)
+* Unclosed `AsyncClient` instances will now raise warnings if garbage collected. (Pull #1197)
+* Support `Response(content=..., text=..., html=..., json=...)` for creating usable response instances in code. (Pull #1265, #1297)
+* Support instantiating requests from the low-level transport API. (Pull #1293)
+* Raise errors on invalid URL types. (Pull #1259)
+
+### Changed
+
+* Cleaned up expected behaviour for URL escaping. `url.path` is now URL escaped. (Pull #1285)
+* Cleaned up expected behaviour for bytes vs str in URL components. `url.userinfo` and `url.query` are not URL escaped, and so return bytes. (Pull #1285)
+* Drop `url.authority` property in favour of `url.netloc`, since "authority" was semantically incorrect. (Pull #1285)
+* Drop `url.full_path` property in favour of `url.raw_path`, for better consistency with other parts of the API. (Pull #1285)
+* No longer use the `chardet` library for auto-detecting charsets, instead defaulting to a simpler approach when no charset is specified. (#1269)
+
+### Fixed
+
+* Swapped ordering of redirects and authentication flow. (Pull #1267)
+* `.netrc` lookups should use host, not host+port. (Pull #1298)
+
+### Removed
+
+* The `URLLib3Transport` class no longer exists. We've published it instead as an example of [a custom transport class](https://gist.github.com/florimondmanca/d56764d78d748eb9f73165da388e546e). (Pull #1182)
+* Drop `request.timer` attribute, which was being used internally to set `response.elapsed`. (Pull #1249)
+* Drop `response.decoder` attribute, which was being used internally. (Pull #1276)
+* `Request.prepare()` is now a private method. (Pull #1284)
+* The `Headers.getlist()` method had previously been deprecated in favour of `Headers.get_list()`. It is now fully removed.
+* The `QueryParams.getlist()` method had previously been deprecated in favour of `QueryParams.get_list()`. It is now fully removed.
+* The `URL.is_ssl` property had previously been deprecated in favour of `URL.scheme == "https"`. It is now fully removed.
+* The `httpx.PoolLimits` class had previously been deprecated in favour of `httpx.Limits`. It is now fully removed.
+* The `max_keepalive` setting had previously been deprecated in favour of the more explicit `max_keepalive_connections`. It is now fully removed.
+* The verbose `httpx.Timeout(5.0, connect_timeout=60.0)` style had previously been deprecated in favour of `httpx.Timeout(5.0, connect=60.0)`. It is now fully removed.
+* Support for instantiating a timeout config missing some defaults, such as `httpx.Timeout(connect=60.0)`, had previously been deprecated in favour of enforcing a more explicit style, such as `httpx.Timeout(5.0, connect=60.0)`. This is now strictly enforced.
+
## 0.14.3 (September 2nd, 2020)
### Added
from ._api import delete, get, head, options, patch, post, put, request, stream
from ._auth import Auth, BasicAuth, DigestAuth
from ._client import AsyncClient, Client
-from ._config import Limits, PoolLimits, Proxy, Timeout, create_ssl_context
+from ._config import Limits, Proxy, Timeout, create_ssl_context
from ._exceptions import (
CloseError,
ConnectError,
"NotRedirectResponse",
"options",
"patch",
- "PoolLimits",
"PoolTimeout",
"post",
"ProtocolError",
__title__ = "httpx"
__description__ = "A next generation HTTP client, for Python 3."
-__version__ = "0.14.3"
+__version__ = "0.15.0"
timer.sync_start()
with map_exceptions(HTTPCORE_EXC_MAP, request=request):
- (
- http_version,
- status_code,
- reason_phrase,
- headers,
- stream,
- ) = transport.request(
+ (status_code, headers, stream, ext) = transport.request(
request.method.encode(),
request.url.raw,
headers=request.headers.raw,
stream=request.stream, # type: ignore
- timeout=timeout.as_dict(),
+ ext={"timeout": timeout.as_dict()},
)
def on_close(response: Response) -> None:
response = Response(
status_code,
- http_version=http_version.decode("ascii"),
headers=headers,
stream=stream, # type: ignore
+ ext=ext,
request=request,
on_close=on_close,
)
await timer.async_start()
with map_exceptions(HTTPCORE_EXC_MAP, request=request):
- (
- http_version,
- status_code,
- reason_phrase,
- headers,
- stream,
- ) = await transport.request(
+ (status_code, headers, stream, ext,) = await transport.arequest(
request.method.encode(),
request.url.raw,
headers=request.headers.raw,
stream=request.stream, # type: ignore
- timeout=timeout.as_dict(),
+ ext={"timeout": timeout.as_dict()},
)
async def on_close(response: Response) -> None:
response = Response(
status_code,
- http_version=http_version.decode("ascii"),
headers=headers,
stream=stream, # type: ignore
+ ext=ext,
request=request,
on_close=on_close,
)
import os
import ssl
import typing
-import warnings
from base64 import b64encode
from pathlib import Path
from ._models import URL, Headers
from ._types import CertTypes, HeaderTypes, TimeoutTypes, URLTypes, VerifyTypes
-from ._utils import get_ca_bundle_from_env, get_logger, warn_deprecated
+from ._utils import get_ca_bundle_from_env, get_logger
DEFAULT_CIPHERS = ":".join(
[
read: typing.Union[None, float, UnsetType] = UNSET,
write: typing.Union[None, float, UnsetType] = UNSET,
pool: typing.Union[None, float, UnsetType] = UNSET,
- # Deprecated aliases.
- connect_timeout: typing.Union[None, float, UnsetType] = UNSET,
- read_timeout: typing.Union[None, float, UnsetType] = UNSET,
- write_timeout: typing.Union[None, float, UnsetType] = UNSET,
- pool_timeout: typing.Union[None, float, UnsetType] = UNSET,
):
- if not isinstance(connect_timeout, UnsetType):
- warn_deprecated(
- "httpx.Timeout(..., connect_timeout=...) is deprecated and will "
- "raise errors in a future version. "
- "Use httpx.Timeout(..., connect=...) instead."
- )
- connect = connect_timeout
-
- if not isinstance(read_timeout, UnsetType):
- warn_deprecated(
- "httpx.Timeout(..., read_timeout=...) is deprecated and will "
- "raise errors in a future version. "
- "Use httpx.Timeout(..., write=...) instead."
- )
- read = read_timeout
-
- if not isinstance(write_timeout, UnsetType):
- warn_deprecated(
- "httpx.Timeout(..., write_timeout=...) is deprecated and will "
- "raise errors in a future version. "
- "Use httpx.Timeout(..., write=...) instead."
- )
- write = write_timeout
-
- if not isinstance(pool_timeout, UnsetType):
- warn_deprecated(
- "httpx.Timeout(..., pool_timeout=...) is deprecated and will "
- "raise errors in a future version. "
- "Use httpx.Timeout(..., pool=...) instead."
- )
- pool = pool_timeout
-
if isinstance(timeout, Timeout):
# Passed as a single explicit Timeout.
assert connect is UNSET
self.pool = pool
else:
if isinstance(timeout, UnsetType):
- warnings.warn(
+ raise ValueError(
"httpx.Timeout must either include a default, or set all "
- "four parameters explicitly. Omitting the default argument "
- "is deprecated and will raise errors in a future version.",
- DeprecationWarning,
+ "four parameters explicitly."
)
- timeout = None
self.connect = timeout if isinstance(connect, UnsetType) else connect
self.read = timeout if isinstance(read, UnsetType) else read
self.write = timeout if isinstance(write, UnsetType) else write
*,
max_connections: int = None,
max_keepalive_connections: int = None,
- # Deprecated parameter naming, in favour of more explicit version:
- max_keepalive: int = None,
):
- if max_keepalive is not None:
- warnings.warn(
- "'max_keepalive' is deprecated. Use 'max_keepalive_connections'.",
- DeprecationWarning,
- )
- max_keepalive_connections = max_keepalive
-
self.max_connections = max_connections
self.max_keepalive_connections = max_keepalive_connections
)
-class PoolLimits(Limits):
- def __init__(self, **kwargs: typing.Any) -> None:
- warn_deprecated(
- "httpx.PoolLimits(...) is deprecated and will raise errors in the future. "
- "Use httpx.Limits(...) instead."
- )
- super().__init__(**kwargs)
-
-
class Proxy:
def __init__(
self, url: URLTypes, *, headers: HeaderTypes = None, mode: str = "DEFAULT"
import json as jsonlib
import typing
import urllib.request
-import warnings
from collections.abc import MutableMapping
from http.cookiejar import Cookie, CookieJar
from urllib.parse import parse_qsl, quote, unquote, urlencode
self.raw_path,
)
- @property
- def is_ssl(self) -> bool:
- message = 'URL.is_ssl() is pending deprecation. Use url.scheme == "https"'
- warnings.warn(message, DeprecationWarning)
- return self.scheme == "https"
-
@property
def is_absolute_url(self) -> bool:
"""
query_string = str(self)
return f"{class_name}({query_string!r})"
- def getlist(self, key: typing.Any) -> typing.List[str]:
- message = (
- "QueryParams.getlist() is pending deprecation. Use QueryParams.get_list()"
- )
- warnings.warn(message, DeprecationWarning)
- return self.get_list(key)
-
class Headers(typing.MutableMapping[str, str]):
"""
return f"{class_name}({as_dict!r}{encoding_str})"
return f"{class_name}({as_list!r}{encoding_str})"
- def getlist(self, key: str, split_commas: bool = False) -> typing.List[str]:
- message = "Headers.getlist() is pending deprecation. Use Headers.get_list()"
- warnings.warn(message, DeprecationWarning)
- return self.get_list(key, split_commas=split_commas)
-
class Request:
def __init__(
html: str = None,
json: typing.Any = None,
stream: ByteStream = None,
- http_version: str = None,
request: Request = None,
+ ext: dict = None,
history: typing.List["Response"] = None,
on_close: typing.Callable = None,
):
self.status_code = status_code
- self.http_version = http_version
self.headers = Headers(headers)
self._request: typing.Optional[Request] = request
self.call_next: typing.Optional[typing.Callable] = None
+ self.ext = {} if ext is None else ext
self.history = [] if history is None else list(history)
self._on_close = on_close
def request(self, value: Request) -> None:
self._request = value
+ @property
+ def http_version(self) -> str:
+ return self.ext.get("http_version", "HTTP/1.1")
+
@property
def reason_phrase(self) -> str:
- return codes.get_reason_phrase(self.status_code)
+ return self.ext.get("reason", codes.get_reason_phrase(self.status_code))
@property
def url(self) -> typing.Optional[URL]:
-from typing import TYPE_CHECKING, Callable, List, Mapping, Optional, Tuple, Union
+from typing import TYPE_CHECKING, Callable, List, Optional, Tuple, Union
import httpcore
import sniffio
self.root_path = root_path
self.client = client
- async def request(
+ async def arequest(
self,
method: bytes,
url: Tuple[bytes, bytes, Optional[int], bytes],
headers: List[Tuple[bytes, bytes]] = None,
stream: httpcore.AsyncByteStream = None,
- timeout: Mapping[str, Optional[float]] = None,
- ) -> Tuple[bytes, int, bytes, List[Tuple[bytes, bytes]], httpcore.AsyncByteStream]:
+ ext: dict = None,
+ ) -> Tuple[int, List[Tuple[bytes, bytes]], httpcore.AsyncByteStream, dict]:
headers = [] if headers is None else headers
stream = httpcore.PlainByteStream(content=b"") if stream is None else stream
assert response_headers is not None
stream = httpcore.PlainByteStream(content=b"".join(body_parts))
+ ext = {}
- return (b"HTTP/1.1", status_code, b"", response_headers, stream)
+ return (status_code, response_headers, stream, ext)
url: typing.Tuple[bytes, bytes, typing.Optional[int], bytes],
headers: typing.List[typing.Tuple[bytes, bytes]] = None,
stream: httpcore.SyncByteStream = None,
- timeout: typing.Mapping[str, typing.Optional[float]] = None,
+ ext: dict = None,
) -> typing.Tuple[
- bytes,
- int,
- bytes,
- typing.List[typing.Tuple[bytes, bytes]],
- httpcore.SyncByteStream,
+ int, typing.List[typing.Tuple[bytes, bytes]], httpcore.SyncByteStream, dict
]:
headers = [] if headers is None else headers
stream = httpcore.PlainByteStream(content=b"") if stream is None else stream
for key, value in seen_response_headers
]
stream = httpcore.IteratorByteStream(iterator=result)
+ ext = {}
- return (b"HTTP/1.1", status_code, b"", headers, stream)
+ return (status_code, headers, stream, ext)
"certifi",
"sniffio",
"rfc3986[idna2008]>=1.3,<2",
- "httpcore==0.10.*",
+ "httpcore==0.11.*",
],
extras_require={
"http2": "h2==3.*",
import httpx
from httpx import URL, Auth, BasicAuth, DigestAuth, ProtocolError, Request, Response
-from tests.utils import AsyncMockTransport, MockTransport
+from tests.utils import MockTransport
from ..common import FIXTURES_DIR
auth = ("tomchristie", "password123")
app = App()
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
url = "https://tomchristie:password123@example.org/"
app = App()
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url)
assert response.status_code == 200
auth = ("tomchristie", "password123")
app = App()
- async with httpx.AsyncClient(
- transport=AsyncMockTransport(app), auth=auth
- ) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app), auth=auth) as client:
response = await client.get(url)
assert response.status_code == 200
request.headers["Authorization"] = "Token 123"
return request
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
url = "http://netrcexample.org"
app = App()
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url)
assert response.status_code == 200
url = "http://netrcexample.org"
app = App()
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, headers={"Authorization": "Override"})
assert response.status_code == 200
app = App()
async with httpx.AsyncClient(
- transport=AsyncMockTransport(app), trust_env=False
+ transport=MockTransport(app), trust_env=False
) as client:
response = await client.get(url)
assert response.json() == {"auth": None}
async with httpx.AsyncClient(
- transport=AsyncMockTransport(app), trust_env=True
+ transport=MockTransport(app), trust_env=True
) as client:
response = await client.get(url)
auth = ("tomchristie", "password123")
app = App()
- async with httpx.AsyncClient(
- transport=AsyncMockTransport(app), auth=auth
- ) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app), auth=auth) as client:
response = await client.get(url, auth=None)
assert response.status_code == 200
auth = ("example-username", "example-password")
app = App()
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert "'authorization': '[secure]'" in str(response.request.headers)
async def test_auth_property() -> None:
app = App()
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
assert client.auth is None
client.auth = ("tomchristie", "password123") # type: ignore
with pytest.raises(TypeError):
client = httpx.AsyncClient(
- transport=AsyncMockTransport(app),
+ transport=MockTransport(app),
auth="not a tuple, not a callable", # type: ignore
)
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
with pytest.raises(TypeError):
await client.get(auth="not a tuple, not a callable") # type: ignore
auth = DigestAuth(username="tomchristie", password="password123")
app = App()
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth_header = 'Digest realm="realm@host.com",qop="auth",nonce="abc",opaque="xyz"'
app = App(auth_header=auth_header, status_code=200)
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth = DigestAuth(username="tomchristie", password="password123")
app = App(auth_header="", status_code=401)
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 401
auth = DigestAuth(username="tomchristie", password="password123")
app = DigestApp(algorithm=algorithm)
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth = DigestAuth(username="tomchristie", password="password123")
app = DigestApp(qop="")
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth = DigestAuth(username="tomchristie", password="password123")
app = DigestApp(qop=qop)
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth = DigestAuth(username="tomchristie", password="password123")
app = DigestApp(qop="auth-int")
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
with pytest.raises(NotImplementedError):
await client.get(url, auth=auth)
auth = DigestAuth(username="tomchristie", password="password123")
app = DigestApp(qop="not-auth")
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
with pytest.raises(ProtocolError):
await client.get(url, auth=auth)
auth = DigestAuth(username="tomchristie", password="password123")
app = DigestApp(send_response_after_attempt=2)
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 401
auth = DigestAuth(username="tomchristie", password="password123")
app = App(auth_header=auth_header, status_code=401)
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
with pytest.raises(ProtocolError):
await client.get(url, auth=auth)
auth = RepeatAuth(repeat=2)
app = App(auth_header="abc")
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
async def streaming_body():
yield b"Example request body" # pragma: nocover
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
with pytest.raises(httpx.StreamConsumed):
await client.post(url, data=streaming_body(), auth=auth)
auth = ResponseBodyAuth("xyz")
app = App()
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth = SyncOrAsyncAuth()
app = App()
- async with httpx.AsyncClient(transport=AsyncMockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
client = httpx.Client(base_url="https://www.example.com/")
request = client.build_request("GET", "http://www.example.com/")
assert request.url == "http://www.example.com/"
- with pytest.warns(DeprecationWarning):
- assert not request.url.is_ssl
def test_merge_relative_url():
import pytest
import httpx
-from tests.utils import AsyncMockTransport, MockTransport
+from tests.utils import MockTransport
def app(request: httpx.Request) -> httpx.Response:
event_hooks = {"request": [on_request], "response": [on_response]}
async with httpx.AsyncClient(
- event_hooks=event_hooks, transport=AsyncMockTransport(app)
+ event_hooks=event_hooks, transport=MockTransport(app)
) as http:
await http.get("http://127.0.0.1:8000/", auth=("username", "password"))
event_hooks = {"response": [raise_on_4xx_5xx]}
async with httpx.AsyncClient(
- event_hooks=event_hooks, transport=AsyncMockTransport(app)
+ event_hooks=event_hooks, transport=MockTransport(app)
) as http:
try:
await http.get("http://127.0.0.1:8000/status/400")
event_hooks = {"request": [on_request], "response": [on_response]}
async with httpx.AsyncClient(
- event_hooks=event_hooks, transport=AsyncMockTransport(app)
+ event_hooks=event_hooks, transport=MockTransport(app)
) as http:
await http.get("http://127.0.0.1:8000/redirect", auth=("username", "password"))
import pytest
import httpx
-from tests.utils import AsyncMockTransport, MockTransport
+from tests.utils import MockTransport
def redirects(request: httpx.Request) -> httpx.Response:
@pytest.mark.usefixtures("async_environment")
async def test_async_too_many_redirects():
- async with httpx.AsyncClient(transport=AsyncMockTransport(redirects)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(redirects)) as client:
with pytest.raises(httpx.TooManyRedirects):
await client.get("https://example.org/multiple_redirects?count=21")
@pytest.mark.usefixtures("async_environment")
async def test_async_too_many_redirects_calling_next():
- async with httpx.AsyncClient(transport=AsyncMockTransport(redirects)) as client:
+ async with httpx.AsyncClient(transport=MockTransport(redirects)) as client:
url = "https://example.org/multiple_redirects?count=21"
response = await client.get(url, allow_redirects=False)
with pytest.raises(httpx.TooManyRedirects):
assert h.get("nope", default=None) is None
assert h.get_list("a") == ["123", "456"]
- with pytest.warns(DeprecationWarning):
- assert h.getlist("a") == ["123", "456"]
-
assert list(h.keys()) == ["a", "b"]
assert list(h.values()) == ["123, 456", "789"]
assert list(h.items()) == [("a", "123, 456"), ("b", "789")]
assert q.get("nope", default=None) is None
assert q.get_list("a") == ["123", "456"]
- with pytest.warns(DeprecationWarning):
- assert q.getlist("a") == ["123", "456"]
-
assert list(q.keys()) == ["a", "b"]
assert list(q.values()) == ["456", "789"]
assert list(q.items()) == [("a", "456"), ("b", "789")]
assert limits == httpx.Limits(max_connections=100)
-def test_pool_limits_deprecated():
- with pytest.warns(DeprecationWarning):
- httpx.PoolLimits()
-
-
-def test_max_keepalive_deprecated():
- with pytest.warns(DeprecationWarning):
- httpx.Limits(max_keepalive=50)
-
-
def test_timeout_eq():
timeout = httpx.Timeout(timeout=5.0)
assert timeout == httpx.Timeout(timeout=5.0)
def test_timeout_missing_default():
- with pytest.warns(DeprecationWarning):
- timeout = httpx.Timeout(pool=60.0)
- assert timeout == httpx.Timeout(timeout=(None, None, None, 60.0))
+ with pytest.raises(ValueError):
+ httpx.Timeout(pool=60.0)
def test_timeout_from_tuple():
async with client.stream("GET", server.url):
with pytest.raises(httpx.PoolTimeout):
await client.get("http://localhost:8000/")
-
-
-def test_deprecated_verbose_timeout_params():
- with pytest.warns(DeprecationWarning):
- httpx.Timeout(None, read_timeout=1.0)
-
- with pytest.warns(DeprecationWarning):
- httpx.Timeout(None, write_timeout=1.0)
-
- with pytest.warns(DeprecationWarning):
- httpx.Timeout(None, connect_timeout=1.0)
-
- with pytest.warns(DeprecationWarning):
- httpx.Timeout(None, pool_timeout=1.0)
import contextlib
import logging
import os
-from typing import Callable, List, Mapping, Optional, Tuple
+from typing import Callable, List, Optional, Tuple
import httpcore
logging.getLogger("httpx").handlers = []
-class MockTransport(httpcore.SyncHTTPTransport):
+class MockTransport(httpcore.SyncHTTPTransport, httpcore.AsyncHTTPTransport):
def __init__(self, handler: Callable) -> None:
self.handler = handler
url: Tuple[bytes, bytes, Optional[int], bytes],
headers: List[Tuple[bytes, bytes]] = None,
stream: httpcore.SyncByteStream = None,
- timeout: Mapping[str, Optional[float]] = None,
- ) -> Tuple[bytes, int, bytes, List[Tuple[bytes, bytes]], httpcore.SyncByteStream]:
+ ext: dict = None,
+ ) -> Tuple[int, List[Tuple[bytes, bytes]], httpcore.SyncByteStream, dict]:
request = httpx.Request(
method=method,
url=url,
request.read()
response = self.handler(request)
return (
- (response.http_version or "HTTP/1.1").encode("ascii"),
response.status_code,
- response.reason_phrase.encode("ascii"),
response.headers.raw,
response.stream,
+ response.ext,
)
-
-class AsyncMockTransport(httpcore.AsyncHTTPTransport):
- def __init__(self, handler: Callable) -> None:
- self.handler = handler
-
- async def request(
+ async def arequest(
self,
method: bytes,
url: Tuple[bytes, bytes, Optional[int], bytes],
headers: List[Tuple[bytes, bytes]] = None,
stream: httpcore.AsyncByteStream = None,
- timeout: Mapping[str, Optional[float]] = None,
- ) -> Tuple[bytes, int, bytes, List[Tuple[bytes, bytes]], httpcore.AsyncByteStream]:
+ ext: dict = None,
+ ) -> Tuple[int, List[Tuple[bytes, bytes]], httpcore.AsyncByteStream, dict]:
request = httpx.Request(
method=method,
url=url,
await request.aread()
response = self.handler(request)
return (
- (response.http_version or "HTTP/1.1").encode("ascii"),
response.status_code,
- response.reason_phrase.encode("ascii"),
response.headers.raw,
response.stream,
+ response.ext,
)