11import json
2- from collections .abc import Generator
2+ from collections .abc import AsyncIterator , Generator , Iterator
33
44import httpx
55import pytest
1515 'invalidItems' : {'0' : ["should have required property 'name'" ], '1' : ["should have required property 'name'" ]}
1616}
1717
18+ RAW_ERROR = (
19+ b'{\n '
20+ b' "error": {\n '
21+ b' "type": "insufficient-permissions",\n '
22+ b' "message": "Insufficient permissions for the Actor run. Make sure you\' '
23+ b're passing a correct API token and that it has the required permissions."\n '
24+ b' }\n '
25+ b'}'
26+ )
1827
19- @pytest .fixture (autouse = True )
28+
29+ @pytest .fixture
2030def mocked_response () -> Generator [respx .MockRouter ]:
2131 response_content = json .dumps (
2232 {'error' : {'message' : _EXPECTED_MESSAGE , 'type' : _EXPECTED_TYPE , 'data' : _EXPECTED_DATA }}
@@ -26,6 +36,7 @@ def mocked_response() -> Generator[respx.MockRouter]:
2636 yield respx_mock
2737
2838
39+ @pytest .mark .usefixtures ('mocked_response' )
2940def test_client_apify_api_error_with_data () -> None :
3041 """Test that client correctly throws ApifyApiError with error data from response."""
3142 client = HTTPClient ()
@@ -38,6 +49,7 @@ def test_client_apify_api_error_with_data() -> None:
3849 assert e .value .data == _EXPECTED_DATA
3950
4051
52+ @pytest .mark .usefixtures ('mocked_response' )
4153async def test_async_client_apify_api_error_with_data () -> None :
4254 """Test that async client correctly throws ApifyApiError with error data from response."""
4355 client = HTTPClientAsync ()
@@ -48,3 +60,53 @@ async def test_async_client_apify_api_error_with_data() -> None:
4860 assert e .value .message == _EXPECTED_MESSAGE
4961 assert e .value .type == _EXPECTED_TYPE
5062 assert e .value .data == _EXPECTED_DATA
63+
64+
65+ def test_client_apify_api_error_streamed () -> None :
66+ """Test that client correctly throws ApifyApiError when the response has stream."""
67+
68+ error = json .loads (RAW_ERROR .decode ())
69+
70+ class ByteStream (httpx ._types .SyncByteStream ):
71+ def __iter__ (self ) -> Iterator [bytes ]:
72+ yield RAW_ERROR
73+
74+ def close (self ) -> None :
75+ pass
76+
77+ stream_url = 'http://some-stream-url.com'
78+
79+ client = HTTPClient ()
80+
81+ with respx .mock () as respx_mock :
82+ respx_mock .get (url = stream_url ).mock (return_value = httpx .Response (stream = ByteStream (), status_code = 403 ))
83+ with pytest .raises (ApifyApiError ) as e :
84+ client .call (method = 'GET' , url = stream_url , stream = True , parse_response = False )
85+
86+ assert e .value .message == error ['error' ]['message' ]
87+ assert e .value .type == error ['error' ]['type' ]
88+
89+
90+ async def test_async_client_apify_api_error_streamed () -> None :
91+ """Test that async client correctly throws ApifyApiError when the response has stream."""
92+
93+ error = json .loads (RAW_ERROR .decode ())
94+
95+ class AsyncByteStream (httpx ._types .AsyncByteStream ):
96+ async def __aiter__ (self ) -> AsyncIterator [bytes ]:
97+ yield RAW_ERROR
98+
99+ async def aclose (self ) -> None :
100+ pass
101+
102+ stream_url = 'http://some-stream-url.com'
103+
104+ client = HTTPClientAsync ()
105+
106+ with respx .mock () as respx_mock :
107+ respx_mock .get (url = stream_url ).mock (return_value = httpx .Response (stream = AsyncByteStream (), status_code = 403 ))
108+ with pytest .raises (ApifyApiError ) as e :
109+ await client .call (method = 'GET' , url = stream_url , stream = True , parse_response = False )
110+
111+ assert e .value .message == error ['error' ]['message' ]
112+ assert e .value .type == error ['error' ]['type' ]
0 commit comments