diff --git a/.stats.yml b/.stats.yml index 9068a9902..fbcb876da 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 22 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-f8e5f5af651b36c2ceed0edd7ad24bc9227ebd55a782be369428c38bde32c3d2.yml +configured_endpoints: 23 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-b8fcc87544efea42048d01a4c7ba4c8abf1725337cfbb6bff607d5fea5cd1e1a.yml diff --git a/api.md b/api.md index 5a5988a8d..6f52516ae 100644 --- a/api.md +++ b/api.md @@ -53,6 +53,7 @@ from runloop_api_client.types import ( DevboxListView, DevboxView, DevboxReadFileContentsResponse, + DevboxUploadFileResponse, ) ``` @@ -65,6 +66,7 @@ Methods: - client.devboxes.read_file(id, \*\*params) -> DevboxExecutionDetailView - client.devboxes.read_file_contents(id, \*\*params) -> str - client.devboxes.shutdown(id) -> DevboxView +- client.devboxes.upload_file(id, \*\*params) -> object - client.devboxes.write_file(id, \*\*params) -> DevboxExecutionDetailView ## Logs diff --git a/src/runloop_api_client/resources/devboxes/devboxes.py b/src/runloop_api_client/resources/devboxes/devboxes.py index 198110b5b..eed5f870b 100644 --- a/src/runloop_api_client/resources/devboxes/devboxes.py +++ b/src/runloop_api_client/resources/devboxes/devboxes.py @@ -19,10 +19,11 @@ devbox_create_params, devbox_read_file_params, devbox_write_file_params, + devbox_upload_file_params, devbox_execute_sync_params, devbox_read_file_contents_params, ) -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes from ..._utils import ( maybe_transform, async_maybe_transform, @@ -365,6 +366,48 @@ def shutdown( cast_to=DevboxView, ) + def upload_file( + self, + id: str, + *, + file_input_stream: FileTypes | NotGiven = NOT_GIVEN, + path: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> object: + """ + Upload file contents to a file at path on the Devbox. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + f"/v1/devboxes/{id}/upload_file", + body=maybe_transform( + { + "file_input_stream": file_input_stream, + "path": path, + }, + devbox_upload_file_params.DevboxUploadFileParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + def write_file( self, id: str, @@ -734,6 +777,48 @@ async def shutdown( cast_to=DevboxView, ) + async def upload_file( + self, + id: str, + *, + file_input_stream: FileTypes | NotGiven = NOT_GIVEN, + path: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> object: + """ + Upload file contents to a file at path on the Devbox. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + f"/v1/devboxes/{id}/upload_file", + body=await async_maybe_transform( + { + "file_input_stream": file_input_stream, + "path": path, + }, + devbox_upload_file_params.DevboxUploadFileParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + async def write_file( self, id: str, @@ -806,6 +891,9 @@ def __init__(self, devboxes: DevboxesResource) -> None: self.shutdown = to_raw_response_wrapper( devboxes.shutdown, ) + self.upload_file = to_raw_response_wrapper( + devboxes.upload_file, + ) self.write_file = to_raw_response_wrapper( devboxes.write_file, ) @@ -840,6 +928,9 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None: self.shutdown = async_to_raw_response_wrapper( devboxes.shutdown, ) + self.upload_file = async_to_raw_response_wrapper( + devboxes.upload_file, + ) self.write_file = async_to_raw_response_wrapper( devboxes.write_file, ) @@ -874,6 +965,9 @@ def __init__(self, devboxes: DevboxesResource) -> None: self.shutdown = to_streamed_response_wrapper( devboxes.shutdown, ) + self.upload_file = to_streamed_response_wrapper( + devboxes.upload_file, + ) self.write_file = to_streamed_response_wrapper( devboxes.write_file, ) @@ -908,6 +1002,9 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None: self.shutdown = async_to_streamed_response_wrapper( devboxes.shutdown, ) + self.upload_file = async_to_streamed_response_wrapper( + devboxes.upload_file, + ) self.write_file = async_to_streamed_response_wrapper( devboxes.write_file, ) diff --git a/src/runloop_api_client/types/__init__.py b/src/runloop_api_client/types/__init__.py index 469d03aa8..616342b9e 100644 --- a/src/runloop_api_client/types/__init__.py +++ b/src/runloop_api_client/types/__init__.py @@ -23,6 +23,7 @@ from .devbox_read_file_params import DevboxReadFileParams as DevboxReadFileParams from .blueprint_preview_params import BlueprintPreviewParams as BlueprintPreviewParams from .devbox_write_file_params import DevboxWriteFileParams as DevboxWriteFileParams +from .devbox_upload_file_params import DevboxUploadFileParams as DevboxUploadFileParams from .blueprint_build_parameters import BlueprintBuildParameters as BlueprintBuildParameters from .devbox_execute_sync_params import DevboxExecuteSyncParams as DevboxExecuteSyncParams from .code_mount_parameters_param import CodeMountParametersParam as CodeMountParametersParam diff --git a/src/runloop_api_client/types/devbox_upload_file_params.py b/src/runloop_api_client/types/devbox_upload_file_params.py new file mode 100644 index 000000000..07529f129 --- /dev/null +++ b/src/runloop_api_client/types/devbox_upload_file_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from .._types import FileTypes +from .._utils import PropertyInfo + +__all__ = ["DevboxUploadFileParams"] + + +class DevboxUploadFileParams(TypedDict, total=False): + file_input_stream: Annotated[FileTypes, PropertyInfo(alias="fileInputStream")] + + path: str diff --git a/tests/api_resources/test_devboxes.py b/tests/api_resources/test_devboxes.py index 3f21fbaa5..5cf7d275c 100644 --- a/tests/api_resources/test_devboxes.py +++ b/tests/api_resources/test_devboxes.py @@ -312,6 +312,53 @@ def test_path_params_shutdown(self, client: Runloop) -> None: "", ) + @parametrize + def test_method_upload_file(self, client: Runloop) -> None: + devbox = client.devboxes.upload_file( + id="id", + ) + assert_matches_type(object, devbox, path=["response"]) + + @parametrize + def test_method_upload_file_with_all_params(self, client: Runloop) -> None: + devbox = client.devboxes.upload_file( + id="id", + file_input_stream=b"raw file contents", + path="path", + ) + assert_matches_type(object, devbox, path=["response"]) + + @parametrize + def test_raw_response_upload_file(self, client: Runloop) -> None: + response = client.devboxes.with_raw_response.upload_file( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + devbox = response.parse() + assert_matches_type(object, devbox, path=["response"]) + + @parametrize + def test_streaming_response_upload_file(self, client: Runloop) -> None: + with client.devboxes.with_streaming_response.upload_file( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + devbox = response.parse() + assert_matches_type(object, devbox, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_upload_file(self, client: Runloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.devboxes.with_raw_response.upload_file( + id="", + ) + @parametrize def test_method_write_file(self, client: Runloop) -> None: devbox = client.devboxes.write_file( @@ -654,6 +701,53 @@ async def test_path_params_shutdown(self, async_client: AsyncRunloop) -> None: "", ) + @parametrize + async def test_method_upload_file(self, async_client: AsyncRunloop) -> None: + devbox = await async_client.devboxes.upload_file( + id="id", + ) + assert_matches_type(object, devbox, path=["response"]) + + @parametrize + async def test_method_upload_file_with_all_params(self, async_client: AsyncRunloop) -> None: + devbox = await async_client.devboxes.upload_file( + id="id", + file_input_stream=b"raw file contents", + path="path", + ) + assert_matches_type(object, devbox, path=["response"]) + + @parametrize + async def test_raw_response_upload_file(self, async_client: AsyncRunloop) -> None: + response = await async_client.devboxes.with_raw_response.upload_file( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + devbox = await response.parse() + assert_matches_type(object, devbox, path=["response"]) + + @parametrize + async def test_streaming_response_upload_file(self, async_client: AsyncRunloop) -> None: + async with async_client.devboxes.with_streaming_response.upload_file( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + devbox = await response.parse() + assert_matches_type(object, devbox, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_upload_file(self, async_client: AsyncRunloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.devboxes.with_raw_response.upload_file( + id="", + ) + @parametrize async def test_method_write_file(self, async_client: AsyncRunloop) -> None: devbox = await async_client.devboxes.write_file(