From d10f1a30377586de7a935491342b63e9e987c5b0 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Mon, 12 May 2025 17:21:34 +0000 Subject: [PATCH 1/3] feat: allow injection of httpx client --- supabase_functions/_async/functions_client.py | 25 ++++++++++++------- supabase_functions/_sync/functions_client.py | 25 ++++++++++++------- tests/_async/test_function_client.py | 25 ++++++++++++++++++- tests/_sync/test_function_client.py | 25 ++++++++++++++++++- 4 files changed, 80 insertions(+), 20 deletions(-) diff --git a/supabase_functions/_async/functions_client.py b/supabase_functions/_async/functions_client.py index ba12dbb..a681cb6 100644 --- a/supabase_functions/_async/functions_client.py +++ b/supabase_functions/_async/functions_client.py @@ -22,6 +22,7 @@ def __init__( timeout: int, verify: bool = True, proxy: Optional[str] = None, + http_client: Optional[AsyncClient] = None, ): if not is_http_url(url): raise ValueError("url must be a valid HTTP URL string") @@ -30,15 +31,21 @@ def __init__( "User-Agent": f"supabase-py/functions-py v{__version__}", **headers, } - self._client = AsyncClient( - base_url=self.url, - headers=self.headers, - verify=bool(verify), - timeout=int(abs(timeout)), - proxy=proxy, - follow_redirects=True, - http2=True, - ) + + if http_client is not None: + http_client.base_url = self.url + http_client.headers.update({**self.headers}) + self._client = http_client + else: + self._client = AsyncClient( + base_url=self.url, + headers=self.headers, + verify=bool(verify), + timeout=int(abs(timeout)), + proxy=proxy, + follow_redirects=True, + http2=True, + ) async def _request( self, diff --git a/supabase_functions/_sync/functions_client.py b/supabase_functions/_sync/functions_client.py index d8a410f..bfb3dbf 100644 --- a/supabase_functions/_sync/functions_client.py +++ b/supabase_functions/_sync/functions_client.py @@ -22,6 +22,7 @@ def __init__( timeout: int, verify: bool = True, proxy: Optional[str] = None, + http_client: Optional[SyncClient] = None, ): if not is_http_url(url): raise ValueError("url must be a valid HTTP URL string") @@ -30,15 +31,21 @@ def __init__( "User-Agent": f"supabase-py/functions-py v{__version__}", **headers, } - self._client = SyncClient( - base_url=self.url, - headers=self.headers, - verify=bool(verify), - timeout=int(abs(timeout)), - proxy=proxy, - follow_redirects=True, - http2=True, - ) + + if http_client is not None: + http_client.base_url = self.url + http_client.headers.update({**self.headers}) + self._client = http_client + else: + self._client = SyncClient( + base_url=self.url, + headers=self.headers, + verify=bool(verify), + timeout=int(abs(timeout)), + proxy=proxy, + follow_redirects=True, + http2=True, + ) def _request( self, diff --git a/tests/_async/test_function_client.py b/tests/_async/test_function_client.py index e2ee513..158b6fe 100644 --- a/tests/_async/test_function_client.py +++ b/tests/_async/test_function_client.py @@ -6,7 +6,7 @@ # Import the class to test from supabase_functions import AsyncFunctionsClient from supabase_functions.errors import FunctionsHttpError, FunctionsRelayError -from supabase_functions.utils import FunctionRegion +from supabase_functions.utils import AsyncClient, FunctionRegion from supabase_functions.version import __version__ @@ -197,3 +197,26 @@ async def test_invoke_with_json_body(client: AsyncFunctionsClient): _, kwargs = mock_request.call_args assert kwargs["headers"]["Content-Type"] == "application/json" + + +async def test_init_with_httpx_client(): + # Create a custom httpx client with specific options + custom_client = AsyncClient( + timeout=Timeout(30), follow_redirects=True, max_redirects=5 + ) + + # Initialize the functions client with the custom httpx client + client = AsyncFunctionsClient( + url="https://example.com", + headers={"Authorization": "Bearer token"}, + timeout=30, + http_client=custom_client, + ) + + # Verify the custom client options are preserved + assert client._client.timeout == Timeout(30) + assert client._client.follow_redirects is True + assert client._client.max_redirects == 5 + + # Verify the client is properly configured with our custom client + assert client._client is custom_client diff --git a/tests/_sync/test_function_client.py b/tests/_sync/test_function_client.py index d11bc11..037ea07 100644 --- a/tests/_sync/test_function_client.py +++ b/tests/_sync/test_function_client.py @@ -6,7 +6,7 @@ # Import the class to test from supabase_functions import SyncFunctionsClient from supabase_functions.errors import FunctionsHttpError, FunctionsRelayError -from supabase_functions.utils import FunctionRegion +from supabase_functions.utils import FunctionRegion, SyncClient from supabase_functions.version import __version__ @@ -181,3 +181,26 @@ def test_invoke_with_json_body(client: SyncFunctionsClient): _, kwargs = mock_request.call_args assert kwargs["headers"]["Content-Type"] == "application/json" + + +def test_init_with_httpx_client(): + # Create a custom httpx client with specific options + custom_client = SyncClient( + timeout=Timeout(30), follow_redirects=True, max_redirects=5 + ) + + # Initialize the functions client with the custom httpx client + client = SyncFunctionsClient( + url="https://example.com", + headers={"Authorization": "Bearer token"}, + timeout=30, + http_client=custom_client, + ) + + # Verify the custom client options are preserved + assert client._client.timeout == Timeout(30) + assert client._client.follow_redirects is True + assert client._client.max_redirects == 5 + + # Verify the client is properly configured with our custom client + assert client._client is custom_client From 9a00193b620b6cc06b243c09a4d92357fef657f4 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Wed, 14 May 2025 15:27:33 +0000 Subject: [PATCH 2/3] fix: add deprecation warnings for params to remove in the future --- supabase_functions/_async/functions_client.py | 30 ++++++++++++++++--- supabase_functions/_sync/functions_client.py | 30 ++++++++++++++++--- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/supabase_functions/_async/functions_client.py b/supabase_functions/_async/functions_client.py index a681cb6..58035bf 100644 --- a/supabase_functions/_async/functions_client.py +++ b/supabase_functions/_async/functions_client.py @@ -19,8 +19,8 @@ def __init__( self, url: str, headers: Dict, - timeout: int, - verify: bool = True, + timeout: Optional[int] = None, + verify: Optional[bool] = None, proxy: Optional[str] = None, http_client: Optional[AsyncClient] = None, ): @@ -32,6 +32,28 @@ def __init__( **headers, } + if timeout is not None: + warn( + "The 'timeout' parameter is deprecated. Please configure it in the httpx client instead.", + DeprecationWarning, + stacklevel=2, + ) + if verify is not None: + warn( + "The 'verify' parameter is deprecated. Please configure it in the httpx client instead.", + DeprecationWarning, + stacklevel=2, + ) + if proxy is not None: + warn( + "The 'proxy' parameter is deprecated. Please configure it in the httpx client instead.", + DeprecationWarning, + stacklevel=2, + ) + + self.verify = bool(verify) if verify is not None else True + self.timeout = int(abs(timeout)) if timeout is not None else 60 + if http_client is not None: http_client.base_url = self.url http_client.headers.update({**self.headers}) @@ -40,8 +62,8 @@ def __init__( self._client = AsyncClient( base_url=self.url, headers=self.headers, - verify=bool(verify), - timeout=int(abs(timeout)), + verify=self.verify, + timeout=self.timeout, proxy=proxy, follow_redirects=True, http2=True, diff --git a/supabase_functions/_sync/functions_client.py b/supabase_functions/_sync/functions_client.py index bfb3dbf..0750786 100644 --- a/supabase_functions/_sync/functions_client.py +++ b/supabase_functions/_sync/functions_client.py @@ -19,8 +19,8 @@ def __init__( self, url: str, headers: Dict, - timeout: int, - verify: bool = True, + timeout: Optional[int] = None, + verify: Optional[bool] = None, proxy: Optional[str] = None, http_client: Optional[SyncClient] = None, ): @@ -32,6 +32,28 @@ def __init__( **headers, } + if timeout is not None: + warn( + "The 'timeout' parameter is deprecated. Please configure it in the httpx client instead.", + DeprecationWarning, + stacklevel=2, + ) + if verify is not None: + warn( + "The 'verify' parameter is deprecated. Please configure it in the httpx client instead.", + DeprecationWarning, + stacklevel=2, + ) + if proxy is not None: + warn( + "The 'proxy' parameter is deprecated. Please configure it in the httpx client instead.", + DeprecationWarning, + stacklevel=2, + ) + + self.verify = bool(verify) if verify is not None else True + self.timeout = int(abs(timeout)) if timeout is not None else 60 + if http_client is not None: http_client.base_url = self.url http_client.headers.update({**self.headers}) @@ -40,8 +62,8 @@ def __init__( self._client = SyncClient( base_url=self.url, headers=self.headers, - verify=bool(verify), - timeout=int(abs(timeout)), + verify=self.verify, + timeout=self.timeout, proxy=proxy, follow_redirects=True, http2=True, From f540e3703bbfc46e1fb3eb3dad957b88c47dd051 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Wed, 14 May 2025 21:42:21 +0000 Subject: [PATCH 3/3] fix: update deprecation message --- supabase_functions/_async/functions_client.py | 6 +++--- supabase_functions/_sync/functions_client.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/supabase_functions/_async/functions_client.py b/supabase_functions/_async/functions_client.py index 58035bf..72f3bb2 100644 --- a/supabase_functions/_async/functions_client.py +++ b/supabase_functions/_async/functions_client.py @@ -34,19 +34,19 @@ def __init__( if timeout is not None: warn( - "The 'timeout' parameter is deprecated. Please configure it in the httpx client instead.", + "The 'timeout' parameter is deprecated. Please configure it in the http client instead.", DeprecationWarning, stacklevel=2, ) if verify is not None: warn( - "The 'verify' parameter is deprecated. Please configure it in the httpx client instead.", + "The 'verify' parameter is deprecated. Please configure it in the http client instead.", DeprecationWarning, stacklevel=2, ) if proxy is not None: warn( - "The 'proxy' parameter is deprecated. Please configure it in the httpx client instead.", + "The 'proxy' parameter is deprecated. Please configure it in the http client instead.", DeprecationWarning, stacklevel=2, ) diff --git a/supabase_functions/_sync/functions_client.py b/supabase_functions/_sync/functions_client.py index 0750786..1e607b2 100644 --- a/supabase_functions/_sync/functions_client.py +++ b/supabase_functions/_sync/functions_client.py @@ -34,19 +34,19 @@ def __init__( if timeout is not None: warn( - "The 'timeout' parameter is deprecated. Please configure it in the httpx client instead.", + "The 'timeout' parameter is deprecated. Please configure it in the http client instead.", DeprecationWarning, stacklevel=2, ) if verify is not None: warn( - "The 'verify' parameter is deprecated. Please configure it in the httpx client instead.", + "The 'verify' parameter is deprecated. Please configure it in the http client instead.", DeprecationWarning, stacklevel=2, ) if proxy is not None: warn( - "The 'proxy' parameter is deprecated. Please configure it in the httpx client instead.", + "The 'proxy' parameter is deprecated. Please configure it in the http client instead.", DeprecationWarning, stacklevel=2, )