From 0b5185e6e5bbaf640724e1bf22a8a354cdbb6f42 Mon Sep 17 00:00:00 2001 From: Jaakko Lappalainen Date: Sun, 2 May 2021 18:36:37 +0000 Subject: [PATCH 1/3] raise RuntimeError depending on state --- httpx/_client.py | 20 ++++++++++++++++++++ tests/client/test_async_client.py | 9 +++++++++ tests/client/test_client.py | 6 ++++++ 3 files changed, 35 insertions(+) diff --git a/httpx/_client.py b/httpx/_client.py index 7f8ce53101..fd74f559a8 100644 --- a/httpx/_client.py +++ b/httpx/_client.py @@ -1126,6 +1126,11 @@ def close(self) -> None: transport.close() def __enter__(self: T) -> T: + if self._state != ClientState.UNOPENED: + raise RuntimeError( + "Cannot open a client, as the current state is not 'UNOPENED'." + ) + self._state = ClientState.OPENED self._transport.__enter__() @@ -1140,6 +1145,11 @@ def __exit__( exc_value: BaseException = None, traceback: TracebackType = None, ) -> None: + if self._state != ClientState.OPENED: + raise RuntimeError( + "Cannot close a client, as the current state is not 'OPENED'." + ) + self._state = ClientState.CLOSED self._transport.__exit__(exc_type, exc_value, traceback) @@ -1770,6 +1780,11 @@ async def aclose(self) -> None: await proxy.aclose() async def __aenter__(self: U) -> U: + if self._state != ClientState.UNOPENED: + raise RuntimeError( + "Cannot open a client, as the current state is not 'UNOPENED'." + ) + self._state = ClientState.OPENED await self._transport.__aenter__() @@ -1784,6 +1799,11 @@ async def __aexit__( exc_value: BaseException = None, traceback: TracebackType = None, ) -> None: + if self._state != ClientState.OPENED: + raise RuntimeError( + "Cannot close a client, as the current state is not 'OPENED'." + ) + self._state = ClientState.CLOSED await self._transport.__aexit__(exc_type, exc_value, traceback) diff --git a/tests/client/test_async_client.py b/tests/client/test_async_client.py index 6c121b5e88..0c16bd8663 100644 --- a/tests/client/test_async_client.py +++ b/tests/client/test_async_client.py @@ -277,6 +277,15 @@ async def test_deleting_unclosed_async_client_causes_warning(): del client +@pytest.mark.usefixtures("async_environment") +async def test_client_unsensible_use_in_with_block(): + with pytest.raises(RuntimeError): + async with httpx.AsyncClient( + transport=httpx.MockTransport(hello_world) + ) as client: + await client.aclose() + + def unmounted(request: httpx.Request) -> httpx.Response: data = {"app": "unmounted"} return httpx.Response(200, json=data) diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 0538e960b2..62572c61b5 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -319,6 +319,12 @@ def test_client_closed_state_using_with_block(): client.get("http://example.com") +def test_client_unsensible_use_in_with_block(): + with pytest.raises(RuntimeError): + with httpx.Client(transport=httpx.MockTransport(hello_world)) as client: + client.close() + + def echo_raw_headers(request: httpx.Request) -> httpx.Response: data = [ (name.decode("ascii"), value.decode("ascii")) From 995bacd87f9ff64c99e981960325593c368263ab Mon Sep 17 00:00:00 2001 From: Jaakko Lappalainen Date: Sun, 2 May 2021 18:44:40 +0000 Subject: [PATCH 2/3] coverage --- tests/client/test_async_client.py | 6 ++++++ tests/client/test_client.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/tests/client/test_async_client.py b/tests/client/test_async_client.py index 0c16bd8663..0e48712293 100644 --- a/tests/client/test_async_client.py +++ b/tests/client/test_async_client.py @@ -285,6 +285,12 @@ async def test_client_unsensible_use_in_with_block(): ) as client: await client.aclose() + with pytest.raises(RuntimeError): + client = httpx.AsyncClient(transport=httpx.MockTransport(hello_world)) + await client.aclose() + async with client: + pass + def unmounted(request: httpx.Request) -> httpx.Response: data = {"app": "unmounted"} diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 62572c61b5..1eae8b9ef1 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -324,6 +324,12 @@ def test_client_unsensible_use_in_with_block(): with httpx.Client(transport=httpx.MockTransport(hello_world)) as client: client.close() + with pytest.raises(RuntimeError): + client = httpx.Client(transport=httpx.MockTransport(hello_world)) + client._state = httpx._client.ClientState.OPENED + with client: + pass + def echo_raw_headers(request: httpx.Request) -> httpx.Response: data = [ From 7db16da0d986665a7309f86434034162916aaa6e Mon Sep 17 00:00:00 2001 From: Jaakko Lappalainen Date: Sun, 2 May 2021 18:51:42 +0000 Subject: [PATCH 3/3] do not cover pass stmt --- tests/client/test_async_client.py | 2 +- tests/client/test_client.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/client/test_async_client.py b/tests/client/test_async_client.py index 0e48712293..404c473f82 100644 --- a/tests/client/test_async_client.py +++ b/tests/client/test_async_client.py @@ -289,7 +289,7 @@ async def test_client_unsensible_use_in_with_block(): client = httpx.AsyncClient(transport=httpx.MockTransport(hello_world)) await client.aclose() async with client: - pass + pass # pragma: no cover def unmounted(request: httpx.Request) -> httpx.Response: diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 1eae8b9ef1..b1a512cc37 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -328,7 +328,7 @@ def test_client_unsensible_use_in_with_block(): client = httpx.Client(transport=httpx.MockTransport(hello_world)) client._state = httpx._client.ClientState.OPENED with client: - pass + pass # pragma: no cover def echo_raw_headers(request: httpx.Request) -> httpx.Response: