Skip to content

Commit 39bf149

Browse files
feat(api): api update
1 parent fa9cdd1 commit 39bf149

34 files changed

Lines changed: 1754 additions & 200 deletions

.stats.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 36
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/nen-labs%2Fsteel-6f8dc0942cdc81f2adc752ae5b24748e288452f8bfac26d7b64143c57fb999c0.yml
3-
openapi_spec_hash: 809a6df32a171c658fa792064093e1d8
4-
config_hash: e49b3f69d57d7ffa0420acf772d5c846
1+
configured_endpoints: 38
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/nen-labs%2Fsteel-97dcad9b050e2818332d548e93c2882fa5482df4dca384ce7f8d3cabdfd92b69.yml
3+
openapi_spec_hash: 8d3fa51c0740046e4caf2a299ba9d89e
4+
config_hash: 03d8eae69b6431c0ae0566dddaa9b0ea

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,23 @@ session = client.sessions.create(
193193
print(session.credentials)
194194
```
195195

196+
## File uploads
197+
198+
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)`.
199+
200+
```python
201+
from pathlib import Path
202+
from steel import Steel
203+
204+
client = Steel()
205+
206+
client.files.upload(
207+
file=Path("/path/to/file"),
208+
)
209+
```
210+
211+
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.
212+
196213
## Handling errors
197214

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

api.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,17 @@ Methods:
129129
Types:
130130

131131
```python
132-
from steel.types import ProfileCreateResponse, ProfileListResponse
132+
from steel.types import (
133+
ProfileCreateResponse,
134+
ProfileUpdateResponse,
135+
ProfileListResponse,
136+
ProfileGetResponse,
137+
)
133138
```
134139

135140
Methods:
136141

137142
- <code title="post /v1/profiles">client.profiles.<a href="./src/steel/resources/profiles.py">create</a>(\*\*<a href="src/steel/types/profile_create_params.py">params</a>) -> <a href="./src/steel/types/profile_create_response.py">ProfileCreateResponse</a></code>
143+
- <code title="patch /v1/profiles/{id}">client.profiles.<a href="./src/steel/resources/profiles.py">update</a>(id, \*\*<a href="src/steel/types/profile_update_params.py">params</a>) -> <a href="./src/steel/types/profile_update_response.py">ProfileUpdateResponse</a></code>
138144
- <code title="get /v1/profiles">client.profiles.<a href="./src/steel/resources/profiles.py">list</a>() -> <a href="./src/steel/types/profile_list_response.py">ProfileListResponse</a></code>
145+
- <code title="get /v1/profiles/{id}">client.profiles.<a href="./src/steel/resources/profiles.py">get</a>(id) -> <a href="./src/steel/types/profile_get_response.py">ProfileGetResponse</a></code>

src/steel/_client.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def pdf(
228228
*,
229229
url: str,
230230
delay: float | Omit = omit,
231-
region: str | Omit = omit,
231+
region: object | Omit = omit,
232232
use_proxy: bool | Omit = omit,
233233
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
234234
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -281,7 +281,7 @@ def scrape(
281281
delay: float | Omit = omit,
282282
format: List[Literal["html", "readability", "cleaned_html", "markdown"]] | Omit = omit,
283283
pdf: bool | Omit = omit,
284-
region: str | Omit = omit,
284+
region: object | Omit = omit,
285285
screenshot: bool | Omit = omit,
286286
use_proxy: bool | Omit = omit,
287287
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -343,7 +343,7 @@ def screenshot(
343343
url: str,
344344
delay: float | Omit = omit,
345345
full_page: bool | Omit = omit,
346-
region: str | Omit = omit,
346+
region: object | Omit = omit,
347347
use_proxy: bool | Omit = omit,
348348
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
349349
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -593,7 +593,7 @@ async def pdf(
593593
*,
594594
url: str,
595595
delay: float | Omit = omit,
596-
region: str | Omit = omit,
596+
region: object | Omit = omit,
597597
use_proxy: bool | Omit = omit,
598598
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
599599
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -646,7 +646,7 @@ async def scrape(
646646
delay: float | Omit = omit,
647647
format: List[Literal["html", "readability", "cleaned_html", "markdown"]] | Omit = omit,
648648
pdf: bool | Omit = omit,
649-
region: str | Omit = omit,
649+
region: object | Omit = omit,
650650
screenshot: bool | Omit = omit,
651651
use_proxy: bool | Omit = omit,
652652
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -708,7 +708,7 @@ async def screenshot(
708708
url: str,
709709
delay: float | Omit = omit,
710710
full_page: bool | Omit = omit,
711-
region: str | Omit = omit,
711+
region: object | Omit = omit,
712712
use_proxy: bool | Omit = omit,
713713
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
714714
# The extra values given here take precedence over values defined on the client or passed to this method.

src/steel/_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/steel-dev/steel-python/tree/main#file-uploads"
3838
) from None
3939

4040

src/steel/resources/extensions.py

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
from __future__ import annotations
44

5+
from typing import Mapping, cast
6+
57
import httpx
68

79
from ..types import extension_update_params, extension_upload_params
8-
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
9-
from .._utils import maybe_transform, async_maybe_transform
10+
from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given
11+
from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform
1012
from .._compat import cached_property
1113
from .._resource import SyncAPIResource, AsyncAPIResource
1214
from .._response import (
@@ -49,7 +51,7 @@ def update(
4951
self,
5052
extension_id: str,
5153
*,
52-
file: object | Omit = omit,
54+
file: FileTypes | Omit = omit,
5355
url: str | Omit = omit,
5456
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
5557
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -77,19 +79,21 @@ def update(
7779
"""
7880
if not extension_id:
7981
raise ValueError(f"Expected a non-empty value for `extension_id` but received {extension_id!r}")
82+
body = deepcopy_minimal(
83+
{
84+
"file": file,
85+
"url": url,
86+
}
87+
)
88+
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
8089
# It should be noted that the actual Content-Type header that will be
8190
# sent to the server will contain a `boundary` parameter, e.g.
8291
# multipart/form-data; boundary=---abc--
8392
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
8493
return self._put(
8594
f"/v1/extensions/{extension_id}",
86-
body=maybe_transform(
87-
{
88-
"file": file,
89-
"url": url,
90-
},
91-
extension_update_params.ExtensionUpdateParams,
92-
),
95+
body=maybe_transform(body, extension_update_params.ExtensionUpdateParams),
96+
files=files,
9397
options=make_request_options(
9498
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
9599
),
@@ -203,7 +207,7 @@ def download(
203207
def upload(
204208
self,
205209
*,
206-
file: object | Omit = omit,
210+
file: FileTypes | Omit = omit,
207211
url: str | Omit = omit,
208212
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
209213
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -229,19 +233,21 @@ def upload(
229233
230234
timeout: Override the client-level default timeout for this request, in seconds
231235
"""
236+
body = deepcopy_minimal(
237+
{
238+
"file": file,
239+
"url": url,
240+
}
241+
)
242+
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
232243
# It should be noted that the actual Content-Type header that will be
233244
# sent to the server will contain a `boundary` parameter, e.g.
234245
# multipart/form-data; boundary=---abc--
235246
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
236247
return self._post(
237248
"/v1/extensions",
238-
body=maybe_transform(
239-
{
240-
"file": file,
241-
"url": url,
242-
},
243-
extension_upload_params.ExtensionUploadParams,
244-
),
249+
body=maybe_transform(body, extension_upload_params.ExtensionUploadParams),
250+
files=files,
245251
options=make_request_options(
246252
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
247253
),
@@ -273,7 +279,7 @@ async def update(
273279
self,
274280
extension_id: str,
275281
*,
276-
file: object | Omit = omit,
282+
file: FileTypes | Omit = omit,
277283
url: str | Omit = omit,
278284
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
279285
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -301,19 +307,21 @@ async def update(
301307
"""
302308
if not extension_id:
303309
raise ValueError(f"Expected a non-empty value for `extension_id` but received {extension_id!r}")
310+
body = deepcopy_minimal(
311+
{
312+
"file": file,
313+
"url": url,
314+
}
315+
)
316+
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
304317
# It should be noted that the actual Content-Type header that will be
305318
# sent to the server will contain a `boundary` parameter, e.g.
306319
# multipart/form-data; boundary=---abc--
307320
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
308321
return await self._put(
309322
f"/v1/extensions/{extension_id}",
310-
body=await async_maybe_transform(
311-
{
312-
"file": file,
313-
"url": url,
314-
},
315-
extension_update_params.ExtensionUpdateParams,
316-
),
323+
body=await async_maybe_transform(body, extension_update_params.ExtensionUpdateParams),
324+
files=files,
317325
options=make_request_options(
318326
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
319327
),
@@ -427,7 +435,7 @@ async def download(
427435
async def upload(
428436
self,
429437
*,
430-
file: object | Omit = omit,
438+
file: FileTypes | Omit = omit,
431439
url: str | Omit = omit,
432440
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
433441
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -453,19 +461,21 @@ async def upload(
453461
454462
timeout: Override the client-level default timeout for this request, in seconds
455463
"""
464+
body = deepcopy_minimal(
465+
{
466+
"file": file,
467+
"url": url,
468+
}
469+
)
470+
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
456471
# It should be noted that the actual Content-Type header that will be
457472
# sent to the server will contain a `boundary` parameter, e.g.
458473
# multipart/form-data; boundary=---abc--
459474
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
460475
return await self._post(
461476
"/v1/extensions",
462-
body=await async_maybe_transform(
463-
{
464-
"file": file,
465-
"url": url,
466-
},
467-
extension_upload_params.ExtensionUploadParams,
468-
),
477+
body=await async_maybe_transform(body, extension_upload_params.ExtensionUploadParams),
478+
files=files,
469479
options=make_request_options(
470480
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
471481
),

src/steel/resources/files.py

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
from __future__ import annotations
44

5+
from typing import Mapping, cast
6+
57
import httpx
68

79
from ..types import file_upload_params
8-
from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
9-
from .._utils import maybe_transform, async_maybe_transform
10+
from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, FileTypes, omit, not_given
11+
from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform
1012
from .._compat import cached_property
1113
from .._resource import SyncAPIResource, AsyncAPIResource
1214
from .._response import (
@@ -140,7 +142,7 @@ def download(
140142
def upload(
141143
self,
142144
*,
143-
file: object | Omit = omit,
145+
file: FileTypes,
144146
path: str | Omit = omit,
145147
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
146148
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -167,19 +169,21 @@ def upload(
167169
168170
timeout: Override the client-level default timeout for this request, in seconds
169171
"""
172+
body = deepcopy_minimal(
173+
{
174+
"file": file,
175+
"path": path,
176+
}
177+
)
178+
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
170179
# It should be noted that the actual Content-Type header that will be
171180
# sent to the server will contain a `boundary` parameter, e.g.
172181
# multipart/form-data; boundary=---abc--
173182
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
174183
return self._post(
175184
"/v1/files",
176-
body=maybe_transform(
177-
{
178-
"file": file,
179-
"path": path,
180-
},
181-
file_upload_params.FileUploadParams,
182-
),
185+
body=maybe_transform(body, file_upload_params.FileUploadParams),
186+
files=files,
183187
options=make_request_options(
184188
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
185189
),
@@ -297,7 +301,7 @@ async def download(
297301
async def upload(
298302
self,
299303
*,
300-
file: object | Omit = omit,
304+
file: FileTypes,
301305
path: str | Omit = omit,
302306
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
303307
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -324,19 +328,21 @@ async def upload(
324328
325329
timeout: Override the client-level default timeout for this request, in seconds
326330
"""
331+
body = deepcopy_minimal(
332+
{
333+
"file": file,
334+
"path": path,
335+
}
336+
)
337+
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
327338
# It should be noted that the actual Content-Type header that will be
328339
# sent to the server will contain a `boundary` parameter, e.g.
329340
# multipart/form-data; boundary=---abc--
330341
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
331342
return await self._post(
332343
"/v1/files",
333-
body=await async_maybe_transform(
334-
{
335-
"file": file,
336-
"path": path,
337-
},
338-
file_upload_params.FileUploadParams,
339-
),
344+
body=await async_maybe_transform(body, file_upload_params.FileUploadParams),
345+
files=files,
340346
options=make_request_options(
341347
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
342348
),

0 commit comments

Comments
 (0)