From 5b482e79e90ad99caa5491e63513543ffcebf29e Mon Sep 17 00:00:00 2001 From: Richard Marmorstein Date: Wed, 24 Jan 2024 17:29:02 -0800 Subject: [PATCH 1/6] Use anyio.sleep --- stripe/_http_client.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/stripe/_http_client.py b/stripe/_http_client.py index 37b3c9180..2dca1ff16 100644 --- a/stripe/_http_client.py +++ b/stripe/_http_client.py @@ -51,9 +51,11 @@ try: import httpx + import anyio from httpx import Timeout as HTTPXTimeout except ImportError: httpx = None + anyio = None try: import requests @@ -986,7 +988,9 @@ def __init__( super(HTTPXClient, self).__init__(**kwargs) assert httpx is not None + assert anyio is not None self.httpx = httpx + self.anyio = anyio kwargs = {} if self._verify_ssl_certs: @@ -998,7 +1002,7 @@ def __init__( self._timeout = timeout def sleep_async(self, secs): - return asyncio.sleep(secs) + return self.anyio.sleep(secs) async def request_async( self, method, url, headers, post_data=None, timeout=80.0 From 01d061c63ff4beb98ff6dcdc81619ddd346abbb4 Mon Sep 17 00:00:00 2001 From: Richard Marmorstein Date: Thu, 25 Jan 2024 10:27:07 -0800 Subject: [PATCH 2/6] wip --- test-requirements.txt | 2 -- tests/conftest.py | 2 +- tests/test_http_client.py | 18 +++++++++--------- tests/test_integration.py | 6 +++--- tests/test_preview.py | 6 +++--- tests/test_raw_request.py | 2 +- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/test-requirements.txt b/test-requirements.txt index 79c1a0034..2bcdf0f18 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,8 +2,6 @@ # This is the last version of httpx compatible with Python 3.6 httpx == 0.22.0 -# This is the last version of pytest-asyncio compatible with Python 3.6 -pytest-asyncio == 0.16.0 pytest-cov >= 2.8.1, < 2.11.0 pytest-mock >= 2.0.0 diff --git a/tests/conftest.py b/tests/conftest.py index b9272e3dc..739d706ca 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,7 +11,7 @@ from tests.http_client_mock import HTTPClientMock -pytest_plugins = ("pytest_asyncio",) +pytest_plugins = ("anyio",) MOCK_MINIMUM_VERSION = "0.109.0" diff --git a/tests/test_http_client.py b/tests/test_http_client.py index 1cdde52dc..d07bda9a7 100644 --- a/tests/test_http_client.py +++ b/tests/test_http_client.py @@ -1205,7 +1205,7 @@ async def make_request_stream_async( method, url, headers, post_data ) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_request(self, request_mock, mock_response, check_call): mock_response('{"foo": "baz"}', 200) @@ -1227,7 +1227,7 @@ async def test_request(self, request_mock, mock_response, check_call): check_call(request_mock, method, abs_url, data, headers) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_request_stream( self, mocker, request_mock, mock_response, check_call ): @@ -1239,7 +1239,7 @@ async def test_exception(self, request_mock, mock_error): with pytest.raises(stripe.APIConnectionError): await self.make_request_async("get", self.valid_url, {}, None) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_timeout(self, request_mock, mock_response, check_call): headers = {"my-header": "header val"} data = {} @@ -1250,7 +1250,7 @@ async def test_timeout(self, request_mock, mock_response, check_call): check_call(None, "POST", self.valid_url, data, headers, timeout=5) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_request_stream_forwards_stream_param( self, mocker, request_mock, mock_response, check_call ): @@ -1336,7 +1336,7 @@ async def make_request_stream(self, *args, **kwargs): "GET", self.valid_url, {}, None, self.max_retries() ) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_retry_error_until_response( self, mock_retry, mock_response, check_call_numbers, mocker ): @@ -1345,7 +1345,7 @@ async def test_retry_error_until_response( assert code == 202 check_call_numbers(2) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_retry_error_until_exceeded( self, mock_retry, mock_response, check_call_numbers ): @@ -1355,7 +1355,7 @@ async def test_retry_error_until_exceeded( check_call_numbers(self.max_retries()) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_no_retry_error( self, mock_retry, mock_response, check_call_numbers ): @@ -1364,7 +1364,7 @@ async def test_no_retry_error( await self.make_request() check_call_numbers(1) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_retry_codes( self, mock_retry, mock_response, check_call_numbers ): @@ -1375,7 +1375,7 @@ async def test_retry_codes( assert code == 202 check_call_numbers(2) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_retry_codes_until_exceeded( self, mock_retry, mock_response, check_call_numbers ): diff --git a/tests/test_integration.py b/tests/test_integration.py index a2706bb26..b346beef2 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -291,7 +291,7 @@ def work(): assert MockServerRequestHandler.num_requests == 20 assert len(MockServerRequestHandler.seen_metrics) == 10 - @pytest.mark.asyncio + @pytest.mark.anyio async def test_async_raw_request_success(self): class MockServerRequestHandler(MyTestHandler): default_body = '{"id": "cus_123", "object": "customer"}'.encode( @@ -315,7 +315,7 @@ class MockServerRequestHandler(MyTestHandler): assert req.command == "POST" assert isinstance(cus, stripe.Customer) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_async_raw_request_timeout(self): class MockServerRequestHandler(MyTestHandler): def do_request(self, n): @@ -340,7 +340,7 @@ def do_request(self, n): assert "A ReadTimeout was raised" in str(exception.user_message) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_async_httpx_raw_request_retries(self): class MockServerRequestHandler(MyTestHandler): def do_request(self, n): diff --git a/tests/test_preview.py b/tests/test_preview.py index f6ba70902..90a85abcd 100644 --- a/tests/test_preview.py +++ b/tests/test_preview.py @@ -75,7 +75,7 @@ def test_delete(self, http_client_mock): assert resp.body == expected_body - @pytest.mark.asyncio + @pytest.mark.anyio async def test_get_async(self, http_client_mock_async): expected_body = '{"id": "acc_123"}' http_client_mock_async.stub_request( @@ -98,7 +98,7 @@ async def test_get_async(self, http_client_mock_async): assert resp.body == expected_body - @pytest.mark.asyncio + @pytest.mark.anyio async def test_post_async(self, http_client_mock_async): expected_body = '{"id": "acc_123"}' http_client_mock_async.stub_request( @@ -124,7 +124,7 @@ async def test_post_async(self, http_client_mock_async): assert resp.body == expected_body - @pytest.mark.asyncio + @pytest.mark.anyio async def test_delete_async(self, http_client_mock_async): expected_body = '{"id": "acc_123"}' http_client_mock_async.stub_request( diff --git a/tests/test_raw_request.py b/tests/test_raw_request.py index f209b66eb..2e29b5b51 100644 --- a/tests/test_raw_request.py +++ b/tests/test_raw_request.py @@ -148,7 +148,7 @@ def test_preview_request_overridden_api_version(self, http_client_mock): is_json=True, ) - @pytest.mark.asyncio + @pytest.mark.anyio async def test_form_request_get_async(self, http_client_mock_async): http_client_mock_async.stub_request( "get", From fa7871a00f4562cac28f86a46e12864e552e1e9c Mon Sep 17 00:00:00 2001 From: Richard Marmorstein Date: Fri, 26 Jan 2024 12:00:59 -0800 Subject: [PATCH 3/6] Use anyio with trio better --- test-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test-requirements.txt b/test-requirements.txt index 2bcdf0f18..4479934d1 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,6 +2,7 @@ # This is the last version of httpx compatible with Python 3.6 httpx == 0.22.0 +anyio[trio] == 3.7.1 pytest-cov >= 2.8.1, < 2.11.0 pytest-mock >= 2.0.0 From 1efd9e8725e9ffd66ebd07485fbfb4394d5dae2f Mon Sep 17 00:00:00 2001 From: Richard Marmorstein Date: Fri, 26 Jan 2024 12:45:51 -0800 Subject: [PATCH 4/6] fixes --- stripe/_http_client.py | 1 - test-requirements.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/stripe/_http_client.py b/stripe/_http_client.py index 2dca1ff16..7202b9257 100644 --- a/stripe/_http_client.py +++ b/stripe/_http_client.py @@ -5,7 +5,6 @@ import random import threading import json -import asyncio # Used for global variables import stripe # noqa: IMP101 diff --git a/test-requirements.txt b/test-requirements.txt index 4479934d1..450a44767 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,7 +2,7 @@ # This is the last version of httpx compatible with Python 3.6 httpx == 0.22.0 -anyio[trio] == 3.7.1 +anyio[trio] == 3.6.2 pytest-cov >= 2.8.1, < 2.11.0 pytest-mock >= 2.0.0 From e64fe3cfd1038e1d2645cda78c1ea5c97a7a6982 Mon Sep 17 00:00:00 2001 From: Richard Marmorstein Date: Fri, 26 Jan 2024 12:49:05 -0800 Subject: [PATCH 5/6] Missed one after rebasing --- tests/test_integration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index b346beef2..24db28f06 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -366,7 +366,7 @@ def do_request(self, n): assert req.path == "/v1/customers" - @pytest.mark.asyncio + @pytest.mark.anyio async def test_async_httpx_raw_request_unretryable(self): class MockServerRequestHandler(MyTestHandler): def do_request(self, n): From b2bc5a5d4ded80e2dd5555bb98c0f3f0e35528c0 Mon Sep 17 00:00:00 2001 From: Richard Marmorstein Date: Fri, 26 Jan 2024 14:24:59 -0800 Subject: [PATCH 6/6] Better assertions --- stripe/_http_client.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/stripe/_http_client.py b/stripe/_http_client.py index 7202b9257..b99fa59a5 100644 --- a/stripe/_http_client.py +++ b/stripe/_http_client.py @@ -986,8 +986,16 @@ def __init__( ): super(HTTPXClient, self).__init__(**kwargs) - assert httpx is not None - assert anyio is not None + if httpx is None: + raise ImportError( + "Unexpected: tried to initialize HTTPXClient but the httpx module is not present." + ) + + if anyio is None: + raise ImportError( + "Unexpected: tried to initialize HTTPXClient but the anyio module is not present." + ) + self.httpx = httpx self.anyio = anyio