Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,26 @@ resp = client.request(
)
```

### Customizing the Transport Layer

If you need to configure custom retry logic, proxies, or use a different HTTP client (such as passing a `requests.Session` with a custom urllib3 `Retry`), you can inject it directly using the `client` parameter on any SDK class:

```python
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from openapi_python_sdk import Client
import requests

retry = Retry(total=3)
adapter = HTTPAdapter(max_retries=retry)

session = requests.Session()
session.mount("https://", adapter)

# Pass the custom session to the Client explicitly
client = Client("token", client=session)
```

## Async Usage

The SDK provides `AsyncClient` and `AsyncOauthClient` for use with asynchronous frameworks like FastAPI or `aiohttp`.
Expand Down
4 changes: 2 additions & 2 deletions openapi_python_sdk/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ class AsyncClient:
Suitable for use with FastAPI, aiohttp, etc.
"""

def __init__(self, token: str):
self.client = httpx.AsyncClient()
def __init__(self, token: str, client: Any = None):
self.client = client if client is not None else httpx.AsyncClient()
self.auth_header: str = f"Bearer {token}"
self.headers: Dict[str, str] = {
"Authorization": self.auth_header,
Expand Down
4 changes: 2 additions & 2 deletions openapi_python_sdk/async_oauth_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class AsyncOauthClient:
Suitable for use with FastAPI, aiohttp, etc.
"""

def __init__(self, username: str, apikey: str, test: bool = False):
self.client = httpx.AsyncClient()
def __init__(self, username: str, apikey: str, test: bool = False, client: Any = None):
self.client = client if client is not None else httpx.AsyncClient()
self.url: str = TEST_OAUTH_BASE_URL if test else OAUTH_BASE_URL
self.auth_header: str = (
"Basic " + base64.b64encode(f"{username}:{apikey}".encode("utf-8")).decode()
Expand Down
4 changes: 2 additions & 2 deletions openapi_python_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class Client:
Synchronous client for making authenticated requests to Openapi endpoints.
"""

def __init__(self, token: str):
self.client = httpx.Client()
def __init__(self, token: str, client: Any = None):
self.client = client if client is not None else httpx.Client()
self.auth_header: str = f"Bearer {token}"
self.headers: Dict[str, str] = {
"Authorization": self.auth_header,
Expand Down
4 changes: 2 additions & 2 deletions openapi_python_sdk/oauth_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class OauthClient:
Synchronous client for handling Openapi authentication and token management.
"""

def __init__(self, username: str, apikey: str, test: bool = False):
self.client = httpx.Client()
def __init__(self, username: str, apikey: str, test: bool = False, client: Any = None):
self.client = client if client is not None else httpx.Client()
self.url: str = TEST_OAUTH_BASE_URL if test else OAUTH_BASE_URL
self.auth_header: str = (
"Basic " + base64.b64encode(f"{username}:{apikey}".encode("utf-8")).decode()
Expand Down
10 changes: 10 additions & 0 deletions tests/test_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ async def test_get_scopes(self, mock_httpx):
await oauth.aclose()
mock_httpx.return_value.aclose.assert_called_once()

def test_custom_client_transport(self):
custom_client = MagicMock()
oauth = AsyncOauthClient(username="user", apikey="key", client=custom_client)
self.assertEqual(oauth.client, custom_client)


class TestAsyncClient(unittest.IsolatedAsyncioTestCase):
"""
Expand Down Expand Up @@ -85,6 +90,11 @@ async def test_request_post(self, mock_httpx):
await client.aclose()
mock_httpx.return_value.aclose.assert_called_once()

def test_custom_client_transport(self):
custom_client = MagicMock()
client = AsyncClient(token="abc123", client=custom_client)
self.assertEqual(client.client, custom_client)


if __name__ == "__main__":
unittest.main()
10 changes: 10 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ def test_auth_header_is_basic(self, mock_httpx):
oauth = OauthClient(username="user", apikey="key")
self.assertTrue(oauth.auth_header.startswith("Basic "))

def test_custom_client_transport(self):
custom_client = MagicMock()
oauth = OauthClient(username="user", apikey="key", client=custom_client)
self.assertEqual(oauth.client, custom_client)


class TestClient(unittest.TestCase):

Expand Down Expand Up @@ -109,6 +114,11 @@ def test_defaults_on_empty_request(self, mock_httpx):
method="GET", url="", headers=client.headers, json={}, params={}
)

def test_custom_client_transport(self):
custom_client = MagicMock()
client = Client(token="tok", client=custom_client)
self.assertEqual(client.client, custom_client)


if __name__ == "__main__":
unittest.main()
Loading