Skip to content

Commit f30dc0d

Browse files
authored
Document and fix behavior of custom client instances (#318)
In #268, we allowed custom headers to be passed to client instances. However, that didn't apply any custom `User-Agent` header. This is now fixed. This PR also updates the README to document how to create a custom client instance, incorporating this new behavior. This PR is an alternative to #304. --------- Signed-off-by: Mattt Zmuda <[email protected]>
1 parent 510233d commit f30dc0d

File tree

4 files changed

+43
-10
lines changed

4 files changed

+43
-10
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,33 @@ training = replicate.trainings.create(
359359
)
360360
```
361361

362+
## Customize client behavior
363+
364+
The `replicate` package exports a default shared client.
365+
This client is initialized with an API token
366+
set by the `REPLICATE_API_TOKEN` environment variable.
367+
368+
You can create your own client instance to
369+
pass a different API token value,
370+
add custom headers to requests,
371+
or control the behavior of the underlying [HTTPX client](https://www.python-httpx.org/api/#client):
372+
373+
```python
374+
import os
375+
from replicate.client import Client
376+
377+
replicate = Client(
378+
api_token=os.environ["SOME_OTHER_REPLICATE_API_TOKEN"]
379+
headers={
380+
"User-Agent": "my-app/1.0
381+
}
382+
)
383+
```
384+
385+
> [!WARNING]
386+
> Never hardcode authentication credentials like API tokens into your code.
387+
> Instead, pass them as environment variables when running your program.
388+
362389
## Development
363390

364391
See [CONTRIBUTING.md](CONTRIBUTING.md)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,5 @@ ignore = [
8080
"S101", # Use of assert
8181
"S106", # Possible use of hard-coded password function arguments
8282
"ANN201", # Missing return type annotation for public function
83+
"ANN202", # Missing return type annotation for private function
8384
]

replicate/client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,11 +330,11 @@ def _build_httpx_client(
330330
**kwargs,
331331
) -> Union[httpx.Client, httpx.AsyncClient]:
332332
headers = kwargs.pop("headers", {})
333-
headers["User-Agent"] = f"replicate-python/{__version__}"
334-
335-
if (
333+
if "User-Agent" not in headers:
334+
headers["User-Agent"] = f"replicate-python/{__version__}"
335+
if "Authorization" not in headers and (
336336
api_token := api_token or os.environ.get("REPLICATE_API_TOKEN")
337-
) and api_token != "":
337+
):
338338
headers["Authorization"] = f"Bearer {api_token}"
339339

340340
base_url = (

tests/test_client.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,21 +91,26 @@ def test_custom_headers_are_applied():
9191
import replicate
9292
from replicate.exceptions import ReplicateError
9393

94-
custom_headers = {"Custom-Header": "CustomValue"}
95-
96-
def mock_send(request: httpx.Request, **kwargs) -> httpx.Response:
97-
assert "Custom-Header" in request.headers
98-
assert request.headers["Custom-Header"] == "CustomValue"
94+
custom_headers = {"User-Agent": "my-custom-user-agent/1.0"}
9995

96+
def mock_send(request):
97+
assert "User-Agent" in request.headers, "Custom header not found in request"
98+
assert (
99+
request.headers["User-Agent"] == "my-custom-user-agent/1.0"
100+
), "Custom header value is incorrect"
100101
return httpx.Response(401, json={})
101102

103+
mock_send_wrapper = mock.Mock(side_effect=mock_send)
104+
102105
client = replicate.Client(
103106
api_token="dummy_token",
104107
headers=custom_headers,
105-
transport=httpx.MockTransport(mock_send),
108+
transport=httpx.MockTransport(mock_send_wrapper),
106109
)
107110

108111
try:
109112
client.accounts.current()
110113
except ReplicateError:
111114
pass
115+
116+
mock_send_wrapper.assert_called_once()

0 commit comments

Comments
 (0)