Skip to content

Commit 8dd199b

Browse files
feat(api): OpenAPI spec update via Stainless API (#184)
1 parent 3d606ed commit 8dd199b

6 files changed

Lines changed: 233 additions & 2 deletions

File tree

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
configured_endpoints: 26
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-fbdcac787258c36334017389efd318753b4e2eae259dc2ffc0cba579b24a1254.yml
1+
configured_endpoints: 27
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-d934c31884a197ffe8f114a062e2da781a4ea6e3df45b691d1f4dba30734a61b.yml

api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Methods:
6565
- <code title="get /v1/devboxes/{id}">client.devboxes.<a href="./src/runloop_api_client/resources/devboxes/devboxes.py">retrieve</a>(id) -> <a href="./src/runloop_api_client/types/devbox_view.py">DevboxView</a></code>
6666
- <code title="get /v1/devboxes">client.devboxes.<a href="./src/runloop_api_client/resources/devboxes/devboxes.py">list</a>(\*\*<a href="src/runloop_api_client/types/devbox_list_params.py">params</a>) -> <a href="./src/runloop_api_client/types/devbox_list_view.py">DevboxListView</a></code>
6767
- <code title="post /v1/devboxes/{id}/create_ssh_key">client.devboxes.<a href="./src/runloop_api_client/resources/devboxes/devboxes.py">create_ssh_key</a>(id) -> <a href="./src/runloop_api_client/types/devbox_create_ssh_key_response.py">DevboxCreateSSHKeyResponse</a></code>
68+
- <code title="post /v1/devboxes/{id}/download_file">client.devboxes.<a href="./src/runloop_api_client/resources/devboxes/devboxes.py">download_file</a>(id, \*\*<a href="src/runloop_api_client/types/devbox_download_file_params.py">params</a>) -> BinaryAPIResponse</code>
6869
- <code title="post /v1/devboxes/{id}/execute_async">client.devboxes.<a href="./src/runloop_api_client/resources/devboxes/devboxes.py">execute_async</a>(id, \*\*<a href="src/runloop_api_client/types/devbox_execute_async_params.py">params</a>) -> <a href="./src/runloop_api_client/types/devbox_async_execution_detail_view.py">DevboxAsyncExecutionDetailView</a></code>
6970
- <code title="post /v1/devboxes/{id}/execute_sync">client.devboxes.<a href="./src/runloop_api_client/resources/devboxes/devboxes.py">execute_sync</a>(id, \*\*<a href="src/runloop_api_client/types/devbox_execute_sync_params.py">params</a>) -> <a href="./src/runloop_api_client/types/devbox_execution_detail_view.py">DevboxExecutionDetailView</a></code>
7071
- <code title="post /v1/devboxes/{id}/read_file_contents">client.devboxes.<a href="./src/runloop_api_client/resources/devboxes/devboxes.py">read_file_contents</a>(id, \*\*<a href="src/runloop_api_client/types/devbox_read_file_contents_params.py">params</a>) -> str</code>

src/runloop_api_client/resources/devboxes/devboxes.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
devbox_write_file_params,
2121
devbox_upload_file_params,
2222
devbox_execute_sync_params,
23+
devbox_download_file_params,
2324
devbox_execute_async_params,
2425
devbox_read_file_contents_params,
2526
)
@@ -41,10 +42,18 @@
4142
)
4243
from ..._resource import SyncAPIResource, AsyncAPIResource
4344
from ..._response import (
45+
BinaryAPIResponse,
46+
AsyncBinaryAPIResponse,
47+
StreamedBinaryAPIResponse,
48+
AsyncStreamedBinaryAPIResponse,
4449
to_raw_response_wrapper,
4550
to_streamed_response_wrapper,
4651
async_to_raw_response_wrapper,
52+
to_custom_raw_response_wrapper,
4753
async_to_streamed_response_wrapper,
54+
to_custom_streamed_response_wrapper,
55+
async_to_custom_raw_response_wrapper,
56+
async_to_custom_streamed_response_wrapper,
4857
)
4958
from ..._base_client import make_request_options
5059
from ...types.devbox_view import DevboxView
@@ -291,6 +300,44 @@ def create_ssh_key(
291300
cast_to=DevboxCreateSSHKeyResponse,
292301
)
293302

303+
def download_file(
304+
self,
305+
id: str,
306+
*,
307+
path: str,
308+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
309+
# The extra values given here take precedence over values defined on the client or passed to this method.
310+
extra_headers: Headers | None = None,
311+
extra_query: Query | None = None,
312+
extra_body: Body | None = None,
313+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
314+
) -> BinaryAPIResponse:
315+
"""
316+
Download file contents to a file at path on the Devbox.
317+
318+
Args:
319+
path: The path on the devbox to read the file
320+
321+
extra_headers: Send extra headers
322+
323+
extra_query: Add additional query parameters to the request
324+
325+
extra_body: Add additional JSON properties to the request
326+
327+
timeout: Override the client-level default timeout for this request, in seconds
328+
"""
329+
if not id:
330+
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
331+
extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})}
332+
return self._post(
333+
f"/v1/devboxes/{id}/download_file",
334+
body=maybe_transform({"path": path}, devbox_download_file_params.DevboxDownloadFileParams),
335+
options=make_request_options(
336+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
337+
),
338+
cast_to=BinaryAPIResponse,
339+
)
340+
294341
def execute_async(
295342
self,
296343
id: str,
@@ -786,6 +833,44 @@ async def create_ssh_key(
786833
cast_to=DevboxCreateSSHKeyResponse,
787834
)
788835

836+
async def download_file(
837+
self,
838+
id: str,
839+
*,
840+
path: str,
841+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
842+
# The extra values given here take precedence over values defined on the client or passed to this method.
843+
extra_headers: Headers | None = None,
844+
extra_query: Query | None = None,
845+
extra_body: Body | None = None,
846+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
847+
) -> AsyncBinaryAPIResponse:
848+
"""
849+
Download file contents to a file at path on the Devbox.
850+
851+
Args:
852+
path: The path on the devbox to read the file
853+
854+
extra_headers: Send extra headers
855+
856+
extra_query: Add additional query parameters to the request
857+
858+
extra_body: Add additional JSON properties to the request
859+
860+
timeout: Override the client-level default timeout for this request, in seconds
861+
"""
862+
if not id:
863+
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
864+
extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})}
865+
return await self._post(
866+
f"/v1/devboxes/{id}/download_file",
867+
body=await async_maybe_transform({"path": path}, devbox_download_file_params.DevboxDownloadFileParams),
868+
options=make_request_options(
869+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
870+
),
871+
cast_to=AsyncBinaryAPIResponse,
872+
)
873+
789874
async def execute_async(
790875
self,
791876
id: str,
@@ -1063,6 +1148,10 @@ def __init__(self, devboxes: DevboxesResource) -> None:
10631148
self.create_ssh_key = to_raw_response_wrapper(
10641149
devboxes.create_ssh_key,
10651150
)
1151+
self.download_file = to_custom_raw_response_wrapper(
1152+
devboxes.download_file,
1153+
BinaryAPIResponse,
1154+
)
10661155
self.execute_async = to_raw_response_wrapper(
10671156
devboxes.execute_async,
10681157
)
@@ -1107,6 +1196,10 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None:
11071196
self.create_ssh_key = async_to_raw_response_wrapper(
11081197
devboxes.create_ssh_key,
11091198
)
1199+
self.download_file = async_to_custom_raw_response_wrapper(
1200+
devboxes.download_file,
1201+
AsyncBinaryAPIResponse,
1202+
)
11101203
self.execute_async = async_to_raw_response_wrapper(
11111204
devboxes.execute_async,
11121205
)
@@ -1151,6 +1244,10 @@ def __init__(self, devboxes: DevboxesResource) -> None:
11511244
self.create_ssh_key = to_streamed_response_wrapper(
11521245
devboxes.create_ssh_key,
11531246
)
1247+
self.download_file = to_custom_streamed_response_wrapper(
1248+
devboxes.download_file,
1249+
StreamedBinaryAPIResponse,
1250+
)
11541251
self.execute_async = to_streamed_response_wrapper(
11551252
devboxes.execute_async,
11561253
)
@@ -1195,6 +1292,10 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None:
11951292
self.create_ssh_key = async_to_streamed_response_wrapper(
11961293
devboxes.create_ssh_key,
11971294
)
1295+
self.download_file = async_to_custom_streamed_response_wrapper(
1296+
devboxes.download_file,
1297+
AsyncStreamedBinaryAPIResponse,
1298+
)
11981299
self.execute_async = async_to_streamed_response_wrapper(
11991300
devboxes.execute_async,
12001301
)

src/runloop_api_client/types/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from .blueprint_build_parameters import BlueprintBuildParameters as BlueprintBuildParameters
2727
from .devbox_execute_sync_params import DevboxExecuteSyncParams as DevboxExecuteSyncParams
2828
from .code_mount_parameters_param import CodeMountParametersParam as CodeMountParametersParam
29+
from .devbox_download_file_params import DevboxDownloadFileParams as DevboxDownloadFileParams
2930
from .devbox_execute_async_params import DevboxExecuteAsyncParams as DevboxExecuteAsyncParams
3031
from .function_invoke_sync_params import FunctionInvokeSyncParams as FunctionInvokeSyncParams
3132
from .devbox_execution_detail_view import DevboxExecutionDetailView as DevboxExecutionDetailView
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
from __future__ import annotations
4+
5+
from typing_extensions import Required, TypedDict
6+
7+
__all__ = ["DevboxDownloadFileParams"]
8+
9+
10+
class DevboxDownloadFileParams(TypedDict, total=False):
11+
path: Required[str]
12+
"""The path on the devbox to read the file"""

tests/api_resources/test_devboxes.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import os
66
from typing import Any, cast
77

8+
import httpx
89
import pytest
10+
from respx import MockRouter
911

1012
from tests.utils import assert_matches_type
1113
from runloop_api_client import Runloop, AsyncRunloop
@@ -16,6 +18,12 @@
1618
DevboxCreateSSHKeyResponse,
1719
DevboxAsyncExecutionDetailView,
1820
)
21+
from runloop_api_client._response import (
22+
BinaryAPIResponse,
23+
AsyncBinaryAPIResponse,
24+
StreamedBinaryAPIResponse,
25+
AsyncStreamedBinaryAPIResponse,
26+
)
1927

2028
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
2129

@@ -198,6 +206,60 @@ def test_path_params_create_ssh_key(self, client: Runloop) -> None:
198206
"",
199207
)
200208

209+
@parametrize
210+
@pytest.mark.respx(base_url=base_url)
211+
def test_method_download_file(self, client: Runloop, respx_mock: MockRouter) -> None:
212+
respx_mock.post("/v1/devboxes/id/download_file").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
213+
devbox = client.devboxes.download_file(
214+
id="id",
215+
path="path",
216+
)
217+
assert devbox.is_closed
218+
assert devbox.json() == {"foo": "bar"}
219+
assert cast(Any, devbox.is_closed) is True
220+
assert isinstance(devbox, BinaryAPIResponse)
221+
222+
@parametrize
223+
@pytest.mark.respx(base_url=base_url)
224+
def test_raw_response_download_file(self, client: Runloop, respx_mock: MockRouter) -> None:
225+
respx_mock.post("/v1/devboxes/id/download_file").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
226+
227+
devbox = client.devboxes.with_raw_response.download_file(
228+
id="id",
229+
path="path",
230+
)
231+
232+
assert devbox.is_closed is True
233+
assert devbox.http_request.headers.get("X-Stainless-Lang") == "python"
234+
assert devbox.json() == {"foo": "bar"}
235+
assert isinstance(devbox, BinaryAPIResponse)
236+
237+
@parametrize
238+
@pytest.mark.respx(base_url=base_url)
239+
def test_streaming_response_download_file(self, client: Runloop, respx_mock: MockRouter) -> None:
240+
respx_mock.post("/v1/devboxes/id/download_file").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
241+
with client.devboxes.with_streaming_response.download_file(
242+
id="id",
243+
path="path",
244+
) as devbox:
245+
assert not devbox.is_closed
246+
assert devbox.http_request.headers.get("X-Stainless-Lang") == "python"
247+
248+
assert devbox.json() == {"foo": "bar"}
249+
assert cast(Any, devbox.is_closed) is True
250+
assert isinstance(devbox, StreamedBinaryAPIResponse)
251+
252+
assert cast(Any, devbox.is_closed) is True
253+
254+
@parametrize
255+
@pytest.mark.respx(base_url=base_url)
256+
def test_path_params_download_file(self, client: Runloop) -> None:
257+
with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
258+
client.devboxes.with_raw_response.download_file(
259+
id="",
260+
path="path",
261+
)
262+
201263
@parametrize
202264
def test_method_execute_async(self, client: Runloop) -> None:
203265
devbox = client.devboxes.execute_async(
@@ -652,6 +714,60 @@ async def test_path_params_create_ssh_key(self, async_client: AsyncRunloop) -> N
652714
"",
653715
)
654716

717+
@parametrize
718+
@pytest.mark.respx(base_url=base_url)
719+
async def test_method_download_file(self, async_client: AsyncRunloop, respx_mock: MockRouter) -> None:
720+
respx_mock.post("/v1/devboxes/id/download_file").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
721+
devbox = await async_client.devboxes.download_file(
722+
id="id",
723+
path="path",
724+
)
725+
assert devbox.is_closed
726+
assert await devbox.json() == {"foo": "bar"}
727+
assert cast(Any, devbox.is_closed) is True
728+
assert isinstance(devbox, AsyncBinaryAPIResponse)
729+
730+
@parametrize
731+
@pytest.mark.respx(base_url=base_url)
732+
async def test_raw_response_download_file(self, async_client: AsyncRunloop, respx_mock: MockRouter) -> None:
733+
respx_mock.post("/v1/devboxes/id/download_file").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
734+
735+
devbox = await async_client.devboxes.with_raw_response.download_file(
736+
id="id",
737+
path="path",
738+
)
739+
740+
assert devbox.is_closed is True
741+
assert devbox.http_request.headers.get("X-Stainless-Lang") == "python"
742+
assert await devbox.json() == {"foo": "bar"}
743+
assert isinstance(devbox, AsyncBinaryAPIResponse)
744+
745+
@parametrize
746+
@pytest.mark.respx(base_url=base_url)
747+
async def test_streaming_response_download_file(self, async_client: AsyncRunloop, respx_mock: MockRouter) -> None:
748+
respx_mock.post("/v1/devboxes/id/download_file").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
749+
async with async_client.devboxes.with_streaming_response.download_file(
750+
id="id",
751+
path="path",
752+
) as devbox:
753+
assert not devbox.is_closed
754+
assert devbox.http_request.headers.get("X-Stainless-Lang") == "python"
755+
756+
assert await devbox.json() == {"foo": "bar"}
757+
assert cast(Any, devbox.is_closed) is True
758+
assert isinstance(devbox, AsyncStreamedBinaryAPIResponse)
759+
760+
assert cast(Any, devbox.is_closed) is True
761+
762+
@parametrize
763+
@pytest.mark.respx(base_url=base_url)
764+
async def test_path_params_download_file(self, async_client: AsyncRunloop) -> None:
765+
with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
766+
await async_client.devboxes.with_raw_response.download_file(
767+
id="",
768+
path="path",
769+
)
770+
655771
@parametrize
656772
async def test_method_execute_async(self, async_client: AsyncRunloop) -> None:
657773
devbox = await async_client.devboxes.execute_async(

0 commit comments

Comments
 (0)