diff --git a/.stats.yml b/.stats.yml index 31759036f..311ea3267 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 44 +configured_endpoints: 46 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-15f23a9e2e014d2e5d4d72c39ee31c5556060fb37d1490f308ecce5aeb41d5c8.yml diff --git a/api.md b/api.md index 00eb5ac7e..be9c20e21 100644 --- a/api.md +++ b/api.md @@ -168,8 +168,10 @@ Methods: Methods: +- client.devboxes.executions.retrieve(execution_id, \*, devbox_id, \*\*params) -> DevboxAsyncExecutionDetailView - client.devboxes.executions.execute_async(id, \*\*params) -> DevboxAsyncExecutionDetailView - client.devboxes.executions.execute_sync(id, \*\*params) -> DevboxExecutionDetailView +- client.devboxes.executions.kill(execution_id, \*, devbox_id) -> DevboxAsyncExecutionDetailView # Repositories diff --git a/src/runloop_api_client/resources/devboxes/executions.py b/src/runloop_api_client/resources/devboxes/executions.py index b8cc6fbf3..6d8184e0a 100755 --- a/src/runloop_api_client/resources/devboxes/executions.py +++ b/src/runloop_api_client/resources/devboxes/executions.py @@ -20,7 +20,7 @@ async_to_streamed_response_wrapper, ) from ..._base_client import make_request_options -from ...types.devboxes import execution_execute_sync_params, execution_execute_async_params +from ...types.devboxes import execution_retrieve_params, execution_execute_sync_params, execution_execute_async_params from ...types.devbox_execution_detail_view import DevboxExecutionDetailView from ...types.devbox_async_execution_detail_view import DevboxAsyncExecutionDetailView @@ -47,6 +47,50 @@ def with_streaming_response(self) -> ExecutionsResourceWithStreamingResponse: """ return ExecutionsResourceWithStreamingResponse(self) + def retrieve( + self, + execution_id: str, + *, + devbox_id: str, + last_n: 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, + ) -> DevboxAsyncExecutionDetailView: + """ + Get the latest status of a previously launched asynchronous execuction including + stdout/error and the exit code if complete. + + Args: + last_n: Last n lines of standard error / standard out to return + + 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 devbox_id: + raise ValueError(f"Expected a non-empty value for `devbox_id` but received {devbox_id!r}") + if not execution_id: + raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}") + return self._get( + f"/v1/devboxes/{devbox_id}/executions/{execution_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"last_n": last_n}, execution_retrieve_params.ExecutionRetrieveParams), + ), + cast_to=DevboxAsyncExecutionDetailView, + ) + def execute_async( self, id: str, @@ -165,6 +209,50 @@ def execute_sync( cast_to=DevboxExecutionDetailView, ) + def kill( + self, + execution_id: str, + *, + devbox_id: str, + # 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, + idempotency_key: str | None = None, + ) -> DevboxAsyncExecutionDetailView: + """ + Kill a previously launched asynchronous execution if it is still running by + killing the launched process. + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + if not devbox_id: + raise ValueError(f"Expected a non-empty value for `devbox_id` but received {devbox_id!r}") + if not execution_id: + raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}") + return self._post( + f"/v1/devboxes/{devbox_id}/executions/{execution_id}/kill", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=DevboxAsyncExecutionDetailView, + ) + class AsyncExecutionsResource(AsyncAPIResource): @cached_property @@ -186,6 +274,52 @@ def with_streaming_response(self) -> AsyncExecutionsResourceWithStreamingRespons """ return AsyncExecutionsResourceWithStreamingResponse(self) + async def retrieve( + self, + execution_id: str, + *, + devbox_id: str, + last_n: 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, + ) -> DevboxAsyncExecutionDetailView: + """ + Get the latest status of a previously launched asynchronous execuction including + stdout/error and the exit code if complete. + + Args: + last_n: Last n lines of standard error / standard out to return + + 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 devbox_id: + raise ValueError(f"Expected a non-empty value for `devbox_id` but received {devbox_id!r}") + if not execution_id: + raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}") + return await self._get( + f"/v1/devboxes/{devbox_id}/executions/{execution_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"last_n": last_n}, execution_retrieve_params.ExecutionRetrieveParams + ), + ), + cast_to=DevboxAsyncExecutionDetailView, + ) + async def execute_async( self, id: str, @@ -304,50 +438,118 @@ async def execute_sync( cast_to=DevboxExecutionDetailView, ) + async def kill( + self, + execution_id: str, + *, + devbox_id: str, + # 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, + idempotency_key: str | None = None, + ) -> DevboxAsyncExecutionDetailView: + """ + Kill a previously launched asynchronous execution if it is still running by + killing the launched process. + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + if not devbox_id: + raise ValueError(f"Expected a non-empty value for `devbox_id` but received {devbox_id!r}") + if not execution_id: + raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}") + return await self._post( + f"/v1/devboxes/{devbox_id}/executions/{execution_id}/kill", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=DevboxAsyncExecutionDetailView, + ) + class ExecutionsResourceWithRawResponse: def __init__(self, executions: ExecutionsResource) -> None: self._executions = executions + self.retrieve = to_raw_response_wrapper( + executions.retrieve, + ) self.execute_async = to_raw_response_wrapper( executions.execute_async, ) self.execute_sync = to_raw_response_wrapper( executions.execute_sync, ) + self.kill = to_raw_response_wrapper( + executions.kill, + ) class AsyncExecutionsResourceWithRawResponse: def __init__(self, executions: AsyncExecutionsResource) -> None: self._executions = executions + self.retrieve = async_to_raw_response_wrapper( + executions.retrieve, + ) self.execute_async = async_to_raw_response_wrapper( executions.execute_async, ) self.execute_sync = async_to_raw_response_wrapper( executions.execute_sync, ) + self.kill = async_to_raw_response_wrapper( + executions.kill, + ) class ExecutionsResourceWithStreamingResponse: def __init__(self, executions: ExecutionsResource) -> None: self._executions = executions + self.retrieve = to_streamed_response_wrapper( + executions.retrieve, + ) self.execute_async = to_streamed_response_wrapper( executions.execute_async, ) self.execute_sync = to_streamed_response_wrapper( executions.execute_sync, ) + self.kill = to_streamed_response_wrapper( + executions.kill, + ) class AsyncExecutionsResourceWithStreamingResponse: def __init__(self, executions: AsyncExecutionsResource) -> None: self._executions = executions + self.retrieve = async_to_streamed_response_wrapper( + executions.retrieve, + ) self.execute_async = async_to_streamed_response_wrapper( executions.execute_async, ) self.execute_sync = async_to_streamed_response_wrapper( executions.execute_sync, ) + self.kill = async_to_streamed_response_wrapper( + executions.kill, + ) diff --git a/src/runloop_api_client/types/devboxes/__init__.py b/src/runloop_api_client/types/devboxes/__init__.py index f2f7c0765..30d13b0fb 100644 --- a/src/runloop_api_client/types/devboxes/__init__.py +++ b/src/runloop_api_client/types/devboxes/__init__.py @@ -52,6 +52,7 @@ from .code_action_trigger_kind import CodeActionTriggerKind as CodeActionTriggerKind from .base_workspace_edit_param import BaseWorkspaceEditParam as BaseWorkspaceEditParam from .code_action_context_param import CodeActionContextParam as CodeActionContextParam +from .execution_retrieve_params import ExecutionRetrieveParams as ExecutionRetrieveParams from .base_parameter_information import BaseParameterInformation as BaseParameterInformation from .code_segment_info_response import CodeSegmentInfoResponse as CodeSegmentInfoResponse from .lsp_file_definition_params import LspFileDefinitionParams as LspFileDefinitionParams diff --git a/src/runloop_api_client/types/devboxes/execution_retrieve_params.py b/src/runloop_api_client/types/devboxes/execution_retrieve_params.py new file mode 100644 index 000000000..96e8bc24b --- /dev/null +++ b/src/runloop_api_client/types/devboxes/execution_retrieve_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ExecutionRetrieveParams"] + + +class ExecutionRetrieveParams(TypedDict, total=False): + devbox_id: Required[str] + + last_n: str + """Last n lines of standard error / standard out to return""" diff --git a/tests/api_resources/devboxes/test_executions.py b/tests/api_resources/devboxes/test_executions.py index 0b17d6067..a1a7b8b58 100755 --- a/tests/api_resources/devboxes/test_executions.py +++ b/tests/api_resources/devboxes/test_executions.py @@ -17,6 +17,63 @@ class TestExecutions: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize + def test_method_retrieve(self, client: Runloop) -> None: + execution = client.devboxes.executions.retrieve( + execution_id="execution_id", + devbox_id="devbox_id", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_method_retrieve_with_all_params(self, client: Runloop) -> None: + execution = client.devboxes.executions.retrieve( + execution_id="execution_id", + devbox_id="devbox_id", + last_n="last_n", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Runloop) -> None: + response = client.devboxes.executions.with_raw_response.retrieve( + execution_id="execution_id", + devbox_id="devbox_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = response.parse() + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Runloop) -> None: + with client.devboxes.executions.with_streaming_response.retrieve( + execution_id="execution_id", + devbox_id="devbox_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = response.parse() + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Runloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `devbox_id` but received ''"): + client.devboxes.executions.with_raw_response.retrieve( + execution_id="execution_id", + devbox_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): + client.devboxes.executions.with_raw_response.retrieve( + execution_id="", + devbox_id="devbox_id", + ) + @parametrize def test_method_execute_async(self, client: Runloop) -> None: execution = client.devboxes.executions.execute_async( @@ -119,10 +176,115 @@ def test_path_params_execute_sync(self, client: Runloop) -> None: command="command", ) + @parametrize + def test_method_kill(self, client: Runloop) -> None: + execution = client.devboxes.executions.kill( + execution_id="execution_id", + devbox_id="devbox_id", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_raw_response_kill(self, client: Runloop) -> None: + response = client.devboxes.executions.with_raw_response.kill( + execution_id="execution_id", + devbox_id="devbox_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = response.parse() + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_streaming_response_kill(self, client: Runloop) -> None: + with client.devboxes.executions.with_streaming_response.kill( + execution_id="execution_id", + devbox_id="devbox_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = response.parse() + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_kill(self, client: Runloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `devbox_id` but received ''"): + client.devboxes.executions.with_raw_response.kill( + execution_id="execution_id", + devbox_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): + client.devboxes.executions.with_raw_response.kill( + execution_id="", + devbox_id="devbox_id", + ) + class TestAsyncExecutions: parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize + async def test_method_retrieve(self, async_client: AsyncRunloop) -> None: + execution = await async_client.devboxes.executions.retrieve( + execution_id="execution_id", + devbox_id="devbox_id", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncRunloop) -> None: + execution = await async_client.devboxes.executions.retrieve( + execution_id="execution_id", + devbox_id="devbox_id", + last_n="last_n", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncRunloop) -> None: + response = await async_client.devboxes.executions.with_raw_response.retrieve( + execution_id="execution_id", + devbox_id="devbox_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = await response.parse() + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncRunloop) -> None: + async with async_client.devboxes.executions.with_streaming_response.retrieve( + execution_id="execution_id", + devbox_id="devbox_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = await response.parse() + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncRunloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `devbox_id` but received ''"): + await async_client.devboxes.executions.with_raw_response.retrieve( + execution_id="execution_id", + devbox_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): + await async_client.devboxes.executions.with_raw_response.retrieve( + execution_id="", + devbox_id="devbox_id", + ) + @parametrize async def test_method_execute_async(self, async_client: AsyncRunloop) -> None: execution = await async_client.devboxes.executions.execute_async( @@ -224,3 +386,51 @@ async def test_path_params_execute_sync(self, async_client: AsyncRunloop) -> Non id="", command="command", ) + + @parametrize + async def test_method_kill(self, async_client: AsyncRunloop) -> None: + execution = await async_client.devboxes.executions.kill( + execution_id="execution_id", + devbox_id="devbox_id", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_raw_response_kill(self, async_client: AsyncRunloop) -> None: + response = await async_client.devboxes.executions.with_raw_response.kill( + execution_id="execution_id", + devbox_id="devbox_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = await response.parse() + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_streaming_response_kill(self, async_client: AsyncRunloop) -> None: + async with async_client.devboxes.executions.with_streaming_response.kill( + execution_id="execution_id", + devbox_id="devbox_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = await response.parse() + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_kill(self, async_client: AsyncRunloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `devbox_id` but received ''"): + await async_client.devboxes.executions.with_raw_response.kill( + execution_id="execution_id", + devbox_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): + await async_client.devboxes.executions.with_raw_response.kill( + execution_id="", + devbox_id="devbox_id", + )