{"text": "Hello, world!"}
```
+### Mock transports
+
+During testing it can often be useful to be able to mock out a transport,
+and return pre-determined responses, rather than making actual network requests.
+
+The `httpx.MockTransport` class accepts a handler function, which can be used
+to map requests onto pre-determined responses:
+
+```python
+def handler(request):
+ return httpx.Response(200, json={"text": "Hello, world!"})
+
+
+# Switch to a mock transport, if the TESTING environment variable is set.
+if os.environ['TESTING'].upper() == "TRUE":
+ transport = httpx.MockTransport(handler)
+else:
+ transport = httpx.HTTPTransport()
+
+client = httpx.Client(transport=transport)
+```
+
+For more advanced use-cases you might want to take a look at either [the third-party
+mocking library, RESPX](https://lundberg.github.io/respx/), or the [pytest-httpx library](https://github.com/Colin-b/pytest_httpx).
+
### Mounting transports
You can also mount transports against given schemes or domains, to control
```python
# All requests to "example.org" should be mocked out.
# Other requests occur as usual.
-mounts = {"all://example.org": MockTransport()}
+def handler(request):
+ return httpx.Response(200, json={"text": "Hello, World!"})
+
+mounts = {"all://example.org": httpx.MockTransport(handler)}
client = httpx.Client(mounts=mounts)
```
from ._models import URL, Cookies, Headers, QueryParams, Request, Response
from ._status_codes import StatusCode, codes
from ._transports.asgi import ASGITransport
+from ._transports.mock import MockTransport
from ._transports.wsgi import WSGITransport
__all__ = [
"InvalidURL",
"Limits",
"LocalProtocolError",
+ "MockTransport",
"NetworkError",
"options",
"patch",
--- /dev/null
+from typing import Callable, List, Optional, Tuple
+
+import httpcore
+
+from .._models import Request
+
+
+class MockTransport(httpcore.SyncHTTPTransport, httpcore.AsyncHTTPTransport):
+ def __init__(self, handler: Callable) -> None:
+ self.handler = handler
+
+ def request(
+ self,
+ method: bytes,
+ url: Tuple[bytes, bytes, Optional[int], bytes],
+ headers: List[Tuple[bytes, bytes]] = None,
+ stream: httpcore.SyncByteStream = None,
+ ext: dict = None,
+ ) -> Tuple[int, List[Tuple[bytes, bytes]], httpcore.SyncByteStream, dict]:
+ request = Request(
+ method=method,
+ url=url,
+ headers=headers,
+ stream=stream,
+ )
+ request.read()
+ response = self.handler(request)
+ return (
+ response.status_code,
+ response.headers.raw,
+ response.stream,
+ response.ext,
+ )
+
+ async def arequest(
+ self,
+ method: bytes,
+ url: Tuple[bytes, bytes, Optional[int], bytes],
+ headers: List[Tuple[bytes, bytes]] = None,
+ stream: httpcore.AsyncByteStream = None,
+ ext: dict = None,
+ ) -> Tuple[int, List[Tuple[bytes, bytes]], httpcore.AsyncByteStream, dict]:
+ request = Request(
+ method=method,
+ url=url,
+ headers=headers,
+ stream=stream,
+ )
+ await request.aread()
+ response = self.handler(request)
+ return (
+ response.status_code,
+ response.headers.raw,
+ response.stream,
+ response.ext,
+ )
import pytest
import httpx
-from tests.utils import MockTransport
@pytest.mark.usefixtures("async_environment")
@pytest.mark.usefixtures("async_environment")
async def test_client_closed_state_using_implicit_open():
- client = httpx.AsyncClient(transport=MockTransport(hello_world))
+ client = httpx.AsyncClient(transport=httpx.MockTransport(hello_world))
assert not client.is_closed
await client.get("http://example.com")
@pytest.mark.usefixtures("async_environment")
async def test_client_closed_state_using_with_block():
- async with httpx.AsyncClient(transport=MockTransport(hello_world)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(hello_world)) as client:
assert not client.is_closed
await client.get("http://example.com")
@pytest.mark.usefixtures("async_environment")
async def test_deleting_unclosed_async_client_causes_warning():
- client = httpx.AsyncClient(transport=MockTransport(hello_world))
+ client = httpx.AsyncClient(transport=httpx.MockTransport(hello_world))
await client.get("http://example.com")
with pytest.warns(UserWarning):
del client
@pytest.mark.usefixtures("async_environment")
async def test_mounted_transport():
- transport = MockTransport(unmounted)
- mounts = {"custom://": MockTransport(mounted)}
+ transport = httpx.MockTransport(unmounted)
+ mounts = {"custom://": httpx.MockTransport(mounted)}
async with httpx.AsyncClient(transport=transport, mounts=mounts) as client:
response = await client.get("https://www.example.com")
import httpx
from httpx import URL, Auth, BasicAuth, DigestAuth, ProtocolError, Request, Response
-from tests.utils import MockTransport
from ..common import FIXTURES_DIR
auth = ("tomchristie", "password123")
app = App()
- async with httpx.AsyncClient(transport=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth = ("tomchristie", "password123")
app = App()
- async with httpx.AsyncClient(transport=MockTransport(app), auth=auth) as client:
+ async with httpx.AsyncClient(
+ transport=httpx.MockTransport(app), auth=auth
+ ) as client:
async with client.stream("GET", url) as response:
await response.aread()
url = "https://tomchristie:password123@example.org/"
app = App()
- async with httpx.AsyncClient(transport=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
response = await client.get(url)
assert response.status_code == 200
auth = ("tomchristie", "password123")
app = App()
- async with httpx.AsyncClient(transport=MockTransport(app), auth=auth) as client:
+ async with httpx.AsyncClient(
+ transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
response = await client.get(url, headers={"Authorization": "Override"})
assert response.status_code == 200
app = App()
async with httpx.AsyncClient(
- transport=MockTransport(app), trust_env=False
+ transport=httpx.MockTransport(app), trust_env=False
) as client:
response = await client.get(url)
assert response.json() == {"auth": None}
async with httpx.AsyncClient(
- transport=MockTransport(app), trust_env=True
+ transport=httpx.MockTransport(app), trust_env=True
) as client:
response = await client.get(url)
auth = ("tomchristie", "password123")
app = App()
- async with httpx.AsyncClient(transport=MockTransport(app), auth=auth) as client:
+ async with httpx.AsyncClient(
+ transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
assert client.auth is None
client.auth = ("tomchristie", "password123") # type: ignore
with pytest.raises(TypeError):
client = httpx.AsyncClient(
- transport=MockTransport(app),
+ transport=httpx.MockTransport(app),
auth="not a tuple, not a callable", # type: ignore
)
- async with httpx.AsyncClient(transport=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth_header = "Token ..."
app = App(auth_header=auth_header, status_code=401)
- client = httpx.Client(transport=MockTransport(app))
+ client = httpx.Client(transport=httpx.MockTransport(app))
response = client.get(url, auth=auth)
assert response.status_code == 401
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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
with pytest.raises(ProtocolError):
await client.get(url, auth=auth)
auth = DigestAuth(username="tomchristie", password="password123")
app = App(auth_header=auth_header, status_code=401)
- with httpx.Client(transport=MockTransport(app)) as client:
+ with httpx.Client(transport=httpx.MockTransport(app)) as client:
with pytest.raises(ProtocolError):
client.get(url, auth=auth)
auth = RepeatAuth(repeat=2)
app = App(auth_header="abc")
- async with httpx.AsyncClient(transport=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth = RepeatAuth(repeat=2)
app = App(auth_header="abc")
- with httpx.Client(transport=MockTransport(app)) as client:
+ with httpx.Client(transport=httpx.MockTransport(app)) as client:
response = 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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.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=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth = ResponseBodyAuth("xyz")
app = App()
- with httpx.Client(transport=MockTransport(app)) as client:
+ with httpx.Client(transport=httpx.MockTransport(app)) as client:
response = client.get(url, auth=auth)
assert response.status_code == 200
auth = SyncOrAsyncAuth()
app = App()
- async with httpx.AsyncClient(transport=MockTransport(app)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client:
response = await client.get(url, auth=auth)
assert response.status_code == 200
auth = SyncOrAsyncAuth()
app = App()
- with httpx.Client(transport=MockTransport(app)) as client:
+ with httpx.Client(transport=httpx.MockTransport(app)) as client:
response = client.get(url, auth=auth)
assert response.status_code == 200
import pytest
import httpx
-from tests.utils import MockTransport
def test_get(server):
def test_client_closed_state_using_implicit_open():
- client = httpx.Client(transport=MockTransport(hello_world))
+ client = httpx.Client(transport=httpx.MockTransport(hello_world))
assert not client.is_closed
client.get("http://example.com")
def test_client_closed_state_using_with_block():
- with httpx.Client(transport=MockTransport(hello_world)) as client:
+ with httpx.Client(transport=httpx.MockTransport(hello_world)) as client:
assert not client.is_closed
client.get("http://example.com")
url = "http://example.org/echo_headers"
headers = {"Example-Header": "example-value"}
- client = httpx.Client(transport=MockTransport(echo_raw_headers), headers=headers)
+ client = httpx.Client(
+ transport=httpx.MockTransport(echo_raw_headers), headers=headers
+ )
response = client.get(url)
assert response.status_code == 200
def test_mounted_transport():
- transport = MockTransport(unmounted)
- mounts = {"custom://": MockTransport(mounted)}
+ transport = httpx.MockTransport(unmounted)
+ mounts = {"custom://": httpx.MockTransport(mounted)}
client = httpx.Client(transport=transport, mounts=mounts)
def test_all_mounted_transport():
- mounts = {"all://": MockTransport(mounted)}
+ mounts = {"all://": httpx.MockTransport(mounted)}
client = httpx.Client(mounts=mounts)
from http.cookiejar import Cookie, CookieJar
import httpx
-from tests.utils import MockTransport
def get_and_set_cookies(request: httpx.Request) -> httpx.Response:
url = "http://example.org/echo_cookies"
cookies = {"example-name": "example-value"}
- client = httpx.Client(transport=MockTransport(get_and_set_cookies))
+ client = httpx.Client(transport=httpx.MockTransport(get_and_set_cookies))
response = client.get(url, cookies=cookies)
assert response.status_code == 200
)
cookies.set_cookie(cookie)
- client = httpx.Client(transport=MockTransport(get_and_set_cookies))
+ client = httpx.Client(transport=httpx.MockTransport(get_and_set_cookies))
response = client.get(url, cookies=cookies)
assert response.status_code == 200
)
cookies.set_cookie(cookie)
- client = httpx.Client(transport=MockTransport(get_and_set_cookies))
+ client = httpx.Client(transport=httpx.MockTransport(get_and_set_cookies))
client.cookies = cookies # type: ignore
response = client.get(url)
cookies = httpx.Cookies()
cookies["example-name"] = "example-value"
- client = httpx.Client(transport=MockTransport(get_and_set_cookies))
+ client = httpx.Client(transport=httpx.MockTransport(get_and_set_cookies))
response = client.get(url, cookies=cookies)
assert response.status_code == 200
def test_get_cookie() -> None:
url = "http://example.org/set_cookie"
- client = httpx.Client(transport=MockTransport(get_and_set_cookies))
+ client = httpx.Client(transport=httpx.MockTransport(get_and_set_cookies))
response = client.get(url)
assert response.status_code == 200
"""
Ensure that Client instances persist cookies between requests.
"""
- client = httpx.Client(transport=MockTransport(get_and_set_cookies))
+ client = httpx.Client(transport=httpx.MockTransport(get_and_set_cookies))
response = client.get("http://example.org/echo_cookies")
assert response.status_code == 200
import pytest
import httpx
-from tests.utils import MockTransport
def app(request: httpx.Request) -> httpx.Response:
event_hooks = {"request": [on_request], "response": [on_response]}
- with httpx.Client(event_hooks=event_hooks, transport=MockTransport(app)) as http:
+ with httpx.Client(
+ event_hooks=event_hooks, transport=httpx.MockTransport(app)
+ ) as http:
http.get("http://127.0.0.1:8000/", auth=("username", "password"))
assert events == [
event_hooks = {"response": [raise_on_4xx_5xx]}
- with httpx.Client(event_hooks=event_hooks, transport=MockTransport(app)) as http:
+ with httpx.Client(
+ event_hooks=event_hooks, transport=httpx.MockTransport(app)
+ ) as http:
try:
http.get("http://127.0.0.1:8000/status/400")
except httpx.HTTPStatusError as exc:
event_hooks = {"request": [on_request], "response": [on_response]}
async with httpx.AsyncClient(
- event_hooks=event_hooks, transport=MockTransport(app)
+ event_hooks=event_hooks, transport=httpx.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=MockTransport(app)
+ event_hooks=event_hooks, transport=httpx.MockTransport(app)
) as http:
try:
await http.get("http://127.0.0.1:8000/status/400")
event_hooks = {"request": [on_request], "response": [on_response]}
- with httpx.Client(event_hooks=event_hooks, transport=MockTransport(app)) as http:
+ with httpx.Client(
+ event_hooks=event_hooks, transport=httpx.MockTransport(app)
+ ) as http:
http.get("http://127.0.0.1:8000/redirect", auth=("username", "password"))
assert events == [
event_hooks = {"request": [on_request], "response": [on_response]}
async with httpx.AsyncClient(
- event_hooks=event_hooks, transport=MockTransport(app)
+ event_hooks=event_hooks, transport=httpx.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 MockTransport
def echo_headers(request: httpx.Request) -> httpx.Response:
url = "http://example.org/echo_headers"
headers = {"Example-Header": "example-value"}
- client = httpx.Client(transport=MockTransport(echo_headers), headers=headers)
+ client = httpx.Client(transport=httpx.MockTransport(echo_headers), headers=headers)
response = client.get(url)
assert response.status_code == 200
url = "http://example.org/echo_headers"
client_headers = {"User-Agent": "python-myclient/0.2.1"}
request_headers = {"X-Auth-Token": "FooBarBazToken"}
- client = httpx.Client(transport=MockTransport(echo_headers), headers=client_headers)
+ client = httpx.Client(
+ transport=httpx.MockTransport(echo_headers), headers=client_headers
+ )
response = client.get(url, headers=request_headers)
assert response.status_code == 200
url = "http://example.org/echo_headers"
client_headers = {"X-Auth-Token": "FooBar"}
request_headers = {"X-Auth-Token": "BazToken"}
- client = httpx.Client(transport=MockTransport(echo_headers), headers=client_headers)
+ client = httpx.Client(
+ transport=httpx.MockTransport(echo_headers), headers=client_headers
+ )
response = client.get(url, headers=request_headers)
assert response.status_code == 200
def test_header_update():
url = "http://example.org/echo_headers"
- client = httpx.Client(transport=MockTransport(echo_headers))
+ client = httpx.Client(transport=httpx.MockTransport(echo_headers))
first_response = client.get(url)
client.headers.update(
{"User-Agent": "python-myclient/0.2.1", "Another-Header": "AThing"}
"""
url = "http://example.org/echo_headers"
- client = httpx.Client(transport=MockTransport(echo_headers))
+ client = httpx.Client(transport=httpx.MockTransport(echo_headers))
del client.headers["User-Agent"]
response = client.get(url)
"""
url = "http://username:password@example.org:80/echo_headers"
- client = httpx.Client(transport=MockTransport(echo_headers))
+ client = httpx.Client(transport=httpx.MockTransport(echo_headers))
response = client.get(url)
assert response.status_code == 200
"""
url = "http://username:password@example.org:123/echo_headers"
- client = httpx.Client(transport=MockTransport(echo_headers))
+ client = httpx.Client(transport=httpx.MockTransport(echo_headers))
response = client.get(url)
assert response.status_code == 200
import httpx
-from tests.utils import MockTransport
def hello_world(request: httpx.Request) -> httpx.Response:
client_queryparams = "first=str"
request_queryparams = {"second": "dict"}
client = httpx.Client(
- transport=MockTransport(hello_world), params=client_queryparams
+ transport=httpx.MockTransport(hello_world), params=client_queryparams
)
response = client.get(url, params=request_queryparams)
import pytest
import httpx
-from tests.utils import MockTransport
def redirects(request: httpx.Request) -> httpx.Response:
def test_redirect_301():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
response = client.post("https://example.org/redirect_301")
assert response.status_code == httpx.codes.OK
assert response.url == "https://example.org/"
def test_redirect_302():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
response = client.post("https://example.org/redirect_302")
assert response.status_code == httpx.codes.OK
assert response.url == "https://example.org/"
def test_redirect_303():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
response = client.get("https://example.org/redirect_303")
assert response.status_code == httpx.codes.OK
assert response.url == "https://example.org/"
def test_next_request():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
request = client.build_request("POST", "https://example.org/redirect_303")
response = client.send(request, allow_redirects=False)
assert response.status_code == httpx.codes.SEE_OTHER
@pytest.mark.usefixtures("async_environment")
async def test_async_next_request():
- async with httpx.AsyncClient(transport=MockTransport(redirects)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(redirects)) as client:
request = client.build_request("POST", "https://example.org/redirect_303")
response = await client.send(request, allow_redirects=False)
assert response.status_code == httpx.codes.SEE_OTHER
"""
Contrary to Requests, redirects remain enabled by default for HEAD requests.
"""
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
response = client.head("https://example.org/redirect_302")
assert response.status_code == httpx.codes.OK
assert response.url == "https://example.org/"
def test_relative_redirect():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
response = client.get("https://example.org/relative_redirect")
assert response.status_code == httpx.codes.OK
assert response.url == "https://example.org/"
def test_malformed_redirect():
# https://github.com/encode/httpx/issues/771
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
response = client.get("http://example.org/malformed_redirect")
assert response.status_code == httpx.codes.OK
assert response.url == "https://example.org:443/"
def test_invalid_redirect():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
with pytest.raises(httpx.RemoteProtocolError):
client.get("http://example.org/invalid_redirect")
def test_no_scheme_redirect():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
response = client.get("https://example.org/no_scheme_redirect")
assert response.status_code == httpx.codes.OK
assert response.url == "https://example.org/"
def test_fragment_redirect():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
response = client.get("https://example.org/relative_redirect#fragment")
assert response.status_code == httpx.codes.OK
assert response.url == "https://example.org/#fragment"
def test_multiple_redirects():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
response = client.get("https://example.org/multiple_redirects?count=20")
assert response.status_code == httpx.codes.OK
assert response.url == "https://example.org/multiple_redirects"
@pytest.mark.usefixtures("async_environment")
async def test_async_too_many_redirects():
- async with httpx.AsyncClient(transport=MockTransport(redirects)) as client:
+ async with httpx.AsyncClient(transport=httpx.MockTransport(redirects)) as client:
with pytest.raises(httpx.TooManyRedirects):
await client.get("https://example.org/multiple_redirects?count=21")
def test_sync_too_many_redirects():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
with pytest.raises(httpx.TooManyRedirects):
client.get("https://example.org/multiple_redirects?count=21")
def test_redirect_loop():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
with pytest.raises(httpx.TooManyRedirects):
client.get("https://example.org/redirect_loop")
def test_cross_domain_redirect_with_auth_header():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
url = "https://example.com/cross_domain"
headers = {"Authorization": "abc"}
response = client.get(url, headers=headers)
def test_cross_domain_redirect_with_auth():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
url = "https://example.com/cross_domain"
response = client.get(url, auth=("user", "pass"))
assert response.url == "https://example.org/cross_domain_target"
def test_same_domain_redirect():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
url = "https://example.org/cross_domain"
headers = {"Authorization": "abc"}
response = client.get(url, headers=headers)
"""
A 308 redirect should preserve the request body.
"""
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
url = "https://example.org/redirect_body"
content = b"Example request body"
response = client.post(url, content=content)
"""
A 303 redirect should remove the request body.
"""
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
url = "https://example.org/redirect_no_body"
content = b"Example request body"
response = client.post(url, content=content)
def test_can_stream_if_no_redirect():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
url = "https://example.org/redirect_301"
with client.stream("GET", url, allow_redirects=False) as response:
assert not response.is_closed
def test_cannot_redirect_streaming_body():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
url = "https://example.org/redirect_body"
def streaming_body():
def test_cross_subdomain_redirect():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
url = "https://example.com/cross_subdomain"
response = client.get(url)
assert response.url == "https://www.example.org/cross_subdomain"
def test_redirect_cookie_behavior():
- client = httpx.Client(transport=MockTransport(cookie_sessions))
+ client = httpx.Client(transport=httpx.MockTransport(cookie_sessions))
# The client is not logged in.
response = client.get("https://example.com/")
def test_redirect_custom_scheme():
- client = httpx.Client(transport=MockTransport(redirects))
+ client = httpx.Client(transport=httpx.MockTransport(redirects))
with pytest.raises(httpx.UnsupportedProtocol) as e:
client.post("https://example.org/redirect_custom_scheme")
assert str(e.value) == "Scheme 'market' not supported."
import httpx
from httpx._content import encode_request
from httpx._utils import format_form_param
-from tests.utils import MockTransport
def echo_request_content(request: httpx.Request) -> httpx.Response:
@pytest.mark.parametrize(("value,output"), (("abc", b"abc"), (b"abc", b"abc")))
def test_multipart(value, output):
- client = httpx.Client(transport=MockTransport(echo_request_content))
+ client = httpx.Client(transport=httpx.MockTransport(echo_request_content))
# Test with a single-value 'data' argument, and a plain file 'files' argument.
data = {"text": value}
@pytest.mark.parametrize(("key"), (b"abc", 1, 2.3, None))
def test_multipart_invalid_key(key):
- client = httpx.Client(transport=MockTransport(echo_request_content))
+ client = httpx.Client(transport=httpx.MockTransport(echo_request_content))
data = {key: "abc"}
files = {"file": io.BytesIO(b"<file content>")}
@pytest.mark.parametrize(("value"), (1, 2.3, None, [None, "abc"], {None: "abc"}))
def test_multipart_invalid_value(value):
- client = httpx.Client(transport=MockTransport(echo_request_content))
+ client = httpx.Client(transport=httpx.MockTransport(echo_request_content))
data = {"text": value}
files = {"file": io.BytesIO(b"<file content>")}
def test_multipart_file_tuple():
- client = httpx.Client(transport=MockTransport(echo_request_content))
+ client = httpx.Client(transport=httpx.MockTransport(echo_request_content))
# Test with a list of values 'data' argument,
# and a tuple style 'files' argument.
import contextlib
import logging
import os
-from typing import Callable, List, Optional, Tuple
-import httpcore
-
-import httpx
from httpx import _utils
finally:
# Reset the logger so we don't have verbose output in all unit tests
logging.getLogger("httpx").handlers = []
-
-
-class MockTransport(httpcore.SyncHTTPTransport, httpcore.AsyncHTTPTransport):
- def __init__(self, handler: Callable) -> None:
- self.handler = handler
-
- def request(
- self,
- method: bytes,
- url: Tuple[bytes, bytes, Optional[int], bytes],
- headers: List[Tuple[bytes, bytes]] = None,
- stream: httpcore.SyncByteStream = None,
- ext: dict = None,
- ) -> Tuple[int, List[Tuple[bytes, bytes]], httpcore.SyncByteStream, dict]:
- request = httpx.Request(
- method=method,
- url=url,
- headers=headers,
- stream=stream,
- )
- request.read()
- response = self.handler(request)
- return (
- response.status_code,
- response.headers.raw,
- response.stream,
- response.ext,
- )
-
- async def arequest(
- self,
- method: bytes,
- url: Tuple[bytes, bytes, Optional[int], bytes],
- headers: List[Tuple[bytes, bytes]] = None,
- stream: httpcore.AsyncByteStream = None,
- ext: dict = None,
- ) -> Tuple[int, List[Tuple[bytes, bytes]], httpcore.AsyncByteStream, dict]:
- request = httpx.Request(
- method=method,
- url=url,
- headers=headers,
- stream=stream,
- )
- await request.aread()
- response = self.handler(request)
- return (
- response.status_code,
- response.headers.raw,
- response.stream,
- response.ext,
- )