import httpcore
import pytest
+import httpx
from httpx import (
URL,
- AsyncClient,
Auth,
BasicAuth,
- Client,
DigestAuth,
ProtocolError,
Request,
url = "https://example.org/"
auth = ("tomchristie", "password123")
- client = AsyncClient(transport=AsyncMockTransport())
- response = await client.get(url, auth=auth)
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ response = await client.get(url, auth=auth)
assert response.status_code == 200
assert response.json() == {"auth": "Basic dG9tY2hyaXN0aWU6cGFzc3dvcmQxMjM="}
async def test_basic_auth_in_url() -> None:
url = "https://tomchristie:password123@example.org/"
- client = AsyncClient(transport=AsyncMockTransport())
- response = await client.get(url)
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ response = await client.get(url)
assert response.status_code == 200
assert response.json() == {"auth": "Basic dG9tY2hyaXN0aWU6cGFzc3dvcmQxMjM="}
url = "https://example.org/"
auth = ("tomchristie", "password123")
- client = AsyncClient(transport=AsyncMockTransport(), auth=auth)
- response = await client.get(url)
+ async with httpx.AsyncClient(transport=AsyncMockTransport(), auth=auth) as client:
+ response = await client.get(url)
assert response.status_code == 200
assert response.json() == {"auth": "Basic dG9tY2hyaXN0aWU6cGFzc3dvcmQxMjM="}
request.headers["Authorization"] = "Token 123"
return request
- client = AsyncClient(transport=AsyncMockTransport())
- response = await client.get(url, auth=auth)
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ response = await client.get(url, auth=auth)
assert response.status_code == 200
assert response.json() == {"auth": "Token 123"}
os.environ["NETRC"] = str(FIXTURES_DIR / ".netrc")
url = "http://netrcexample.org"
- client = AsyncClient(transport=AsyncMockTransport())
- response = await client.get(url)
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ response = await client.get(url)
assert response.status_code == 200
assert response.json() == {
os.environ["NETRC"] = str(FIXTURES_DIR / ".netrc")
url = "http://netrcexample.org"
- client = AsyncClient(transport=AsyncMockTransport())
- response = await client.get(url, headers={"Authorization": "Override"})
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ response = await client.get(url, headers={"Authorization": "Override"})
assert response.status_code == 200
assert response.json() == {"auth": "Override"}
os.environ["NETRC"] = str(FIXTURES_DIR / ".netrc")
url = "http://netrcexample.org"
- client = AsyncClient(transport=AsyncMockTransport(), trust_env=False)
- response = await client.get(url)
+ async with httpx.AsyncClient(
+ transport=AsyncMockTransport(), trust_env=False
+ ) as client:
+ response = await client.get(url)
assert response.status_code == 200
assert response.json() == {"auth": None}
- client = AsyncClient(transport=AsyncMockTransport(), trust_env=True)
- response = await client.get(url)
+ async with httpx.AsyncClient(
+ transport=AsyncMockTransport(), trust_env=True
+ ) as client:
+ response = await client.get(url)
assert response.status_code == 200
assert response.json() == {
url = "https://example.org/"
auth = ("tomchristie", "password123")
- client = AsyncClient(transport=AsyncMockTransport(), auth=auth)
- response = await client.get(url, auth=None)
+ async with httpx.AsyncClient(transport=AsyncMockTransport(), auth=auth) as client:
+ response = await client.get(url, auth=None)
assert response.status_code == 200
assert response.json() == {"auth": None}
url = "https://example.org/"
auth = ("example-username", "example-password")
- client = AsyncClient(transport=AsyncMockTransport())
- response = await client.get(url, auth=auth)
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ response = await client.get(url, auth=auth)
assert "'authorization': '[secure]'" in str(response.request.headers)
@pytest.mark.asyncio
async def test_auth_property() -> None:
- client = AsyncClient(transport=AsyncMockTransport())
- assert client.auth is None
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ assert client.auth is None
- client.auth = ("tomchristie", "password123") # type: ignore
- assert isinstance(client.auth, BasicAuth)
+ client.auth = ("tomchristie", "password123") # type: ignore
+ assert isinstance(client.auth, BasicAuth)
- url = "https://example.org/"
- response = await client.get(url)
- assert response.status_code == 200
- assert response.json() == {"auth": "Basic dG9tY2hyaXN0aWU6cGFzc3dvcmQxMjM="}
+ url = "https://example.org/"
+ response = await client.get(url)
+ assert response.status_code == 200
+ assert response.json() == {"auth": "Basic dG9tY2hyaXN0aWU6cGFzc3dvcmQxMjM="}
@pytest.mark.asyncio
async def test_auth_invalid_type() -> None:
with pytest.raises(TypeError):
- client = AsyncClient(
+ client = httpx.AsyncClient(
transport=AsyncMockTransport(),
auth="not a tuple, not a callable", # type: ignore
)
- client = AsyncClient(transport=AsyncMockTransport())
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ with pytest.raises(TypeError):
+ await client.get(auth="not a tuple, not a callable") # type: ignore
- with pytest.raises(TypeError):
- await client.get(auth="not a tuple, not a callable") # type: ignore
-
- with pytest.raises(TypeError):
- client.auth = "not a tuple, not a callable" # type: ignore
+ with pytest.raises(TypeError):
+ client.auth = "not a tuple, not a callable" # type: ignore
@pytest.mark.asyncio
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(transport=AsyncMockTransport())
- response = await client.get(url, auth=auth)
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ response = await client.get(url, auth=auth)
assert response.status_code == 200
assert response.json() == {"auth": None}
auth = DigestAuth(username="tomchristie", password="password123")
auth_header = b'Digest realm="realm@host.com",qop="auth",nonce="abc",opaque="xyz"'
- client = AsyncClient(
+ async with httpx.AsyncClient(
transport=AsyncMockTransport(auth_header=auth_header, status_code=200)
- )
- response = await client.get(url, auth=auth)
+ ) as client:
+ response = await client.get(url, auth=auth)
assert response.status_code == 200
assert response.json() == {"auth": None}
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(transport=AsyncMockTransport(auth_header=b"", status_code=401))
- response = await client.get(url, auth=auth)
+ async with httpx.AsyncClient(
+ transport=AsyncMockTransport(auth_header=b"", status_code=401)
+ ) as client:
+ response = await client.get(url, auth=auth)
assert response.status_code == 401
assert response.json() == {"auth": None}
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(transport=MockDigestAuthTransport(algorithm=algorithm))
- response = await client.get(url, auth=auth)
+ async with httpx.AsyncClient(
+ transport=MockDigestAuthTransport(algorithm=algorithm)
+ ) as client:
+ response = await client.get(url, auth=auth)
assert response.status_code == 200
assert len(response.history) == 1
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(transport=MockDigestAuthTransport(qop=""))
- response = await client.get(url, auth=auth)
+ async with httpx.AsyncClient(transport=MockDigestAuthTransport(qop="")) as client:
+ response = await client.get(url, auth=auth)
assert response.status_code == 200
assert len(response.history) == 1
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(transport=MockDigestAuthTransport(qop=qop))
- response = await client.get(url, auth=auth)
+ async with httpx.AsyncClient(transport=MockDigestAuthTransport(qop=qop)) as client:
+ response = await client.get(url, auth=auth)
assert response.status_code == 200
assert len(response.history) == 1
async def test_digest_auth_qop_auth_int_not_implemented() -> None:
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(transport=MockDigestAuthTransport(qop="auth-int"))
- with pytest.raises(NotImplementedError):
- await client.get(url, auth=auth)
+ async with httpx.AsyncClient(
+ transport=MockDigestAuthTransport(qop="auth-int")
+ ) as client:
+ with pytest.raises(NotImplementedError):
+ await client.get(url, auth=auth)
@pytest.mark.asyncio
async def test_digest_auth_qop_must_be_auth_or_auth_int() -> None:
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(transport=MockDigestAuthTransport(qop="not-auth"))
- with pytest.raises(ProtocolError):
- await client.get(url, auth=auth)
+ async with httpx.AsyncClient(
+ transport=MockDigestAuthTransport(qop="not-auth")
+ ) as client:
+ with pytest.raises(ProtocolError):
+ await client.get(url, auth=auth)
@pytest.mark.asyncio
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(
+ async with httpx.AsyncClient(
transport=MockDigestAuthTransport(send_response_after_attempt=2)
- )
- response = await client.get(url, auth=auth)
+ ) as client:
+ response = await client.get(url, auth=auth)
assert response.status_code == 401
assert len(response.history) == 1
) -> None:
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(
+ async with httpx.AsyncClient(
transport=AsyncMockTransport(auth_header=auth_header, status_code=401)
- )
-
- with pytest.raises(ProtocolError):
- await client.get(url, auth=auth)
+ ) as client:
+ with pytest.raises(ProtocolError):
+ await client.get(url, auth=auth)
@pytest.mark.parametrize(
) -> None:
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = Client(
- transport=SyncMockTransport(auth_header=auth_header, status_code=401)
- )
- with pytest.raises(ProtocolError):
- client.get(url, auth=auth)
+ with httpx.Client(
+ transport=SyncMockTransport(auth_header=auth_header, status_code=401)
+ ) as client:
+ with pytest.raises(ProtocolError):
+ client.get(url, auth=auth)
@pytest.mark.asyncio
"""
url = "https://example.org/"
auth = RepeatAuth(repeat=2)
- client = AsyncClient(transport=AsyncMockTransport(auth_header=b"abc"))
- response = await client.get(url, auth=auth)
+ async with httpx.AsyncClient(
+ transport=AsyncMockTransport(auth_header=b"abc")
+ ) as client:
+ response = await client.get(url, auth=auth)
+
assert response.status_code == 200
assert response.json() == {"auth": "Repeat abc.abc"}
"""
url = "https://example.org/"
auth = RepeatAuth(repeat=2)
- client = Client(transport=SyncMockTransport(auth_header=b"abc"))
- response = client.get(url, auth=auth)
+ with httpx.Client(transport=SyncMockTransport(auth_header=b"abc")) as client:
+ response = client.get(url, auth=auth)
+
assert response.status_code == 200
assert response.json() == {"auth": "Repeat abc.abc"}
async def test_digest_auth_unavailable_streaming_body():
url = "https://example.org/"
auth = DigestAuth(username="tomchristie", password="password123")
- client = AsyncClient(transport=AsyncMockTransport())
async def streaming_body():
yield b"Example request body" # pragma: nocover
- with pytest.raises(RequestBodyUnavailable):
- await client.post(url, data=streaming_body(), auth=auth)
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ with pytest.raises(RequestBodyUnavailable):
+ await client.post(url, data=streaming_body(), auth=auth)
@pytest.mark.asyncio
"""
url = "https://example.org/"
auth = ResponseBodyAuth("xyz")
- client = AsyncClient(transport=AsyncMockTransport())
+ async with httpx.AsyncClient(transport=AsyncMockTransport()) as client:
+ response = await client.get(url, auth=auth)
- response = await client.get(url, auth=auth)
assert response.status_code == 200
assert response.json() == {"auth": '{"auth": "xyz"}'}
"""
url = "https://example.org/"
auth = ResponseBodyAuth("xyz")
- client = Client(transport=SyncMockTransport())
- response = client.get(url, auth=auth)
+ with httpx.Client(transport=SyncMockTransport()) as client:
+ response = client.get(url, auth=auth)
+
assert response.status_code == 200
assert response.json() == {"auth": '{"auth": "xyz"}'}
@pytest.mark.parametrize(("value,output"), (("abc", b"abc"), (b"abc", b"abc")))
@pytest.mark.asyncio
async def test_multipart(value, output):
- client = httpx.AsyncClient(transport=MockTransport())
-
- # Test with a single-value 'data' argument, and a plain file 'files' argument.
- data = {"text": value}
- files = {"file": io.BytesIO(b"<file content>")}
- response = await client.post("http://127.0.0.1:8000/", data=data, files=files)
- assert response.status_code == 200
-
- # We're using the cgi module to verify the behavior here, which is a
- # bit grungy, but sufficient just for our testing purposes.
- boundary = response.request.headers["Content-Type"].split("boundary=")[-1]
- content_length = response.request.headers["Content-Length"]
- pdict: dict = {
- "boundary": boundary.encode("ascii"),
- "CONTENT-LENGTH": content_length,
- }
- multipart = cgi.parse_multipart(io.BytesIO(response.content), pdict)
-
- # Note that the expected return type for text fields
- # appears to differs from 3.6 to 3.7+
- assert multipart["text"] == [output.decode()] or multipart["text"] == [output]
- assert multipart["file"] == [b"<file content>"]
+ async with httpx.AsyncClient(transport=MockTransport()) as client:
+ # Test with a single-value 'data' argument, and a plain file 'files' argument.
+ data = {"text": value}
+ files = {"file": io.BytesIO(b"<file content>")}
+ response = await client.post("http://127.0.0.1:8000/", data=data, files=files)
+ assert response.status_code == 200
+
+ # We're using the cgi module to verify the behavior here, which is a
+ # bit grungy, but sufficient just for our testing purposes.
+ boundary = response.request.headers["Content-Type"].split("boundary=")[-1]
+ content_length = response.request.headers["Content-Length"]
+ pdict: dict = {
+ "boundary": boundary.encode("ascii"),
+ "CONTENT-LENGTH": content_length,
+ }
+ multipart = cgi.parse_multipart(io.BytesIO(response.content), pdict)
+
+ # Note that the expected return type for text fields
+ # appears to differs from 3.6 to 3.7+
+ assert multipart["text"] == [output.decode()] or multipart["text"] == [output]
+ assert multipart["file"] == [b"<file content>"]
@pytest.mark.parametrize(("key"), (b"abc", 1, 2.3, None))
@pytest.mark.asyncio
async def test_multipart_invalid_key(key):
- client = httpx.AsyncClient(transport=MockTransport())
- data = {key: "abc"}
- files = {"file": io.BytesIO(b"<file content>")}
- with pytest.raises(TypeError) as e:
- await client.post("http://127.0.0.1:8000/", data=data, files=files)
- assert "Invalid type for name" in str(e.value)
+ async with httpx.AsyncClient(transport=MockTransport()) as client:
+ data = {key: "abc"}
+ files = {"file": io.BytesIO(b"<file content>")}
+ with pytest.raises(TypeError) as e:
+ await client.post(
+ "http://127.0.0.1:8000/",
+ data=data,
+ files=files,
+ )
+ assert "Invalid type for name" in str(e.value)
@pytest.mark.parametrize(("value"), (1, 2.3, None, [None, "abc"], {None: "abc"}))
@pytest.mark.asyncio
async def test_multipart_invalid_value(value):
- client = httpx.AsyncClient(transport=MockTransport())
- data = {"text": value}
- files = {"file": io.BytesIO(b"<file content>")}
- with pytest.raises(TypeError) as e:
- await client.post("http://127.0.0.1:8000/", data=data, files=files)
- assert "Invalid type for value" in str(e.value)
+ async with httpx.AsyncClient(transport=MockTransport()) as client:
+ data = {"text": value}
+ files = {"file": io.BytesIO(b"<file content>")}
+ with pytest.raises(TypeError) as e:
+ await client.post("http://127.0.0.1:8000/", data=data, files=files)
+ assert "Invalid type for value" in str(e.value)
@pytest.mark.asyncio
async def test_multipart_file_tuple():
- client = httpx.AsyncClient(transport=MockTransport())
-
- # Test with a list of values 'data' argument, and a tuple style 'files' argument.
- data = {"text": ["abc"]}
- files = {"file": ("name.txt", io.BytesIO(b"<file content>"))}
- response = await client.post("http://127.0.0.1:8000/", data=data, files=files)
- assert response.status_code == 200
-
- # We're using the cgi module to verify the behavior here, which is a
- # bit grungy, but sufficient just for our testing purposes.
- boundary = response.request.headers["Content-Type"].split("boundary=")[-1]
- content_length = response.request.headers["Content-Length"]
- pdict: dict = {
- "boundary": boundary.encode("ascii"),
- "CONTENT-LENGTH": content_length,
- }
- multipart = cgi.parse_multipart(io.BytesIO(response.content), pdict)
-
- # Note that the expected return type for text fields
- # appears to differs from 3.6 to 3.7+
- assert multipart["text"] == ["abc"] or multipart["text"] == [b"abc"]
- assert multipart["file"] == [b"<file content>"]
+ async with httpx.AsyncClient(transport=MockTransport()) as client:
+ # Test with a list of values 'data' argument,
+ # and a tuple style 'files' argument.
+ data = {"text": ["abc"]}
+ files = {"file": ("name.txt", io.BytesIO(b"<file content>"))}
+ response = await client.post("http://127.0.0.1:8000/", data=data, files=files)
+ assert response.status_code == 200
+
+ # We're using the cgi module to verify the behavior here, which is a
+ # bit grungy, but sufficient just for our testing purposes.
+ boundary = response.request.headers["Content-Type"].split("boundary=")[-1]
+ content_length = response.request.headers["Content-Length"]
+ pdict: dict = {
+ "boundary": boundary.encode("ascii"),
+ "CONTENT-LENGTH": content_length,
+ }
+ multipart = cgi.parse_multipart(io.BytesIO(response.content), pdict)
+
+ # Note that the expected return type for text fields
+ # appears to differs from 3.6 to 3.7+
+ assert multipart["text"] == ["abc"] or multipart["text"] == [b"abc"]
+ assert multipart["file"] == [b"<file content>"]
def test_multipart_encode(tmp_path: typing.Any) -> None: