replace pytest-asyncio and pytest-trio with anyio (#2512)

* replace pytest-asyncio with anyio

* remove pytest-trio also

* Update setup.cfg

* use anyio.Lock in test_auth

Co-authored-by: Tom Christie <tom@tomchristie.com>
This commit is contained in:
Thomas Grainger 2023-01-02 12:53:30 +00:00 committed by GitHub
parent e4438a3a71
commit e27d1b8333
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 120 additions and 146 deletions

View File

@ -31,8 +31,6 @@ isort==5.11.4
mypy==0.982
types-certifi==2021.10.8.2
pytest==7.2.0
pytest-asyncio==0.20.3
pytest-trio==0.7.0
trio==0.21.0
trio-typing==0.7.0
trustme==0.9.0

View File

@ -18,7 +18,7 @@ combine_as_imports = True
addopts = -rxXs
filterwarnings =
error
asyncio_mode = strict
ignore: You seem to already have a custom sys.excepthook handler installed. I'll skip installing Trio's custom handler, but this means MultiErrors will not show full tracebacks.:RuntimeWarning
markers =
copied_from(source, changes=None): mark test as copied from somewhere else, along with a description of changes made to accodomate e.g. our test setup
network: marks tests which require network connection. Used in 3rd-party build environments that have network disabled.

View File

@ -6,7 +6,7 @@ import pytest
import httpx
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_get(server):
url = server.url
async with httpx.AsyncClient(http2=True) as client:
@ -27,14 +27,14 @@ async def test_get(server):
pytest.param("http://", id="no-host"),
],
)
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_get_invalid_url(server, url):
async with httpx.AsyncClient() as client:
with pytest.raises((httpx.UnsupportedProtocol, httpx.LocalProtocolError)):
await client.get(url)
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_build_request(server):
url = server.url.copy_with(path="/echo_headers")
headers = {"Custom-header": "value"}
@ -49,7 +49,7 @@ async def test_build_request(server):
assert response.json()["Custom-header"] == "value"
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_post(server):
url = server.url
async with httpx.AsyncClient() as client:
@ -57,7 +57,7 @@ async def test_post(server):
assert response.status_code == 200
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_post_json(server):
url = server.url
async with httpx.AsyncClient() as client:
@ -65,7 +65,7 @@ async def test_post_json(server):
assert response.status_code == 200
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_stream_response(server):
async with httpx.AsyncClient() as client:
async with client.stream("GET", server.url) as response:
@ -76,7 +76,7 @@ async def test_stream_response(server):
assert response.content == b"Hello, world!"
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_access_content_stream_response(server):
async with httpx.AsyncClient() as client:
async with client.stream("GET", server.url) as response:
@ -87,7 +87,7 @@ async def test_access_content_stream_response(server):
response.content
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_stream_request(server):
async def hello_world() -> typing.AsyncIterator[bytes]:
yield b"Hello, "
@ -98,7 +98,7 @@ async def test_stream_request(server):
assert response.status_code == 200
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_cannot_stream_sync_request(server):
def hello_world() -> typing.Iterator[bytes]: # pragma: no cover
yield b"Hello, "
@ -109,7 +109,7 @@ async def test_cannot_stream_sync_request(server):
await client.post(server.url, content=hello_world())
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_raise_for_status(server):
async with httpx.AsyncClient() as client:
for status_code in (200, 400, 404, 500, 505):
@ -125,7 +125,7 @@ async def test_raise_for_status(server):
assert response.raise_for_status() is None # type: ignore
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_options(server):
async with httpx.AsyncClient() as client:
response = await client.options(server.url)
@ -133,7 +133,7 @@ async def test_options(server):
assert response.text == "Hello, world!"
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_head(server):
async with httpx.AsyncClient() as client:
response = await client.head(server.url)
@ -141,21 +141,21 @@ async def test_head(server):
assert response.text == ""
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_put(server):
async with httpx.AsyncClient() as client:
response = await client.put(server.url, content=b"Hello, world!")
assert response.status_code == 200
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_patch(server):
async with httpx.AsyncClient() as client:
response = await client.patch(server.url, content=b"Hello, world!")
assert response.status_code == 200
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_delete(server):
async with httpx.AsyncClient() as client:
response = await client.delete(server.url)
@ -163,7 +163,7 @@ async def test_delete(server):
assert response.text == "Hello, world!"
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_100_continue(server):
headers = {"Expect": "100-continue"}
content = b"Echo request body"
@ -177,7 +177,7 @@ async def test_100_continue(server):
assert response.content == content
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_context_managed_transport():
class Transport(httpx.AsyncBaseTransport):
def __init__(self) -> None:
@ -209,7 +209,7 @@ async def test_context_managed_transport():
]
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_context_managed_transport_and_mount():
class Transport(httpx.AsyncBaseTransport):
def __init__(self, name: str):
@ -254,7 +254,7 @@ def hello_world(request):
return httpx.Response(200, text="Hello, world!")
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_client_closed_state_using_implicit_open():
client = httpx.AsyncClient(transport=httpx.MockTransport(hello_world))
@ -275,7 +275,7 @@ async def test_client_closed_state_using_implicit_open():
pass # pragma: no cover
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_client_closed_state_using_with_block():
async with httpx.AsyncClient(transport=httpx.MockTransport(hello_world)) as client:
assert not client.is_closed
@ -296,7 +296,7 @@ def mounted(request: httpx.Request) -> httpx.Response:
return httpx.Response(200, json=data)
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_mounted_transport():
transport = httpx.MockTransport(unmounted)
mounts = {"custom://": httpx.MockTransport(mounted)}
@ -311,7 +311,7 @@ async def test_mounted_transport():
assert response.json() == {"app": "mounted"}
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_async_mock_transport():
async def hello_world(request):
return httpx.Response(200, text="Hello, world!")
@ -324,7 +324,7 @@ async def test_async_mock_transport():
assert response.text == "Hello, world!"
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_cancellation_during_stream():
"""
If any BaseException is raised during streaming the response, then the
@ -364,7 +364,7 @@ async def test_cancellation_during_stream():
assert stream_was_closed
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_server_extensions(server):
url = server.url
async with httpx.AsyncClient(http2=True) as client:

View File

@ -3,13 +3,13 @@ Integration tests for authentication.
Unit tests for auth classes also exist in tests/test_auth.py
"""
import asyncio
import hashlib
import os
import threading
import typing
from urllib.request import parse_keqv_list
import anyio
import pytest
import httpx
@ -135,7 +135,7 @@ class SyncOrAsyncAuth(httpx.Auth):
def __init__(self) -> None:
self._lock = threading.Lock()
self._async_lock = asyncio.Lock()
self._async_lock = anyio.Lock()
def sync_auth_flow(
self, request: httpx.Request
@ -152,7 +152,7 @@ class SyncOrAsyncAuth(httpx.Auth):
yield request
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_basic_auth() -> None:
url = "https://example.org/"
auth = ("user", "password123")
@ -165,7 +165,7 @@ async def test_basic_auth() -> None:
assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_basic_auth_with_stream() -> None:
"""
See: https://github.com/encode/httpx/pull/1312
@ -184,7 +184,7 @@ async def test_basic_auth_with_stream() -> None:
assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_basic_auth_in_url() -> None:
url = "https://user:password123@example.org/"
app = App()
@ -196,7 +196,7 @@ async def test_basic_auth_in_url() -> None:
assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_basic_auth_on_session() -> None:
url = "https://example.org/"
auth = ("user", "password123")
@ -211,7 +211,7 @@ async def test_basic_auth_on_session() -> None:
assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_custom_auth() -> None:
url = "https://example.org/"
app = App()
@ -227,7 +227,7 @@ async def test_custom_auth() -> None:
assert response.json() == {"auth": "Token 123"}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_netrc_auth() -> None:
os.environ["NETRC"] = str(FIXTURES_DIR / ".netrc")
url = "http://netrcexample.org"
@ -242,7 +242,7 @@ async def test_netrc_auth() -> None:
}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_auth_header_has_priority_over_netrc() -> None:
os.environ["NETRC"] = str(FIXTURES_DIR / ".netrc")
url = "http://netrcexample.org"
@ -255,7 +255,7 @@ async def test_auth_header_has_priority_over_netrc() -> None:
assert response.json() == {"auth": "Override"}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_trust_env_auth() -> None:
os.environ["NETRC"] = str(FIXTURES_DIR / ".netrc")
url = "http://netrcexample.org"
@ -280,7 +280,7 @@ async def test_trust_env_auth() -> None:
}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_auth_disable_per_request() -> None:
url = "https://example.org/"
auth = ("user", "password123")
@ -302,7 +302,7 @@ def test_auth_hidden_url() -> None:
assert expected == repr(httpx.URL(url))
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_auth_hidden_header() -> None:
url = "https://example.org/"
auth = ("example-username", "example-password")
@ -314,7 +314,7 @@ async def test_auth_hidden_header() -> None:
assert "'authorization': '[secure]'" in str(response.request.headers)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_auth_property() -> None:
app = App()
@ -330,7 +330,7 @@ async def test_auth_property() -> None:
assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_auth_invalid_type() -> None:
app = App()
@ -348,7 +348,7 @@ async def test_auth_invalid_type() -> None:
client.auth = "not a tuple, not a callable" # type: ignore
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_returns_no_auth_if_no_digest_header_in_response() -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -376,7 +376,7 @@ def test_digest_auth_returns_no_auth_if_alternate_auth_scheme() -> None:
assert len(response.history) == 0
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_200_response_including_digest_auth_header() -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -391,7 +391,7 @@ async def test_digest_auth_200_response_including_digest_auth_header() -> None:
assert len(response.history) == 0
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_401_response_without_digest_auth_header() -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -418,7 +418,7 @@ async def test_digest_auth_401_response_without_digest_auth_header() -> None:
("SHA-512-SESS", 64, 128),
],
)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth(
algorithm: str, expected_hash_length: int, expected_response_length: int
) -> None:
@ -451,7 +451,7 @@ async def test_digest_auth(
assert len(digest_data["cnonce"]) == 16 + 2
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_no_specified_qop() -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -483,7 +483,7 @@ async def test_digest_auth_no_specified_qop() -> None:
@pytest.mark.parametrize("qop", ("auth, auth-int", "auth,auth-int", "unknown,auth"))
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_qop_including_spaces_and_auth_returns_auth(qop: str) -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -496,7 +496,7 @@ async def test_digest_auth_qop_including_spaces_and_auth_returns_auth(qop: str)
assert len(response.history) == 1
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_qop_auth_int_not_implemented() -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -507,7 +507,7 @@ async def test_digest_auth_qop_auth_int_not_implemented() -> None:
await client.get(url, auth=auth)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_qop_must_be_auth_or_auth_int() -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -518,7 +518,7 @@ async def test_digest_auth_qop_must_be_auth_or_auth_int() -> None:
await client.get(url, auth=auth)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_incorrect_credentials() -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -531,7 +531,7 @@ async def test_digest_auth_incorrect_credentials() -> None:
assert len(response.history) == 1
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_reuses_challenge() -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -548,7 +548,7 @@ async def test_digest_auth_reuses_challenge() -> None:
assert len(response_2.history) == 0
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_resets_nonce_count_after_401() -> None:
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -594,7 +594,7 @@ async def test_digest_auth_resets_nonce_count_after_401() -> None:
'Digest realm="httpx@example.org", qop="auth,au', # malformed fields list
],
)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_async_digest_auth_raises_protocol_error_on_malformed_header(
auth_header: str,
) -> None:
@ -626,7 +626,7 @@ def test_sync_digest_auth_raises_protocol_error_on_malformed_header(
client.get(url, auth=auth)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_async_auth_history() -> None:
"""
Test that intermediate requests sent as part of an authentication flow
@ -686,7 +686,7 @@ class ConsumeBodyTransport(httpx.MockTransport):
return self.handler(request)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_digest_auth_unavailable_streaming_body():
url = "https://example.org/"
auth = httpx.DigestAuth(username="user", password="password123")
@ -700,7 +700,7 @@ async def test_digest_auth_unavailable_streaming_body():
await client.post(url, content=streaming_body(), auth=auth)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_async_auth_reads_response_body() -> None:
"""
Test that we can read the response body in an auth flow if `requires_response_body`
@ -733,7 +733,7 @@ def test_sync_auth_reads_response_body() -> None:
assert response.json() == {"auth": '{"auth": "xyz"}'}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_async_auth() -> None:
"""
Test that we can use an auth implementation specific to the async case, to

View File

@ -63,7 +63,7 @@ def test_event_hooks_raising_exception(server):
assert exc.response.is_closed
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_async_event_hooks():
events = []
@ -99,7 +99,7 @@ async def test_async_event_hooks():
]
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_async_event_hooks_raising_exception():
async def raise_on_4xx_5xx(response):
response.raise_for_status()
@ -171,7 +171,7 @@ def test_event_hooks_with_redirect():
]
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_async_event_hooks_with_redirect():
"""
A redirect request should trigger additional 'request' and 'response' event hooks.

View File

@ -132,7 +132,7 @@ def test_transport_for_request(url, proxies, expected):
assert transport._pool._proxy_url == url_to_origin(expected)
@pytest.mark.asyncio
@pytest.mark.anyio
@pytest.mark.network
async def test_async_proxy_close():
try:

View File

@ -151,7 +151,7 @@ def test_next_request():
assert response.next_request is None
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_async_next_request():
async with httpx.AsyncClient(transport=httpx.MockTransport(redirects)) as client:
request = client.build_request("POST", "https://example.org/redirect_303")
@ -240,7 +240,7 @@ def test_multiple_redirects():
assert len(response.history[1].history) == 1
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_async_too_many_redirects():
async with httpx.AsyncClient(transport=httpx.MockTransport(redirects)) as client:
with pytest.raises(httpx.TooManyRedirects):
@ -438,7 +438,7 @@ def test_redirect_custom_scheme():
assert str(e.value) == "Scheme 'market' not supported."
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_async_invalid_redirect():
async with httpx.AsyncClient(transport=httpx.MockTransport(redirects)) as client:
with pytest.raises(httpx.RemoteProtocolError):

View File

@ -34,30 +34,6 @@ ENVIRONMENT_VARIABLES = {
}
@pytest.fixture(
params=[
pytest.param("asyncio", marks=pytest.mark.asyncio),
pytest.param("trio", marks=pytest.mark.trio),
]
)
def async_environment(request: typing.Any) -> str:
"""
Mark a test function to be run on both asyncio and trio.
Equivalent to having a pair of tests, each respectively marked with
'@pytest.mark.asyncio' and '@pytest.mark.trio'.
Intended usage:
```
@pytest.mark.usefixtures("async_environment")
async def my_async_test():
...
```
"""
return typing.cast(str, request.param)
@pytest.fixture(scope="function", autouse=True)
def clean_environ():
"""Keeps os.environ clean for every test without having to mock os.environ"""

View File

@ -86,7 +86,7 @@ def test_read_and_stream_data():
assert content == request.content
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aread_and_stream_data():
# Ensure a request may still be streamed if it has been read.
# Needed for cases such as authentication classes that read the request body.
@ -192,7 +192,7 @@ def test_request_picklable():
}
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_request_async_streaming_content_picklable():
async def streaming_body(data: bytes) -> typing.AsyncIterator[bytes]:
yield data

View File

@ -331,7 +331,7 @@ def test_empty_read():
assert response.is_closed
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aread():
response = httpx.Response(
200,
@ -350,7 +350,7 @@ async def test_aread():
assert response.is_closed
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_empty_aread():
response = httpx.Response(200)
@ -449,7 +449,7 @@ def test_iter_raw_increments_updates_counter():
num_downloaded = response.num_bytes_downloaded
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiter_raw():
response = httpx.Response(200, content=async_streaming_body())
@ -459,7 +459,7 @@ async def test_aiter_raw():
assert raw == b"Hello, world!"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiter_raw_with_chunksize():
response = httpx.Response(200, content=async_streaming_body())
@ -477,7 +477,7 @@ async def test_aiter_raw_with_chunksize():
assert parts == [b"Hello, world!"]
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiter_raw_on_sync():
response = httpx.Response(
200,
@ -488,7 +488,7 @@ async def test_aiter_raw_on_sync():
[part async for part in response.aiter_raw()]
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aclose_on_sync():
response = httpx.Response(
200,
@ -499,7 +499,7 @@ async def test_aclose_on_sync():
await response.aclose()
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiter_raw_increments_updates_counter():
response = httpx.Response(200, content=async_streaming_body())
@ -551,7 +551,7 @@ def test_iter_bytes_doesnt_return_empty_chunks():
assert parts == [b"Hello, ", b"world!"]
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiter_bytes():
response = httpx.Response(
200,
@ -564,7 +564,7 @@ async def test_aiter_bytes():
assert content == b"Hello, world!"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiter_bytes_with_chunk_size():
response = httpx.Response(200, content=async_streaming_body())
parts = [part async for part in response.aiter_bytes(chunk_size=5)]
@ -605,7 +605,7 @@ def test_iter_text_with_chunk_size():
assert parts == ["Hello, world!"]
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiter_text():
response = httpx.Response(
200,
@ -618,7 +618,7 @@ async def test_aiter_text():
assert content == "Hello, world!"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiter_text_with_chunk_size():
response = httpx.Response(200, content=b"Hello, world!")
parts = [part async for part in response.aiter_text(chunk_size=5)]
@ -642,7 +642,7 @@ def test_iter_lines():
assert content == ["Hello,\n", "world!"]
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiter_lines():
response = httpx.Response(
200,
@ -671,7 +671,7 @@ def test_sync_streaming_response():
assert response.is_closed
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_async_streaming_response():
response = httpx.Response(
200,
@ -702,7 +702,7 @@ def test_cannot_read_after_stream_consumed():
response.read()
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_cannot_aread_after_stream_consumed():
response = httpx.Response(
200,
@ -728,7 +728,7 @@ def test_cannot_read_after_response_closed():
response.read()
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_cannot_aread_after_response_closed():
response = httpx.Response(
200,
@ -740,7 +740,7 @@ async def test_cannot_aread_after_response_closed():
await response.aread()
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_elapsed_not_available_until_closed():
response = httpx.Response(
200,
@ -947,7 +947,7 @@ def test_response_picklable():
assert pickle_response.history == []
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_response_async_streaming_picklable():
response = httpx.Response(200, content=async_streaming_body())
pickle_response = pickle.loads(pickle.dumps(response))

View File

@ -70,7 +70,7 @@ async def raise_exc_after_response(scope, receive, send):
raise RuntimeError()
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi_transport():
async with httpx.ASGITransport(app=hello_world) as transport:
request = httpx.Request("GET", "http://www.example.com/")
@ -80,7 +80,7 @@ async def test_asgi_transport():
assert response.content == b"Hello, World!"
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi_transport_no_body():
async with httpx.ASGITransport(app=echo_body) as transport:
request = httpx.Request("GET", "http://www.example.com/")
@ -90,7 +90,7 @@ async def test_asgi_transport_no_body():
assert response.content == b""
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi():
async with httpx.AsyncClient(app=hello_world) as client:
response = await client.get("http://www.example.org/")
@ -99,7 +99,7 @@ async def test_asgi():
assert response.text == "Hello, World!"
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi_urlencoded_path():
async with httpx.AsyncClient(app=echo_path) as client:
url = httpx.URL("http://www.example.org/").copy_with(path="/user@example.org")
@ -109,7 +109,7 @@ async def test_asgi_urlencoded_path():
assert response.json() == {"path": "/user@example.org"}
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi_raw_path():
async with httpx.AsyncClient(app=echo_raw_path) as client:
url = httpx.URL("http://www.example.org/").copy_with(path="/user@example.org")
@ -119,7 +119,7 @@ async def test_asgi_raw_path():
assert response.json() == {"raw_path": "/user%40example.org"}
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi_upload():
async with httpx.AsyncClient(app=echo_body) as client:
response = await client.post("http://www.example.org/", content=b"example")
@ -128,7 +128,7 @@ async def test_asgi_upload():
assert response.text == "example"
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi_headers():
async with httpx.AsyncClient(app=echo_headers) as client:
response = await client.get("http://www.example.org/")
@ -145,21 +145,21 @@ async def test_asgi_headers():
}
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi_exc():
async with httpx.AsyncClient(app=raise_exc) as client:
with pytest.raises(RuntimeError):
await client.get("http://www.example.org/")
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi_exc_after_response():
async with httpx.AsyncClient(app=raise_exc_after_response) as client:
with pytest.raises(RuntimeError):
await client.get("http://www.example.org/")
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_asgi_disconnect_after_response_complete():
disconnect = False

View File

@ -9,7 +9,7 @@ method = "POST"
url = "https://www.example.com"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_empty_content():
request = httpx.Request(method, url)
assert isinstance(request.stream, httpx.SyncByteStream)
@ -23,7 +23,7 @@ async def test_empty_content():
assert async_content == b""
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_bytes_content():
request = httpx.Request(method, url, content=b"Hello, world!")
assert isinstance(request.stream, typing.Iterable)
@ -50,7 +50,7 @@ async def test_bytes_content():
assert async_content == b"Hello, world!"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_bytesio_content():
request = httpx.Request(method, url, content=io.BytesIO(b"Hello, world!"))
assert isinstance(request.stream, typing.Iterable)
@ -62,7 +62,7 @@ async def test_bytesio_content():
assert content == b"Hello, world!"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_async_bytesio_content():
class AsyncBytesIO:
def __init__(self, content: bytes) -> None:
@ -90,7 +90,7 @@ async def test_async_bytesio_content():
assert content == b"Hello, world!"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_iterator_content():
def hello_world() -> typing.Iterator[bytes]:
yield b"Hello, "
@ -126,7 +126,7 @@ async def test_iterator_content():
assert content == b"Hello, world!"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_aiterator_content():
async def hello_world() -> typing.AsyncIterator[bytes]:
yield b"Hello, "
@ -162,7 +162,7 @@ async def test_aiterator_content():
assert content == b"Hello, world!"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_json_content():
request = httpx.Request(method, url, json={"Hello": "world!"})
assert isinstance(request.stream, typing.Iterable)
@ -180,7 +180,7 @@ async def test_json_content():
assert async_content == b'{"Hello": "world!"}'
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_urlencoded_content():
request = httpx.Request(method, url, data={"Hello": "world!"})
assert isinstance(request.stream, typing.Iterable)
@ -198,7 +198,7 @@ async def test_urlencoded_content():
assert async_content == b"Hello=world%21"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_urlencoded_boolean():
request = httpx.Request(method, url, data={"example": True})
assert isinstance(request.stream, typing.Iterable)
@ -216,7 +216,7 @@ async def test_urlencoded_boolean():
assert async_content == b"example=true"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_urlencoded_none():
request = httpx.Request(method, url, data={"example": None})
assert isinstance(request.stream, typing.Iterable)
@ -234,7 +234,7 @@ async def test_urlencoded_none():
assert async_content == b"example="
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_urlencoded_list():
request = httpx.Request(method, url, data={"example": ["a", 1, True]})
assert isinstance(request.stream, typing.Iterable)
@ -252,7 +252,7 @@ async def test_urlencoded_list():
assert async_content == b"example=a&example=1&example=true"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_multipart_files_content():
files = {"file": io.BytesIO(b"<file content>")}
headers = {"Content-Type": "multipart/form-data; boundary=+++"}
@ -295,7 +295,7 @@ async def test_multipart_files_content():
)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_multipart_data_and_files_content():
data = {"message": "Hello, world!"}
files = {"file": io.BytesIO(b"<file content>")}
@ -342,7 +342,7 @@ async def test_multipart_data_and_files_content():
)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_empty_request():
request = httpx.Request(method, url, data={}, files={})
assert isinstance(request.stream, typing.Iterable)
@ -364,7 +364,7 @@ def test_invalid_argument():
httpx.Request(method, url, content={"a": "b"}) # type: ignore
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_multipart_multiple_files_single_input_content():
files = [
("file", io.BytesIO(b"<file content 1>")),
@ -415,7 +415,7 @@ async def test_multipart_multiple_files_single_input_content():
)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_response_empty_content():
response = httpx.Response(200)
assert isinstance(response.stream, typing.Iterable)
@ -429,7 +429,7 @@ async def test_response_empty_content():
assert async_content == b""
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_response_bytes_content():
response = httpx.Response(200, content=b"Hello, world!")
assert isinstance(response.stream, typing.Iterable)
@ -443,7 +443,7 @@ async def test_response_bytes_content():
assert async_content == b"Hello, world!"
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_response_iterator_content():
def hello_world() -> typing.Iterator[bytes]:
yield b"Hello, "
@ -462,7 +462,7 @@ async def test_response_iterator_content():
[part for part in response.stream]
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_response_aiterator_content():
async def hello_world() -> typing.AsyncIterator[bytes]:
yield b"Hello, "

View File

@ -114,7 +114,7 @@ def test_multi_with_identity():
assert response.content == body
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_streaming():
body = b"test 123"
compressor = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16)
@ -173,7 +173,7 @@ def test_decoding_errors(header_value):
((b"Accented: \xd6sterreich abcdefghijklmnopqrstuvwxyz", b""), "iso-8859-1"),
],
)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_text_decoder_with_autodetect(data, encoding):
async def iterator() -> typing.AsyncIterator[bytes]:
nonlocal data
@ -196,7 +196,7 @@ async def test_text_decoder_with_autodetect(data, encoding):
assert text == (b"".join(data)).decode(encoding)
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_text_decoder_known_encoding():
async def iterator() -> typing.AsyncIterator[bytes]:
yield b"\x83g"

View File

@ -3,7 +3,7 @@ import pytest
import httpx
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_read_timeout(server):
timeout = httpx.Timeout(None, read=1e-6)
@ -12,7 +12,7 @@ async def test_read_timeout(server):
await client.get(server.url.copy_with(path="/slow_response"))
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_write_timeout(server):
timeout = httpx.Timeout(None, write=1e-6)
@ -22,7 +22,7 @@ async def test_write_timeout(server):
await client.put(server.url.copy_with(path="/slow_response"), content=data)
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
@pytest.mark.network
async def test_connect_timeout(server):
timeout = httpx.Timeout(None, connect=1e-6)
@ -33,7 +33,7 @@ async def test_connect_timeout(server):
await client.get("http://10.255.255.1/")
@pytest.mark.usefixtures("async_environment")
@pytest.mark.anyio
async def test_pool_timeout(server):
limits = httpx.Limits(max_connections=1)
timeout = httpx.Timeout(None, pool=1e-4)

View File

@ -98,7 +98,7 @@ def test_parse_header_links(value, expected):
assert parse_header_links(value) == expected
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_logs_debug(server, capsys):
with override_log_level("debug"):
async with httpx.AsyncClient() as client:
@ -108,7 +108,7 @@ async def test_logs_debug(server, capsys):
assert 'HTTP Request: GET http://127.0.0.1:8000/ "HTTP/1.1 200 OK"' in stderr
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_logs_trace(server, capsys):
with override_log_level("trace"):
async with httpx.AsyncClient() as client:
@ -118,7 +118,7 @@ async def test_logs_trace(server, capsys):
assert 'HTTP Request: GET http://127.0.0.1:8000/ "HTTP/1.1 200 OK"' in stderr
@pytest.mark.asyncio
@pytest.mark.anyio
async def test_logs_redirect_chain(server, capsys):
with override_log_level("debug"):
async with httpx.AsyncClient(follow_redirects=True) as client: