Skip to content

Commit 3173e5f

Browse files
feat(api): add Files API methods
...and mark them as undocumented.
1 parent c36bf61 commit 3173e5f

19 files changed

+1544
-158
lines changed

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 30
1+
configured_endpoints: 35
22
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/replicate%2Freplicate-client-efbc8cc2d74644b213e161d3e11e0589d1cef181fb318ea02c8eb6b00f245713.yml
33
openapi_spec_hash: 13da0c06c900b61cd98ab678e024987a
4-
config_hash: 927b6ebc00ee115763ad69483bbf5566
4+
config_hash: e25b98bb6202d27e54fc6e08c7de80d8

README.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ import os
2828
from replicate import Replicate
2929

3030
client = Replicate(
31-
bearer_token=os.environ.get("REPLICATE_API_TOKEN"), # This is the default and can be omitted
31+
api_key=os.environ.get("REPLICATE_CLIENT_API_KEY"), # This is the default and can be omitted
3232
)
3333

3434
account = client.account.get()
3535
print(account.type)
3636
```
3737

38-
While you can provide a `bearer_token` keyword argument,
38+
While you can provide an `api_key` keyword argument,
3939
we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
40-
to add `REPLICATE_API_TOKEN="My Bearer Token"` to your `.env` file
41-
so that your Bearer Token is not stored in source control.
40+
to add `REPLICATE_CLIENT_API_KEY="My API Key"` to your `.env` file
41+
so that your API Key is not stored in source control.
4242

4343
## Async usage
4444

@@ -50,7 +50,7 @@ import asyncio
5050
from replicate import AsyncReplicate
5151

5252
client = AsyncReplicate(
53-
bearer_token=os.environ.get("REPLICATE_API_TOKEN"), # This is the default and can be omitted
53+
api_key=os.environ.get("REPLICATE_CLIENT_API_KEY"), # This is the default and can be omitted
5454
)
5555

5656

@@ -136,6 +136,24 @@ for prediction in first_page.results:
136136
# Remove `await` for non-async usage.
137137
```
138138

139+
## File uploads
140+
141+
Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`.
142+
143+
```python
144+
from pathlib import Path
145+
from replicate import Replicate
146+
147+
client = Replicate()
148+
149+
client.files.create(
150+
content=Path("/path/to/file"),
151+
filename="filename",
152+
)
153+
```
154+
155+
The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically.
156+
139157
## Handling errors
140158

141159
When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `replicate.APIConnectionError` is raised.

api.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,11 @@ from replicate.types.webhooks.default import SecretGetResponse
154154
Methods:
155155

156156
- <code title="get /webhooks/default/secret">client.webhooks.default.secret.<a href="./src/replicate/resources/webhooks/default/secret.py">get</a>() -> <a href="./src/replicate/types/webhooks/default/secret_get_response.py">SecretGetResponse</a></code>
157+
158+
# Files
159+
160+
Types:
161+
162+
```python
163+
from replicate.types import FileCreateResponse, FileListResponse, FileGetResponse
164+
```

src/replicate/__init__.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104

105105
from ._base_client import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES
106106

107-
bearer_token: str | None = None
107+
api_key: str | None = None
108108

109109
base_url: str | _httpx.URL | None = None
110110

@@ -125,14 +125,14 @@ class _ModuleClient(Replicate):
125125

126126
@property # type: ignore
127127
@override
128-
def bearer_token(self) -> str | None:
129-
return bearer_token
128+
def api_key(self) -> str | None:
129+
return api_key
130130

131-
@bearer_token.setter # type: ignore
132-
def bearer_token(self, value: str | None) -> None: # type: ignore
133-
global bearer_token
131+
@api_key.setter # type: ignore
132+
def api_key(self, value: str | None) -> None: # type: ignore
133+
global api_key
134134

135-
bearer_token = value
135+
api_key = value
136136

137137
@property
138138
@override
@@ -210,7 +210,7 @@ def _load_client() -> Replicate: # type: ignore[reportUnusedFunction]
210210

211211
if _client is None:
212212
_client = _ModuleClient(
213-
bearer_token=bearer_token,
213+
api_key=api_key,
214214
base_url=base_url,
215215
timeout=timeout,
216216
max_retries=max_retries,
@@ -230,6 +230,7 @@ def _reset_client() -> None: # type: ignore[reportUnusedFunction]
230230

231231

232232
from ._module_client import (
233+
files as files,
233234
models as models,
234235
account as account,
235236
hardware as hardware,

src/replicate/_client.py

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
)
3232

3333
if TYPE_CHECKING:
34-
from .resources import models, account, hardware, webhooks, trainings, collections, deployments, predictions
34+
from .resources import files, models, account, hardware, webhooks, trainings, collections, deployments, predictions
35+
from .resources.files import FilesResource, AsyncFilesResource
3536
from .resources.account import AccountResource, AsyncAccountResource
3637
from .resources.hardware import HardwareResource, AsyncHardwareResource
3738
from .resources.trainings import TrainingsResource, AsyncTrainingsResource
@@ -55,12 +56,12 @@
5556

5657
class Replicate(SyncAPIClient):
5758
# client options
58-
bearer_token: str
59+
api_key: str
5960

6061
def __init__(
6162
self,
6263
*,
63-
bearer_token: str | None = None,
64+
api_key: str | None = None,
6465
base_url: str | httpx.URL | None = None,
6566
timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
6667
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -82,15 +83,15 @@ def __init__(
8283
) -> None:
8384
"""Construct a new synchronous Replicate client instance.
8485
85-
This automatically infers the `bearer_token` argument from the `REPLICATE_API_TOKEN` environment variable if it is not provided.
86+
This automatically infers the `api_key` argument from the `REPLICATE_CLIENT_API_KEY` environment variable if it is not provided.
8687
"""
87-
if bearer_token is None:
88-
bearer_token = os.environ.get("REPLICATE_API_TOKEN")
89-
if bearer_token is None:
88+
if api_key is None:
89+
api_key = os.environ.get("REPLICATE_CLIENT_API_KEY")
90+
if api_key is None:
9091
raise ReplicateError(
91-
"The bearer_token client option must be set either by passing bearer_token to the client or by setting the REPLICATE_API_TOKEN environment variable"
92+
"The api_key client option must be set either by passing api_key to the client or by setting the REPLICATE_CLIENT_API_KEY environment variable"
9293
)
93-
self.bearer_token = bearer_token
94+
self.api_key = api_key
9495

9596
if base_url is None:
9697
base_url = os.environ.get("REPLICATE_BASE_URL")
@@ -156,6 +157,12 @@ def webhooks(self) -> WebhooksResource:
156157

157158
return WebhooksResource(self)
158159

160+
@cached_property
161+
def files(self) -> FilesResource:
162+
from .resources.files import FilesResource
163+
164+
return FilesResource(self)
165+
159166
@cached_property
160167
def with_raw_response(self) -> ReplicateWithRawResponse:
161168
return ReplicateWithRawResponse(self)
@@ -172,8 +179,8 @@ def qs(self) -> Querystring:
172179
@property
173180
@override
174181
def auth_headers(self) -> dict[str, str]:
175-
bearer_token = self.bearer_token
176-
return {"Authorization": f"Bearer {bearer_token}"}
182+
api_key = self.api_key
183+
return {"Authorization": f"Bearer {api_key}"}
177184

178185
@property
179186
@override
@@ -187,7 +194,7 @@ def default_headers(self) -> dict[str, str | Omit]:
187194
def copy(
188195
self,
189196
*,
190-
bearer_token: str | None = None,
197+
api_key: str | None = None,
191198
base_url: str | httpx.URL | None = None,
192199
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
193200
http_client: httpx.Client | None = None,
@@ -221,7 +228,7 @@ def copy(
221228

222229
http_client = http_client or self._client
223230
return self.__class__(
224-
bearer_token=bearer_token or self.bearer_token,
231+
api_key=api_key or self.api_key,
225232
base_url=base_url or self.base_url,
226233
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
227234
http_client=http_client,
@@ -271,12 +278,12 @@ def _make_status_error(
271278

272279
class AsyncReplicate(AsyncAPIClient):
273280
# client options
274-
bearer_token: str
281+
api_key: str
275282

276283
def __init__(
277284
self,
278285
*,
279-
bearer_token: str | None = None,
286+
api_key: str | None = None,
280287
base_url: str | httpx.URL | None = None,
281288
timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
282289
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -298,15 +305,15 @@ def __init__(
298305
) -> None:
299306
"""Construct a new async AsyncReplicate client instance.
300307
301-
This automatically infers the `bearer_token` argument from the `REPLICATE_API_TOKEN` environment variable if it is not provided.
308+
This automatically infers the `api_key` argument from the `REPLICATE_CLIENT_API_KEY` environment variable if it is not provided.
302309
"""
303-
if bearer_token is None:
304-
bearer_token = os.environ.get("REPLICATE_API_TOKEN")
305-
if bearer_token is None:
310+
if api_key is None:
311+
api_key = os.environ.get("REPLICATE_CLIENT_API_KEY")
312+
if api_key is None:
306313
raise ReplicateError(
307-
"The bearer_token client option must be set either by passing bearer_token to the client or by setting the REPLICATE_API_TOKEN environment variable"
314+
"The api_key client option must be set either by passing api_key to the client or by setting the REPLICATE_CLIENT_API_KEY environment variable"
308315
)
309-
self.bearer_token = bearer_token
316+
self.api_key = api_key
310317

311318
if base_url is None:
312319
base_url = os.environ.get("REPLICATE_BASE_URL")
@@ -372,6 +379,12 @@ def webhooks(self) -> AsyncWebhooksResource:
372379

373380
return AsyncWebhooksResource(self)
374381

382+
@cached_property
383+
def files(self) -> AsyncFilesResource:
384+
from .resources.files import AsyncFilesResource
385+
386+
return AsyncFilesResource(self)
387+
375388
@cached_property
376389
def with_raw_response(self) -> AsyncReplicateWithRawResponse:
377390
return AsyncReplicateWithRawResponse(self)
@@ -388,8 +401,8 @@ def qs(self) -> Querystring:
388401
@property
389402
@override
390403
def auth_headers(self) -> dict[str, str]:
391-
bearer_token = self.bearer_token
392-
return {"Authorization": f"Bearer {bearer_token}"}
404+
api_key = self.api_key
405+
return {"Authorization": f"Bearer {api_key}"}
393406

394407
@property
395408
@override
@@ -403,7 +416,7 @@ def default_headers(self) -> dict[str, str | Omit]:
403416
def copy(
404417
self,
405418
*,
406-
bearer_token: str | None = None,
419+
api_key: str | None = None,
407420
base_url: str | httpx.URL | None = None,
408421
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
409422
http_client: httpx.AsyncClient | None = None,
@@ -437,7 +450,7 @@ def copy(
437450

438451
http_client = http_client or self._client
439452
return self.__class__(
440-
bearer_token=bearer_token or self.bearer_token,
453+
api_key=api_key or self.api_key,
441454
base_url=base_url or self.base_url,
442455
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
443456
http_client=http_client,
@@ -539,6 +552,12 @@ def webhooks(self) -> webhooks.WebhooksResourceWithRawResponse:
539552

540553
return WebhooksResourceWithRawResponse(self._client.webhooks)
541554

555+
@cached_property
556+
def files(self) -> files.FilesResourceWithRawResponse:
557+
from .resources.files import FilesResourceWithRawResponse
558+
559+
return FilesResourceWithRawResponse(self._client.files)
560+
542561

543562
class AsyncReplicateWithRawResponse:
544563
_client: AsyncReplicate
@@ -594,6 +613,12 @@ def webhooks(self) -> webhooks.AsyncWebhooksResourceWithRawResponse:
594613

595614
return AsyncWebhooksResourceWithRawResponse(self._client.webhooks)
596615

616+
@cached_property
617+
def files(self) -> files.AsyncFilesResourceWithRawResponse:
618+
from .resources.files import AsyncFilesResourceWithRawResponse
619+
620+
return AsyncFilesResourceWithRawResponse(self._client.files)
621+
597622

598623
class ReplicateWithStreamedResponse:
599624
_client: Replicate
@@ -649,6 +674,12 @@ def webhooks(self) -> webhooks.WebhooksResourceWithStreamingResponse:
649674

650675
return WebhooksResourceWithStreamingResponse(self._client.webhooks)
651676

677+
@cached_property
678+
def files(self) -> files.FilesResourceWithStreamingResponse:
679+
from .resources.files import FilesResourceWithStreamingResponse
680+
681+
return FilesResourceWithStreamingResponse(self._client.files)
682+
652683

653684
class AsyncReplicateWithStreamedResponse:
654685
_client: AsyncReplicate
@@ -704,6 +735,12 @@ def webhooks(self) -> webhooks.AsyncWebhooksResourceWithStreamingResponse:
704735

705736
return AsyncWebhooksResourceWithStreamingResponse(self._client.webhooks)
706737

738+
@cached_property
739+
def files(self) -> files.AsyncFilesResourceWithStreamingResponse:
740+
from .resources.files import AsyncFilesResourceWithStreamingResponse
741+
742+
return AsyncFilesResourceWithStreamingResponse(self._client.files)
743+
707744

708745
Client = Replicate
709746

src/replicate/_files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def assert_is_file_content(obj: object, *, key: str | None = None) -> None:
3434
if not is_file_content(obj):
3535
prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`"
3636
raise RuntimeError(
37-
f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead."
37+
f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead. See https://github.com/replicate/replicate-python-stainless/tree/main#file-uploads"
3838
) from None
3939

4040

src/replicate/_module_client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from typing_extensions import override
77

88
if TYPE_CHECKING:
9+
from .resources.files import FilesResource
910
from .resources.account import AccountResource
1011
from .resources.hardware import HardwareResource
1112
from .resources.trainings import TrainingsResource
@@ -19,6 +20,12 @@
1920
from ._utils import LazyProxy
2021

2122

23+
class FilesResourceProxy(LazyProxy["FilesResource"]):
24+
@override
25+
def __load__(self) -> FilesResource:
26+
return _load_client().files
27+
28+
2229
class ModelsResourceProxy(LazyProxy["ModelsResource"]):
2330
@override
2431
def __load__(self) -> ModelsResource:
@@ -67,6 +74,7 @@ def __load__(self) -> PredictionsResource:
6774
return _load_client().predictions
6875

6976

77+
files: FilesResource = FilesResourceProxy().__as_proxied__()
7078
models: ModelsResource = ModelsResourceProxy().__as_proxied__()
7179
account: AccountResource = AccountResourceProxy().__as_proxied__()
7280
hardware: HardwareResource = HardwareResourceProxy().__as_proxied__()

0 commit comments

Comments
 (0)